diff options
Diffstat (limited to 'src')
487 files changed, 44432 insertions, 3939 deletions
diff --git a/src/3rdparty/harfbuzz/src/harfbuzz-gpos.c b/src/3rdparty/harfbuzz/src/harfbuzz-gpos.c index 1ac3779..c932ec2 100644 --- a/src/3rdparty/harfbuzz/src/harfbuzz-gpos.c +++ b/src/3rdparty/harfbuzz/src/harfbuzz-gpos.c @@ -2723,7 +2723,7 @@ static HB_Error Load_Mark2Array( HB_Mark2Array* m2a, { HB_Error error; - HB_UShort k, m, n, count; + HB_UShort m, n, count; HB_UInt cur_offset, new_offset, base_offset; HB_Mark2Record *m2r; diff --git a/src/3rdparty/phonon/ds9/backend.cpp b/src/3rdparty/phonon/ds9/backend.cpp index 245749a..2c56af7 100644 --- a/src/3rdparty/phonon/ds9/backend.cpp +++ b/src/3rdparty/phonon/ds9/backend.cpp @@ -50,7 +50,7 @@ namespace Phonon Backend::Backend(QObject *parent, const QVariantList &) : QObject(parent) { - ::CoInitialize(0); + ::CoInitialize(0); //registering meta types qRegisterMetaType<HRESULT>("HRESULT"); @@ -61,7 +61,7 @@ namespace Phonon { m_audioOutputs.clear(); m_audioEffects.clear(); - ::CoUninitialize(); + ::CoUninitialize(); } QObject *Backend::createObject(BackendInterface::Class c, QObject *parent, const QList<QVariant> &args) @@ -216,7 +216,7 @@ namespace Phonon LPOLESTR str = 0; HRESULT hr = mon->GetDisplayName(0,0, &str); if (SUCCEEDED(hr)) { - QString name = QString::fromUtf16((unsigned short*)str); + QString name = QString::fromUtf16((unsigned short*)str); ComPointer<IMalloc> alloc; ::CoGetMalloc(1, alloc.pparam()); alloc->Free(str); diff --git a/src/3rdparty/phonon/ds9/backendnode.cpp b/src/3rdparty/phonon/ds9/backendnode.cpp index 7e0b3cd..855357a 100644 --- a/src/3rdparty/phonon/ds9/backendnode.cpp +++ b/src/3rdparty/phonon/ds9/backendnode.cpp @@ -57,6 +57,8 @@ namespace Phonon BackendNode::~BackendNode() { + //this will remove the filter from the graph + mediaObjectDestroyed(); } void BackendNode::setMediaObject(MediaObject *mo) diff --git a/src/3rdparty/phonon/ds9/mediaobject.cpp b/src/3rdparty/phonon/ds9/mediaobject.cpp index f77bdc1..df42011 100644 --- a/src/3rdparty/phonon/ds9/mediaobject.cpp +++ b/src/3rdparty/phonon/ds9/mediaobject.cpp @@ -36,7 +36,7 @@ along with this library. If not, see <http://www.gnu.org/licenses/>. #include <QtCore/QDebug> -#define TIMER_INTERVAL 16 //... ms for the timer that polls the current state (we use the multimedia timer +#define TIMER_INTERVAL 16 //... ms for the timer that polls the current state (we use the multimedia timer) #define PRELOAD_TIME 2000 // 2 seconds to load a source QT_BEGIN_NAMESPACE @@ -89,7 +89,7 @@ namespace Phonon DWORD result = ::WaitForMultipleObjects(count, handles, FALSE, INFINITE); if (result == WAIT_OBJECT_0) { if (m_finished) { - //that's the end if the thread execution + //that's the end of the thread execution return; } @@ -210,7 +210,7 @@ namespace Phonon { QMutexLocker locker(&m_mutex); m_currentRender = w.graph; - m_currentRenderId = w.id; + m_currentRenderId = w.id; } if (w.task == ReplaceGraph) { @@ -253,7 +253,7 @@ namespace Phonon hr = w.graph->RenderFile(reinterpret_cast<const wchar_t *>(w.url.utf16()), 0); } if (hr != E_ABORT) { - emit asyncRenderFinished(w.id, hr, w.graph); + emit asyncRenderFinished(w.id, hr, w.graph); } } else if (w.task == Seek) { //that's a seekrequest @@ -269,7 +269,7 @@ namespace Phonon } } emit asyncSeekingFinished(w.id, currentTime); - hr = E_ABORT; //to avoid emitting asyncRenderFinished + hr = E_ABORT; //to avoid emitting asyncRenderFinished } else if (w.task == ChangeState) { //remove useless decoders @@ -330,16 +330,14 @@ namespace Phonon { QMutexLocker locker(&m_mutex); m_currentRender = Graph(); - m_currentRenderId = 0; + m_currentRenderId = 0; } - } - void WorkerThread::abortCurrentRender(qint16 renderId) - { + void WorkerThread::abortCurrentRender(qint16 renderId) + { QMutexLocker locker(&m_mutex); bool found = false; - //we try to see if there is already an attempt to seek and we remove it for(int i = 0; !found && i < m_queue.size(); ++i) { const Work &w = m_queue.at(i); if (w.id == renderId) { @@ -348,10 +346,10 @@ namespace Phonon } } - if (m_currentRender && m_currentRenderId == renderId) { - m_currentRender->Abort(); - } - } + if (m_currentRender && m_currentRenderId == renderId) { + m_currentRender->Abort(); + } + } //tells the thread to stop processing void WorkerThread::signalStop() @@ -389,13 +387,13 @@ namespace Phonon { for(int i = 0; i < FILTER_COUNT; ++i) { - m_graphs[i] = new MediaGraph(this, i); + m_graphs[i] = new MediaGraph(this, i); } - connect(&m_thread, SIGNAL(stateReady(Graph, Phonon::State)), + connect(&m_thread, SIGNAL(stateReady(Graph, Phonon::State)), SLOT(slotStateReady(Graph, Phonon::State))); - connect(&m_thread, SIGNAL(eventReady(Graph, long, long)), + connect(&m_thread, SIGNAL(eventReady(Graph, long, long)), SLOT(handleEvents(Graph, long, long))); connect(&m_thread, SIGNAL(asyncRenderFinished(quint16, HRESULT, Graph)), @@ -490,7 +488,7 @@ namespace Phonon } if (!m_aboutToFinishSent && remaining < PRELOAD_TIME - m_transitionTime + TIMER_INTERVAL/2) { - //let's take a 2 seconds time time to actually load the next file + //let's take a 2 seconds time to actually load the next file #ifdef GRAPH_DEBUG qDebug() << "DS9: emit aboutToFinish" << remaining << QTime::currentTime().toString(); #endif @@ -579,7 +577,7 @@ namespace Phonon { #ifndef QT_NO_PHONON_MEDIACONTROLLER //1st, check if there is more titles after - const qint64 ret = (m_currentTitle < _iface_availableTitles() - 1) ? + const qint64 ret = (m_currentTitle < _iface_availableTitles() - 1) ? titleAbsolutePosition(m_currentTitle+1) : currentGraph()->absoluteTotalTime(); //this is the duration of the current title @@ -592,7 +590,7 @@ namespace Phonon qint64 MediaObject::currentTime() const { //this handles inaccuracy when stopping on a title - return currentGraph()->absoluteCurrentTime() + return currentGraph()->absoluteCurrentTime() #ifndef QT_NO_PHONON_MEDIACONTROLLER - titleAbsolutePosition(m_currentTitle) #endif //QT_NO_PHONON_MEDIACONTROLLER @@ -742,7 +740,7 @@ namespace Phonon m_oldHasVideo = currentGraph()->hasVideo(); setState(Phonon::LoadingState); //After loading we go into stopped state - m_nextState = Phonon::StoppedState; + m_nextState = Phonon::StoppedState; catchComError(currentGraph()->loadSource(source)); emit currentSourceChanged(source); } @@ -756,7 +754,7 @@ namespace Phonon void MediaObject::loadingFinished(MediaGraph *mg) { - if (mg == currentGraph()) { + if (mg == currentGraph()) { #ifndef QT_NO_PHONON_MEDIACONTROLLER //Title interface m_currentTitle = 0; @@ -813,7 +811,7 @@ namespace Phonon void MediaObject::seekingFinished(MediaGraph *mg) { - if (mg == currentGraph()) { + if (mg == currentGraph()) { updateTargetTick(); if (currentTime() < totalTime() - m_prefinishMark) { @@ -888,7 +886,7 @@ namespace Phonon #ifndef QT_NO_PHONON_VIDEO if (VideoWidget *video = qobject_cast<VideoWidget*>(sink)) { m_videoWidgets += video; - } else + } else #endif //QT_NO_PHONON_VIDEO if (AudioOutput *audio = qobject_cast<AudioOutput*>(sink)) { m_audioOutputs += audio; @@ -907,7 +905,7 @@ namespace Phonon #ifndef QT_NO_PHONON_VIDEO if (VideoWidget *video = qobject_cast<VideoWidget*>(sink)) { m_videoWidgets.removeOne(video); - } else + } else #endif //QT_NO_PHONON_VIDEO if (AudioOutput *audio = qobject_cast<AudioOutput*>(sink)) { m_audioOutputs.removeOne(audio); @@ -989,7 +987,7 @@ namespace Phonon emit stateChanged(state(), m_state); } break; - case EC_LENGTH_CHANGED: + case EC_LENGTH_CHANGED: if (graph == currentGraph()->graph()) { emit totalTimeChanged( totalTime() ); } diff --git a/src/3rdparty/phonon/ds9/qmeminputpin.cpp b/src/3rdparty/phonon/ds9/qmeminputpin.cpp index 0af1bfd..dca99db 100644 --- a/src/3rdparty/phonon/ds9/qmeminputpin.cpp +++ b/src/3rdparty/phonon/ds9/qmeminputpin.cpp @@ -28,7 +28,7 @@ namespace Phonon namespace DS9 { - QMemInputPin::QMemInputPin(QBaseFilter *parent, const QVector<AM_MEDIA_TYPE> &mt, bool transform) : + QMemInputPin::QMemInputPin(QBaseFilter *parent, const QVector<AM_MEDIA_TYPE> &mt, bool transform) : QPin(parent, PINDIR_INPUT, mt), m_shouldDuplicateSamples(true), m_transform(transform) { } @@ -203,7 +203,7 @@ namespace Phonon for (int i = 0; i < m_outputs.count(); ++i) { QPin *current = m_outputs.at(i); - IMediaSample *outSample = m_shouldDuplicateSamples ? + IMediaSample *outSample = m_shouldDuplicateSamples ? duplicateSampleForOutput(sample, current->memoryAllocator()) : sample; @@ -261,7 +261,7 @@ namespace Phonon } //addition - //this should be used by the filter to tell it's input pins to which output they should route the samples + //this should be used by the filter to tell its input pins to which output they should route the samples void QMemInputPin::addOutput(QPin *output) { diff --git a/src/3rdparty/phonon/ds9/qpin.cpp b/src/3rdparty/phonon/ds9/qpin.cpp index 5f335ac..68a4ec0 100644 --- a/src/3rdparty/phonon/ds9/qpin.cpp +++ b/src/3rdparty/phonon/ds9/qpin.cpp @@ -303,9 +303,7 @@ namespace Phonon setConnected(0); setConnectedType(defaultMediaType); - if (m_direction == PINDIR_INPUT) { - setMemoryAllocator(0); - } + setMemoryAllocator(0); return S_OK; } @@ -443,8 +441,8 @@ namespace Phonon HRESULT QPin::checkOutputMediaTypesConnection(IPin *pin) { - IEnumMediaTypes *emt = 0; - HRESULT hr = pin->EnumMediaTypes(&emt); + ComPointer<IEnumMediaTypes> emt; + HRESULT hr = pin->EnumMediaTypes(emt.pparam()); if (hr != S_OK) { return hr; } diff --git a/src/3rdparty/phonon/phonon/backendcapabilities.h b/src/3rdparty/phonon/phonon/backendcapabilities.h index 65b2830..36454a3 100644 --- a/src/3rdparty/phonon/phonon/backendcapabilities.h +++ b/src/3rdparty/phonon/phonon/backendcapabilities.h @@ -6,7 +6,7 @@ License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its - successor approved by the membership of KDE e.V.), Trolltech ASA + successor approved by the membership of KDE e.V.), Trolltech ASA (or its successors, if any) and the KDE Free Qt Foundation, which shall act as a proxy defined in Section 6 of version 3 of the license. @@ -15,7 +15,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - You should have received a copy of the GNU Lesser General Public + You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <http://www.gnu.org/licenses/>. */ @@ -88,19 +88,18 @@ namespace BackendCapabilities }; /** - * Use this function to get a QObject pointer to connect to the capabilitiesChanged signal. + * Use this function to get a QObject pointer to connect to one of the Notifier signals. * * \return a pointer to a QObject. * - * The capabilitiesChanged signal is emitted if the capabilities have changed. This can - * happen if the user has requested a backend change. - * - * To connect to this signal do the following: + * To connect to the signal do the following: * \code * QObject::connect(BackendCapabilities::notifier(), SIGNAL(capabilitiesChanged()), ... * \endcode * * \see Notifier::capabilitiesChanged() + * \see Notifier::availableAudioOutputDevicesChanged() + * \see Notifier::availableAudioCaptureDevicesChanged() */ PHONON_EXPORT Notifier *notifier(); diff --git a/src/3rdparty/phonon/phonon/mediaobject.h b/src/3rdparty/phonon/phonon/mediaobject.h index 5cbddbb..c56b6b5 100644 --- a/src/3rdparty/phonon/phonon/mediaobject.h +++ b/src/3rdparty/phonon/phonon/mediaobject.h @@ -6,7 +6,7 @@ License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its - successor approved by the membership of KDE e.V.), Trolltech ASA + successor approved by the membership of KDE e.V.), Trolltech ASA (or its successors, if any) and the KDE Free Qt Foundation, which shall act as a proxy defined in Section 6 of version 3 of the license. @@ -15,7 +15,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - You should have received a copy of the GNU Lesser General Public + You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <http://www.gnu.org/licenses/>. */ @@ -58,7 +58,7 @@ namespace Phonon * media->play(); * \endcode * - * If you want to play more that one media file (one after another) you can + * If you want to play more than one media file (one after another) you can * either tell MediaObject about all those files * \code * media->setCurrentSource(":/sounds/startsound.ogg"); @@ -198,18 +198,18 @@ namespace Phonon * Check whether the current media may be seeked. * * \warning This information cannot be known immediately. It is best - * to also listen to the hasVideoChanged signal. + * to also listen to the seekableChanged signal. * * \code - * connect(media, SIGNAL(hasVideoChanged(bool)), hasVideoChanged(bool)); + * connect(media, SIGNAL(seekableChanged(bool)), seekableChanged(bool)); * media->setCurrentSource("somevideo.avi"); - * media->hasVideo(); // returns false; + * media->isSeekable(); // returns false; * } * - * void hasVideoChanged(bool b) + * void seekableChanged(bool b) * { * // b == true - * media->hasVideo(); // returns true; + * media->isSeekable(); // returns true; * } * \endcode * @@ -301,7 +301,7 @@ namespace Phonon void setCurrentSource(const MediaSource &source); /** - * Returns the queued media sources. This does list does not include + * Returns the queued media sources. This list does not include * the current source (returned by currentSource). */ QList<MediaSource> queue() const; @@ -456,8 +456,6 @@ namespace Phonon Q_SIGNALS: /** * Emitted when the state of the MediaObject has changed. - * In case you're not interested in the old state you can also - * connect to a slot that only has one State argument. * * @param newstate The state the Player is in now. * @param oldstate The state the Player was in before. @@ -587,7 +585,7 @@ namespace Phonon /** * This signal is emitted as soon as the total time of the media file is * known or has changed. For most non-local media data the total - * time of the media can only be known after some time. At that time the + * time of the media can only be known after some time. Initially the * totalTime function can not return useful information. You have * to wait for this signal to know the real total time. * diff --git a/src/3rdparty/webkit/WebCore/WebCore.pro b/src/3rdparty/webkit/WebCore/WebCore.pro index b76cad1..b0b0290 100644 --- a/src/3rdparty/webkit/WebCore/WebCore.pro +++ b/src/3rdparty/webkit/WebCore/WebCore.pro @@ -41,7 +41,7 @@ CONFIG -= warn_on # Disable a few warnings on Windows. The warnings are also # disabled in WebKitLibraries/win/tools/vsprops/common.vsprops -win32-*: QMAKE_CXXFLAGS += -wd4291 -wd4344 +!win32-g++:win32-*: QMAKE_CXXFLAGS += -wd4291 -wd4344 unix:!mac:*-g++*:QMAKE_CXXFLAGS += -ffunction-sections -fdata-sections unix:!mac:*-g++*:QMAKE_LFLAGS += -Wl,--gc-sections diff --git a/src/3rdparty/webkit/WebKit/qt/Api/qwebdatabase.cpp b/src/3rdparty/webkit/WebKit/qt/Api/qwebdatabase.cpp index 2b25f95..0d11381 100644 --- a/src/3rdparty/webkit/WebKit/qt/Api/qwebdatabase.cpp +++ b/src/3rdparty/webkit/WebKit/qt/Api/qwebdatabase.cpp @@ -34,9 +34,20 @@ using namespace WebCore; \brief The QWebDatabase class provides access to HTML 5 databases created with JavaScript. The upcoming HTML 5 standard includes support for SQL databases that web sites can create and - access on a local computer through JavaScript. QWebDatabase is the C++ interface to these databases. + access on a local computer through JavaScript. QWebDatabase is the C++ interface to these + databases. - For more information refer to the \l{http://www.w3.org/html/wg/html5/#sql}{HTML 5 Draft Standard}. + To get access to all databases defined by a security origin, use QWebSecurityOrigin::databases(). + Each database has an internal name(), as well as a user-friendly name, provided by displayName(). + + WebKit uses SQLite to create and access the local SQL databases. The location of the database + file in the local file system is returned by fileName(). You can access the database directly + through the QtSql database module. + + For each database the web site can define an expectedSize(). The current size of the database + in bytes is returned by size(). + + For more information refer to the \l{http://dev.w3.org/html5/webdatabase/}{HTML 5 Draft Standard}. \sa QWebSecurityOrigin */ @@ -127,7 +138,7 @@ QWebDatabase::QWebDatabase(QWebDatabasePrivate* priv) \endcode \note Concurrent access to a database from multiple threads or processes - is not very efficient because Sqlite is used as WebKit's database backend. + is not very efficient because SQLite is used as WebKit's database backend. */ QString QWebDatabase::fileName() const { @@ -149,8 +160,8 @@ QWebSecurityOrigin QWebDatabase::origin() const } /*! - Removes the database, \a db, from its security origin. All data stored in this database - will be destroyed. + Removes the database \a db from its security origin. All data stored in the + database \a db will be destroyed. */ void QWebDatabase::removeDatabase(const QWebDatabase &db) { diff --git a/src/3rdparty/webkit/WebKit/qt/Api/qwebpage.cpp b/src/3rdparty/webkit/WebKit/qt/Api/qwebpage.cpp index 84753bd..3c2151b 100644 --- a/src/3rdparty/webkit/WebKit/qt/Api/qwebpage.cpp +++ b/src/3rdparty/webkit/WebKit/qt/Api/qwebpage.cpp @@ -1315,6 +1315,8 @@ QWebFrame *QWebPage::currentFrame() const /*! + \since 4.6 + Returns the frame at the given point \a pos. \sa mainFrame(), currentFrame() diff --git a/src/3rdparty/webkit/WebKit/qt/Api/qwebsecurityorigin.cpp b/src/3rdparty/webkit/WebKit/qt/Api/qwebsecurityorigin.cpp index da9278c..d2eaf10 100644 --- a/src/3rdparty/webkit/WebKit/qt/Api/qwebsecurityorigin.cpp +++ b/src/3rdparty/webkit/WebKit/qt/Api/qwebsecurityorigin.cpp @@ -36,10 +36,9 @@ using namespace WebCore; \brief The QWebSecurityOrigin class defines a security boundary for web sites. QWebSecurityOrigin provides access to the security domains defined by web sites. - An origin consists of a host name, a scheme, and a port number. Web sites with the same - security origin can access each other's resources for client-side scripting or databases. - - ### diagram + An origin consists of a host name, a scheme, and a port number. Web sites + with the same security origin can access each other's resources for client-side + scripting or databases. For example the site \c{http://www.example.com/my/page.html} is allowed to share the same database as \c{http://www.example.com/my/overview.html}, or access each other's @@ -47,7 +46,13 @@ using namespace WebCore; \c{http://www.malicious.com/evil.html} from accessing \c{http://www.example.com/}'s resources, because they are of a different security origin. - QWebSecurity also provides access to all databases defined within a security origin. + Call QWebFrame::securityOrigin() to get the QWebSecurityOrigin for a frame in a + web page, and use host(), scheme() and port() to identify the security origin. + + Use databases() to access the databases defined within a security origin. The + disk usage of the origin's databases can be limited with setDatabaseQuota(). + databaseQuota() and databaseUsage() report the current limit as well as the + current usage. For more information refer to the \l{http://en.wikipedia.org/wiki/Same_origin_policy}{"Same origin policy" Wikipedia Article}. diff --git a/src/3rdparty/webkit/WebKit/qt/Api/qwebview.cpp b/src/3rdparty/webkit/WebKit/qt/Api/qwebview.cpp index c634a7f..f5afbec 100644 --- a/src/3rdparty/webkit/WebKit/qt/Api/qwebview.cpp +++ b/src/3rdparty/webkit/WebKit/qt/Api/qwebview.cpp @@ -270,19 +270,24 @@ void QWebView::setPage(QWebPage *page) 'ftp'. The result is then passed through QUrl's tolerant parser, and in the case or success, a valid QUrl is returned, or else a QUrl(). - Examples - - webkit.org becomes http://webkit.org - - ftp.webkit.org becomes ftp://ftp.webkit.org - - localhost becomes http://localhost - - /home/user/test.html becomes file:///home/user/test.html (if exists) - - Tips when dealing with URLs and strings - - When creating a QString from a QByteArray or a char*, always use - QString::fromUtf8(). - - Do not use QUrl(string), nor QUrl::toString() anywhere where the URL might - be used, such as in the location bar, as those functions loose data. - Instead use QUrl::fromEncoded() and QUrl::toEncoded(), respectively. + \section2 Examples: + + \list + \o webkit.org becomes http://webkit.org + \o ftp.webkit.org becomes ftp://ftp.webkit.org + \o localhost becomes http://localhost + \o /home/user/test.html becomes file:///home/user/test.html (if exists) + \endlist + \section2 Tips when dealing with URLs and strings: + + \list + \o When creating a QString from a QByteArray or a char*, always use + QString::fromUtf8(). + \o Do not use QUrl(string), nor QUrl::toString() anywhere where the URL might + be used, such as in the location bar, as those functions loose data. + Instead use QUrl::fromEncoded() and QUrl::toEncoded(), respectively. + \endlist */ QUrl QWebView::guessUrlFromString(const QString &string) { diff --git a/src/activeqt/container/qaxobject.cpp b/src/activeqt/container/qaxobject.cpp index 412c5b5..63bdd5e 100644 --- a/src/activeqt/container/qaxobject.cpp +++ b/src/activeqt/container/qaxobject.cpp @@ -122,7 +122,7 @@ QAxObject::~QAxObject() } /*! - \reimp + \internal */ const QMetaObject *QAxObject::metaObject() const { @@ -130,7 +130,7 @@ const QMetaObject *QAxObject::metaObject() const } /*! - \reimp + \internal */ const QMetaObject *QAxObject::parentMetaObject() const { @@ -148,7 +148,7 @@ void *QAxObject::qt_metacast(const char *cname) } /*! - \reimp + \internal */ const char *QAxObject::className() const { @@ -156,7 +156,7 @@ const char *QAxObject::className() const } /*! - \reimp + \internal */ int QAxObject::qt_metacall(QMetaObject::Call call, int id, void **v) { diff --git a/src/activeqt/container/qaxwidget.cpp b/src/activeqt/container/qaxwidget.cpp index 615887f..ae468ef 100644 --- a/src/activeqt/container/qaxwidget.cpp +++ b/src/activeqt/container/qaxwidget.cpp @@ -2034,7 +2034,7 @@ bool QAxWidget::doVerb(const QString &verb) */ /*! - \reimp + \internal */ const QMetaObject *QAxWidget::metaObject() const { @@ -2042,7 +2042,7 @@ const QMetaObject *QAxWidget::metaObject() const } /*! - \reimp + \internal */ const QMetaObject *QAxWidget::parentMetaObject() const { @@ -2060,7 +2060,7 @@ void *QAxWidget::qt_metacast(const char *cname) } /*! - \reimp + \internal */ const char *QAxWidget::className() const { @@ -2068,7 +2068,7 @@ const char *QAxWidget::className() const } /*! - \reimp + \internal */ int QAxWidget::qt_metacall(QMetaObject::Call call, int id, void **v) { diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index eb21cb2..62c55c3 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -620,8 +620,8 @@ void QAbstractAnimation::start(DeletionPolicy policy) Q_D(QAbstractAnimation); if (d->state == Running) return; - d->setState(Running); d->deleteWhenStopped = policy; + d->setState(Running); } /*! @@ -643,9 +643,8 @@ void QAbstractAnimation::stop() /*! Pauses the animation. When the animation is paused, state() returns Paused. - The currenttime will remain unchanged until resume() or start() is called. - If you want to continue from the current time, call resume(). - + The value of currentTime will remain unchanged until resume() or start() + is called. If you want to continue from the current time, call resume(). \sa start(), state(), resume() */ diff --git a/src/corelib/animation/qsequentialanimationgroup.cpp b/src/corelib/animation/qsequentialanimationgroup.cpp index 5932e7c..05dc307 100644 --- a/src/corelib/animation/qsequentialanimationgroup.cpp +++ b/src/corelib/animation/qsequentialanimationgroup.cpp @@ -269,8 +269,10 @@ QSequentialAnimationGroup::~QSequentialAnimationGroup() /*! Adds a pause of \a msecs to this animation group. - The pause is considered as a special type of animation, thus count() will be + The pause is considered as a special type of animation, thus + \l{QAnimationGroup::animationCount()}{animationCount} will be increased by one. + \sa insertPauseAt(), QAnimationGroup::addAnimation() */ QPauseAnimation *QSequentialAnimationGroup::addPause(int msecs) diff --git a/src/corelib/arch/qatomic_powerpc.h b/src/corelib/arch/qatomic_powerpc.h index ea3f458..c3b31f9 100644 --- a/src/corelib/arch/qatomic_powerpc.h +++ b/src/corelib/arch/qatomic_powerpc.h @@ -101,8 +101,6 @@ template <typename T> Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndAddWaitFree() { return false; } -QT_BEGIN_NAMESPACE - #if defined(Q_CC_GNU) #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2) \ diff --git a/src/corelib/codecs/qtextcodec.cpp b/src/corelib/codecs/qtextcodec.cpp index c4266a0..f49e34a 100644 --- a/src/corelib/codecs/qtextcodec.cpp +++ b/src/corelib/codecs/qtextcodec.cpp @@ -99,6 +99,10 @@ Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, (QTextCodecFactoryInterface_iid, QLatin1String("/codecs"))) #endif +static char qtolower(register char c) +{ if (c >= 'A' && c <= 'Z') return c + 0x20; return c; } +static bool qisalnum(register char c) +{ return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); } static bool nameMatch(const QByteArray &name, const QByteArray &test) { @@ -111,21 +115,21 @@ static bool nameMatch(const QByteArray &name, const QByteArray &test) // if the letters and numbers are the same, we have a match while (*n != '\0') { - if (isalnum((uchar)*n)) { + if (qisalnum(*n)) { for (;;) { if (*h == '\0') return false; - if (isalnum((uchar)*h)) + if (qisalnum(*h)) break; ++h; } - if (tolower((uchar)*n) != tolower((uchar)*h)) + if (qtolower(*n) != qtolower(*h)) return false; ++h; } ++n; } - while (*h && !isalnum((uchar)*h)) + while (*h && !qisalnum(*h)) ++h; return (*h == '\0'); } @@ -1532,9 +1536,13 @@ QTextCodec *QTextCodec::codecForHtml(const QByteArray &ba, QTextCodec *defaultCo } /*! - \overload + \overload - If the codec cannot be detected, this overload returns a Latin-1 QTextCodec. + Tries to detect the encoding of the provided snippet of HTML in + the given byte array, \a ba, by checking the BOM (Byte Order Mark) + and the content-type meta header and returns a QTextCodec instance + that is capable of decoding the html to unicode. If the codec cannot + be detected, this overload returns a Latin-1 QTextCodec. */ QTextCodec *QTextCodec::codecForHtml(const QByteArray &ba) { @@ -1546,10 +1554,13 @@ QTextCodec *QTextCodec::codecForHtml(const QByteArray &ba) Tries to detect the encoding of the provided snippet \a ba by using the BOM (Byte Order Mark) and returns a QTextCodec instance - that is capable of decoding the text to unicode. If the codec + that is capable of decoding the text to unicode. If the codec cannot be detected from the content provided, \a defaultCodec is returned. + The behavior of this function is undefined if \a ba is not + encoded in unicode. + \sa codecForHtml() */ QTextCodec *QTextCodec::codecForUtfText(const QByteArray &ba, QTextCodec *defaultCodec) @@ -1587,9 +1598,17 @@ QTextCodec *QTextCodec::codecForUtfText(const QByteArray &ba, QTextCodec *defaul } /*! - \overload + \overload + + Tries to detect the encoding of the provided snippet \a ba by + using the BOM (Byte Order Mark) and returns a QTextCodec instance + that is capable of decoding the text to unicode. If the codec + cannot be detected, this overload returns a Latin-1 QTextCodec. + + The behavior of this function is undefined if \a ba is not + encoded in unicode. - If the codec cannot be detected, this overload returns a Latin-1 QTextCodec. + \sa codecForHtml() */ QTextCodec *QTextCodec::codecForUtfText(const QByteArray &ba) { diff --git a/src/corelib/codecs/qtextcodec_p.h b/src/corelib/codecs/qtextcodec_p.h index 499c0f9..5c82735 100644 --- a/src/corelib/codecs/qtextcodec_p.h +++ b/src/corelib/codecs/qtextcodec_p.h @@ -77,6 +77,33 @@ struct QTextCodecUnalignedPointer } }; +#else + +class QTextCodec +{ +public: + enum ConversionFlag { + DefaultConversion, + ConvertInvalidToNull = 0x80000000, + IgnoreHeader = 0x1, + FreeFunction = 0x2 + }; + Q_DECLARE_FLAGS(ConversionFlags, ConversionFlag) + + struct ConverterState { + ConverterState(ConversionFlags f = DefaultConversion) + : flags(f), remainingChars(0), invalidChars(0), d(0) { state_data[0] = state_data[1] = state_data[2] = 0; } + ~ConverterState() { } + ConversionFlags flags; + int remainingChars; + int invalidChars; + uint state_data[3]; + void *d; + private: + Q_DISABLE_COPY(ConverterState) + }; +}; + #endif //QT_NO_TEXTCODEC QT_END_NAMESPACE diff --git a/src/corelib/codecs/qutfcodec.cpp b/src/corelib/codecs/qutfcodec.cpp index abae6f7..abcc07c 100644 --- a/src/corelib/codecs/qutfcodec.cpp +++ b/src/corelib/codecs/qutfcodec.cpp @@ -44,23 +44,19 @@ #include "qendian.h" #include "qchar.h" -#ifndef QT_NO_TEXTCODEC - QT_BEGIN_NAMESPACE -QUtf8Codec::~QUtf8Codec() -{ -} +enum { Endian = 0, Data = 1 }; -QByteArray QUtf8Codec::convertFromUnicode(const QChar *uc, int len, ConverterState *state) const +QByteArray QUtf8::convertFromUnicode(const QChar *uc, int len, QTextCodec::ConverterState *state) { uchar replacement = '?'; int rlen = 3*len; int surrogate_high = -1; if (state) { - if (state->flags & ConvertInvalidToNull) + if (state->flags & QTextCodec::ConvertInvalidToNull) replacement = 0; - if (!(state->flags & IgnoreHeader)) + if (!(state->flags & QTextCodec::IgnoreHeader)) rlen += 3; if (state->remainingChars) surrogate_high = state->state_data[0]; @@ -71,7 +67,7 @@ QByteArray QUtf8Codec::convertFromUnicode(const QChar *uc, int len, ConverterSta uchar* cursor = (uchar*)rstr.data(); const QChar *ch = uc; int invalid = 0; - if (state && !(state->flags & IgnoreHeader)) { + if (state && !(state->flags & QTextCodec::IgnoreHeader)) { *cursor++ = 0xef; *cursor++ = 0xbb; *cursor++ = 0xbf; @@ -133,7 +129,7 @@ QByteArray QUtf8Codec::convertFromUnicode(const QChar *uc, int len, ConverterSta rstr.resize(cursor - (const uchar*)rstr.constData()); if (state) { state->invalidChars += invalid; - state->flags |= IgnoreHeader; + state->flags |= QTextCodec::IgnoreHeader; state->remainingChars = 0; if (surrogate_high >= 0) { state->remainingChars = 1; @@ -143,18 +139,18 @@ QByteArray QUtf8Codec::convertFromUnicode(const QChar *uc, int len, ConverterSta return rstr; } -void QUtf8Codec::convertToUnicode(QString *target, const char *chars, int len, ConverterState *state) const +QString QUtf8::convertToUnicode(const char *chars, int len, QTextCodec::ConverterState *state) { bool headerdone = false; - QChar replacement = QChar::ReplacementCharacter; + ushort replacement = QChar::ReplacementCharacter; int need = 0; int error = -1; uint uc = 0; uint min_uc = 0; if (state) { - if (state->flags & IgnoreHeader) + if (state->flags & QTextCodec::IgnoreHeader) headerdone = true; - if (state->flags & ConvertInvalidToNull) + if (state->flags & QTextCodec::ConvertInvalidToNull) replacement = QChar::Null; need = state->remainingChars; if (need) { @@ -170,40 +166,28 @@ void QUtf8Codec::convertToUnicode(QString *target, const char *chars, int len, C headerdone = true; } - int originalLength = target->length(); - QString &result = *target; - result.resize(originalLength + len + 1); // worst case - QChar *qch = result.data() + originalLength; + QString result(need + len + 1, Qt::Uninitialized); // worst case + ushort *qch = (ushort *)result.unicode(); uchar ch; int invalid = 0; - for (int i=0; i<len; i++) { + for (int i = 0; i < len; ++i) { ch = chars[i]; if (need) { if ((ch&0xc0) == 0x80) { uc = (uc << 6) | (ch & 0x3f); - need--; + --need; if (!need) { // utf-8 bom composes into 0xfeff code point if (!headerdone && uc == 0xfeff) { // dont do anything, just skip the BOM } else if (uc > 0xffff && uc < 0x110000) { // surrogate pair - uc -= 0x10000; - unsigned short high = uc/0x400 + 0xd800; - unsigned short low = uc%0x400 + 0xdc00; - - // resize if necessary - long where = qch - result.unicode(); - if (where + 2 >= result.length()) { - result.resize(where + 2); - qch = result.data() + where; - } - - *qch++ = QChar(high); - *qch++ = QChar(low); + Q_ASSERT((qch - (ushort*)result.unicode()) + 2 < result.length()); + *qch++ = QChar::highSurrogate(uc); + *qch++ = QChar::lowSurrogate(uc); } else if ((uc < min_uc) || (uc >= 0xd800 && uc <= 0xdfff) || (uc >= 0xfffe)) { - // error + // error: overlong sequence, UTF16 surrogate or BOM *qch++ = replacement; ++invalid; } else { @@ -221,7 +205,7 @@ void QUtf8Codec::convertToUnicode(QString *target, const char *chars, int len, C } } else { if (ch < 128) { - *qch++ = QLatin1Char(ch); + *qch++ = ushort(ch); headerdone = true; } else if ((ch & 0xe0) == 0xc0) { uc = ch & 0x1f; @@ -255,57 +239,35 @@ void QUtf8Codec::convertToUnicode(QString *target, const char *chars, int len, C ++invalid; } } - result.truncate(qch - result.unicode()); + result.truncate(qch - (ushort *)result.unicode()); if (state) { state->invalidChars += invalid; state->remainingChars = need; if (headerdone) - state->flags |= IgnoreHeader; + state->flags |= QTextCodec::IgnoreHeader; state->state_data[0] = need ? uc : 0; state->state_data[1] = need ? min_uc : 0; } -} - -QString QUtf8Codec::convertToUnicode(const char *chars, int len, ConverterState *state) const -{ - QString result; - convertToUnicode(&result, chars, len, state); return result; } -QByteArray QUtf8Codec::name() const -{ - return "UTF-8"; -} - -int QUtf8Codec::mibEnum() const -{ - return 106; -} - -enum { Endian = 0, Data = 1 }; - -QUtf16Codec::~QUtf16Codec() -{ -} - -QByteArray QUtf16Codec::convertFromUnicode(const QChar *uc, int len, ConverterState *state) const +QByteArray QUtf16::convertFromUnicode(const QChar *uc, int len, QTextCodec::ConverterState *state, DataEndianness e) { - Endianness endian = e; + DataEndianness endian = e; int length = 2*len; - if (!state || (!(state->flags & IgnoreHeader))) { + if (!state || (!(state->flags & QTextCodec::IgnoreHeader))) { length += 2; } - if (e == Detect) { - endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BE : LE; + if (e == DetectEndianness) { + endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BigEndianness : LittleEndianness; } QByteArray d; d.resize(length); char *data = d.data(); - if (!state || !(state->flags & IgnoreHeader)) { + if (!state || !(state->flags & QTextCodec::IgnoreHeader)) { QChar bom(QChar::ByteOrderMark); - if (endian == BE) { + if (endian == BigEndianness) { data[0] = bom.row(); data[1] = bom.cell(); } else { @@ -314,7 +276,7 @@ QByteArray QUtf16Codec::convertFromUnicode(const QChar *uc, int len, ConverterSt } data += 2; } - if (endian == BE) { + if (endian == BigEndianness) { for (int i = 0; i < len; ++i) { *(data++) = uc[i].row(); *(data++) = uc[i].cell(); @@ -328,35 +290,35 @@ QByteArray QUtf16Codec::convertFromUnicode(const QChar *uc, int len, ConverterSt if (state) { state->remainingChars = 0; - state->flags |= IgnoreHeader; + state->flags |= QTextCodec::IgnoreHeader; } return d; } -QString QUtf16Codec::convertToUnicode(const char *chars, int len, ConverterState *state) const +QString QUtf16::convertToUnicode(const char *chars, int len, QTextCodec::ConverterState *state, DataEndianness e) { - Endianness endian = e; + DataEndianness endian = e; bool half = false; uchar buf = 0; bool headerdone = false; if (state) { - headerdone = state->flags & IgnoreHeader; - if (endian == Detect) - endian = (Endianness)state->state_data[Endian]; + headerdone = state->flags & QTextCodec::IgnoreHeader; + if (endian == DetectEndianness) + endian = (DataEndianness)state->state_data[Endian]; if (state->remainingChars) { half = true; buf = state->state_data[Data]; } } - if (headerdone && endian == Detect) - endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BE : LE; + if (headerdone && endian == DetectEndianness) + endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BigEndianness : LittleEndianness; QString result(len, Qt::Uninitialized); // worst case QChar *qch = (QChar *)result.unicode(); while (len--) { if (half) { QChar ch; - if (endian == LE) { + if (endian == LittleEndianness) { ch.setRow(*chars++); ch.setCell(buf); } else { @@ -364,17 +326,17 @@ QString QUtf16Codec::convertToUnicode(const char *chars, int len, ConverterState ch.setCell(*chars++); } if (!headerdone) { - if (endian == Detect) { - if (ch == QChar::ByteOrderSwapped && endian != BE) { - endian = LE; - } else if (ch == QChar::ByteOrderMark && endian != LE) { + if (endian == DetectEndianness) { + if (ch == QChar::ByteOrderSwapped && endian != BigEndianness) { + endian = LittleEndianness; + } else if (ch == QChar::ByteOrderMark && endian != LittleEndianness) { // ignore BOM - endian = BE; + endian = BigEndianness; } else { if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { - endian = BE; + endian = BigEndianness; } else { - endian = LE; + endian = LittleEndianness; ch = QChar((ch.unicode() >> 8) | ((ch.unicode() & 0xff) << 8)); } *qch++ = ch; @@ -396,7 +358,7 @@ QString QUtf16Codec::convertToUnicode(const char *chars, int len, ConverterState if (state) { if (headerdone) - state->flags |= IgnoreHeader; + state->flags |= QTextCodec::IgnoreHeader; state->state_data[Endian] = endian; if (half) { state->remainingChars = 1; @@ -409,72 +371,21 @@ QString QUtf16Codec::convertToUnicode(const char *chars, int len, ConverterState return result; } -int QUtf16Codec::mibEnum() const -{ - return 1015; -} - -QByteArray QUtf16Codec::name() const -{ - return "UTF-16"; -} - -QList<QByteArray> QUtf16Codec::aliases() const -{ - return QList<QByteArray>(); -} - -int QUtf16BECodec::mibEnum() const -{ - return 1013; -} - -QByteArray QUtf16BECodec::name() const -{ - return "UTF-16BE"; -} - -QList<QByteArray> QUtf16BECodec::aliases() const -{ - QList<QByteArray> list; - return list; -} - -int QUtf16LECodec::mibEnum() const -{ - return 1014; -} - -QByteArray QUtf16LECodec::name() const -{ - return "UTF-16LE"; -} - -QList<QByteArray> QUtf16LECodec::aliases() const -{ - QList<QByteArray> list; - return list; -} - -QUtf32Codec::~QUtf32Codec() -{ -} - -QByteArray QUtf32Codec::convertFromUnicode(const QChar *uc, int len, ConverterState *state) const +QByteArray QUtf32::convertFromUnicode(const QChar *uc, int len, QTextCodec::ConverterState *state, DataEndianness e) { - Endianness endian = e; + DataEndianness endian = e; int length = 4*len; - if (!state || (!(state->flags & IgnoreHeader))) { + if (!state || (!(state->flags & QTextCodec::IgnoreHeader))) { length += 4; } - if (e == Detect) { - endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BE : LE; + if (e == DetectEndianness) { + endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BigEndianness : LittleEndianness; } QByteArray d(length, Qt::Uninitialized); char *data = d.data(); - if (!state || !(state->flags & IgnoreHeader)) { - if (endian == BE) { + if (!state || !(state->flags & QTextCodec::IgnoreHeader)) { + if (endian == BigEndianness) { data[0] = 0; data[1] = 0; data[2] = (char)0xfe; @@ -487,7 +398,7 @@ QByteArray QUtf32Codec::convertFromUnicode(const QChar *uc, int len, ConverterSt } data += 4; } - if (endian == BE) { + if (endian == BigEndianness) { for (int i = 0; i < len; ++i) { uint cp = uc[i].unicode(); if (uc[i].isHighSurrogate() && i < len - 1) @@ -511,59 +422,59 @@ QByteArray QUtf32Codec::convertFromUnicode(const QChar *uc, int len, ConverterSt if (state) { state->remainingChars = 0; - state->flags |= IgnoreHeader; + state->flags |= QTextCodec::IgnoreHeader; } return d; } -QString QUtf32Codec::convertToUnicode(const char *chars, int len, ConverterState *state) const +QString QUtf32::convertToUnicode(const char *chars, int len, QTextCodec::ConverterState *state, DataEndianness e) { - Endianness endian = e; + DataEndianness endian = e; uchar tuple[4]; int num = 0; bool headerdone = false; if (state) { - headerdone = state->flags & IgnoreHeader; - if (endian == Detect) { - endian = (Endianness)state->state_data[Endian]; + headerdone = state->flags & QTextCodec::IgnoreHeader; + if (endian == DetectEndianness) { + endian = (DataEndianness)state->state_data[Endian]; } num = state->remainingChars; memcpy(tuple, &state->state_data[Data], 4); } - if (headerdone && endian == Detect) - endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BE : LE; + if (headerdone && endian == DetectEndianness) + endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BigEndianness : LittleEndianness; QString result; result.resize((num + len) >> 2 << 1); // worst case QChar *qch = (QChar *)result.unicode(); - + const char *end = chars + len; while (chars < end) { tuple[num++] = *chars++; if (num == 4) { if (!headerdone) { - if (endian == Detect) { - if (endian == Detect) { - if (tuple[0] == 0xff && tuple[1] == 0xfe && tuple[2] == 0 && tuple[3] == 0 && endian != BE) { - endian = LE; + if (endian == DetectEndianness) { + if (endian == DetectEndianness) { + if (tuple[0] == 0xff && tuple[1] == 0xfe && tuple[2] == 0 && tuple[3] == 0 && endian != BigEndianness) { + endian = LittleEndianness; num = 0; continue; - } else if (tuple[0] == 0 && tuple[1] == 0 && tuple[2] == 0xfe && tuple[3] == 0xff && endian != LE) { - endian = BE; + } else if (tuple[0] == 0 && tuple[1] == 0 && tuple[2] == 0xfe && tuple[3] == 0xff && endian != LittleEndianness) { + endian = BigEndianness; num = 0; continue; } else if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { - endian = BE; + endian = BigEndianness; } else { - endian = LE; + endian = LittleEndianness; } } - } else if (((endian == BE) ? qFromBigEndian<quint32>(tuple) : qFromLittleEndian<quint32>(tuple)) == QChar::ByteOrderMark) { + } else if (((endian == BigEndianness) ? qFromBigEndian<quint32>(tuple) : qFromLittleEndian<quint32>(tuple)) == QChar::ByteOrderMark) { num = 0; continue; } } - uint code = (endian == BE) ? qFromBigEndian<quint32>(tuple) : qFromLittleEndian<quint32>(tuple); + uint code = (endian == BigEndianness) ? qFromBigEndian<quint32>(tuple) : qFromLittleEndian<quint32>(tuple); if (code >= 0x10000) { *qch++ = QChar::highSurrogate(code); *qch++ = QChar::lowSurrogate(code); @@ -574,10 +485,10 @@ QString QUtf32Codec::convertToUnicode(const char *chars, int len, ConverterState } } result.truncate(qch - result.unicode()); - + if (state) { if (headerdone) - state->flags |= IgnoreHeader; + state->flags |= QTextCodec::IgnoreHeader; state->state_data[Endian] = endian; state->remainingChars = num; memcpy(&state->state_data[Data], tuple, 4); @@ -585,6 +496,113 @@ QString QUtf32Codec::convertToUnicode(const char *chars, int len, ConverterState return result; } + +#ifndef QT_NO_TEXTCODEC + +QUtf8Codec::~QUtf8Codec() +{ +} + +QByteArray QUtf8Codec::convertFromUnicode(const QChar *uc, int len, ConverterState *state) const +{ + return QUtf8::convertFromUnicode(uc, len, state); +} + +void QUtf8Codec::convertToUnicode(QString *target, const char *chars, int len, ConverterState *state) const +{ + *target += QUtf8::convertToUnicode(chars, len, state); +} + +QString QUtf8Codec::convertToUnicode(const char *chars, int len, ConverterState *state) const +{ + return QUtf8::convertToUnicode(chars, len, state); +} + +QByteArray QUtf8Codec::name() const +{ + return "UTF-8"; +} + +int QUtf8Codec::mibEnum() const +{ + return 106; +} + +QUtf16Codec::~QUtf16Codec() +{ +} + +QByteArray QUtf16Codec::convertFromUnicode(const QChar *uc, int len, ConverterState *state) const +{ + return QUtf16::convertFromUnicode(uc, len, state, e); +} + +QString QUtf16Codec::convertToUnicode(const char *chars, int len, ConverterState *state) const +{ + return QUtf16::convertToUnicode(chars, len, state, e); +} + +int QUtf16Codec::mibEnum() const +{ + return 1015; +} + +QByteArray QUtf16Codec::name() const +{ + return "UTF-16"; +} + +QList<QByteArray> QUtf16Codec::aliases() const +{ + return QList<QByteArray>(); +} + +int QUtf16BECodec::mibEnum() const +{ + return 1013; +} + +QByteArray QUtf16BECodec::name() const +{ + return "UTF-16BE"; +} + +QList<QByteArray> QUtf16BECodec::aliases() const +{ + QList<QByteArray> list; + return list; +} + +int QUtf16LECodec::mibEnum() const +{ + return 1014; +} + +QByteArray QUtf16LECodec::name() const +{ + return "UTF-16LE"; +} + +QList<QByteArray> QUtf16LECodec::aliases() const +{ + QList<QByteArray> list; + return list; +} + +QUtf32Codec::~QUtf32Codec() +{ +} + +QByteArray QUtf32Codec::convertFromUnicode(const QChar *uc, int len, ConverterState *state) const +{ + return QUtf32::convertFromUnicode(uc, len, state, e); +} + +QString QUtf32Codec::convertToUnicode(const char *chars, int len, ConverterState *state) const +{ + return QUtf32::convertToUnicode(chars, len, state, e); +} + int QUtf32Codec::mibEnum() const { return 1017; @@ -633,7 +651,6 @@ QList<QByteArray> QUtf32LECodec::aliases() const return list; } +#endif //QT_NO_TEXTCODEC QT_END_NAMESPACE - -#endif //QT_NO_TEXTCODEC diff --git a/src/corelib/codecs/qutfcodec_p.h b/src/corelib/codecs/qutfcodec_p.h index 749f5be..4f8f92e 100644 --- a/src/corelib/codecs/qutfcodec_p.h +++ b/src/corelib/codecs/qutfcodec_p.h @@ -54,9 +54,35 @@ // #include "QtCore/qtextcodec.h" +#include "private/qtextcodec_p.h" QT_BEGIN_NAMESPACE +enum DataEndianness +{ + DetectEndianness, + BigEndianness, + LittleEndianness +}; + +struct QUtf8 +{ + static QString convertToUnicode(const char *, int, QTextCodec::ConverterState *); + static QByteArray convertFromUnicode(const QChar *, int, QTextCodec::ConverterState *); +}; + +struct QUtf16 +{ + static QString convertToUnicode(const char *, int, QTextCodec::ConverterState *, DataEndianness = DetectEndianness); + static QByteArray convertFromUnicode(const QChar *, int, QTextCodec::ConverterState *, DataEndianness = DetectEndianness); +}; + +struct QUtf32 +{ + static QString convertToUnicode(const char *, int, QTextCodec::ConverterState *, DataEndianness = DetectEndianness); + static QByteArray convertFromUnicode(const QChar *, int, QTextCodec::ConverterState *, DataEndianness = DetectEndianness); +}; + #ifndef QT_NO_TEXTCODEC class QUtf8Codec : public QTextCodec { @@ -73,13 +99,8 @@ public: class QUtf16Codec : public QTextCodec { protected: - enum Endianness { - Detect, - BE, - LE - }; public: - QUtf16Codec() { e = Detect; } + QUtf16Codec() { e = DetectEndianness; } ~QUtf16Codec(); QByteArray name() const; @@ -90,12 +111,12 @@ public: QByteArray convertFromUnicode(const QChar *, int, ConverterState *) const; protected: - Endianness e; + DataEndianness e; }; class QUtf16BECodec : public QUtf16Codec { public: - QUtf16BECodec() : QUtf16Codec() { e = BE; } + QUtf16BECodec() : QUtf16Codec() { e = BigEndianness; } QByteArray name() const; QList<QByteArray> aliases() const; int mibEnum() const; @@ -103,21 +124,15 @@ public: class QUtf16LECodec : public QUtf16Codec { public: - QUtf16LECodec() : QUtf16Codec() { e = LE; } + QUtf16LECodec() : QUtf16Codec() { e = LittleEndianness; } QByteArray name() const; QList<QByteArray> aliases() const; int mibEnum() const; }; class QUtf32Codec : public QTextCodec { -protected: - enum Endianness { - Detect, - BE, - LE - }; public: - QUtf32Codec() { e = Detect; } + QUtf32Codec() { e = DetectEndianness; } ~QUtf32Codec(); QByteArray name() const; @@ -128,12 +143,12 @@ public: QByteArray convertFromUnicode(const QChar *, int, ConverterState *) const; protected: - Endianness e; + DataEndianness e; }; class QUtf32BECodec : public QUtf32Codec { public: - QUtf32BECodec() : QUtf32Codec() { e = BE; } + QUtf32BECodec() : QUtf32Codec() { e = BigEndianness; } QByteArray name() const; QList<QByteArray> aliases() const; int mibEnum() const; @@ -141,7 +156,7 @@ public: class QUtf32LECodec : public QUtf32Codec { public: - QUtf32LECodec() : QUtf32Codec() { e = LE; } + QUtf32LECodec() : QUtf32Codec() { e = LittleEndianness; } QByteArray name() const; QList<QByteArray> aliases() const; int mibEnum() const; diff --git a/src/corelib/concurrent/qfuture.h b/src/corelib/concurrent/qfuture.h index 47015ee..f2db5ac 100644 --- a/src/corelib/concurrent/qfuture.h +++ b/src/corelib/concurrent/qfuture.h @@ -210,7 +210,7 @@ public: bool operator==(const QFuture &other) const { return (d == other.d); } bool operator!=(const QFuture &other) const { return (d != other.d); } -#ifndef QT_NO_MEMBER_TEMPLATES +#if !defined(QT_NO_MEMBER_TEMPLATES) && !defined(Q_CC_XLC) template <typename T> QFuture(const QFuture<T> &other) : d(other.d) diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index ad4868d..f7d6514 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -1668,7 +1668,7 @@ QSysInfo::WinVersion QSysInfo::windowsVersion() winver = QSysInfo::WV_WINDOWS7; } else { qWarning("Qt: Untested Windows version %d.%d detected!", - osver.dwMajorVersion, osver.dwMinorVersion); + int(osver.dwMajorVersion), int(osver.dwMinorVersion)); winver = QSysInfo::WV_NT_based; } } diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 94fa9ab..dbe25cb 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -665,7 +665,8 @@ namespace QT_NAMESPACE {} # define Q_ALIGNOF(type) __alignof__(type) # define Q_TYPEOF(expr) __typeof__(expr) # define Q_DECL_ALIGN(n) __attribute__((__aligned__(n))) -# define Q_DECL_EXPORT __attribute__((__visibility__("default"))) +// using CC 5.9: Warning: attribute visibility is unsupported and will be skipped.. +//# define Q_DECL_EXPORT __attribute__((__visibility__("default"))) # endif # if !defined(_BOOL) # define Q_NO_BOOL_TYPE @@ -705,7 +706,7 @@ namespace QT_NAMESPACE {} # define Q_DECL_ALIGNED(n) __attribute__((aligned(n))) # endif # if __HP_aCC-0 >= 062000 -# define Q_DECL_EXPORT __attribute__((visibility("default")) +# define Q_DECL_EXPORT __attribute__((visibility("default"))) # define Q_DECL_IMPORT Q_DECL_EXPORT # endif # else @@ -2420,28 +2421,15 @@ QT_LICENSED_MODULE(DBus) # define QT_NO_QFUTURE #endif -/* - Turn off certain features for compilers that have problems parsing - the code. -*/ -#if (defined(Q_CC_HPACC) && defined(QT_ARCH_PARISC)) \ - || defined(Q_CC_MIPS) \ - || defined(Q_CC_XLC) -// HP aCC A.03.*, MIPSpro, and xlC cannot handle -// the template function declarations for the QtConcurrent functions -# define QT_NO_QFUTURE -# define QT_NO_CONCURRENT -#endif - -// MSVC 6.0, MSVC .NET 2002, and old versions of Sun CC can`t handle the map(), etc templates, +// MSVC 6.0 and MSVC .NET 2002, can`t handle the map(), etc templates, // but the QFuture class compiles. -#if (defined(Q_CC_MSVC) && _MSC_VER <= 1300) || (defined (__SUNPRO_CC) && __SUNPRO_CC <= 0x590) +#if (defined(Q_CC_MSVC) && _MSC_VER <= 1300) # define QT_NO_CONCURRENT #endif -// Mingw uses a gcc 3 version which has problems with some of the -// map/filter overloads. So does IRIX and Solaris. -#if (defined(Q_OS_IRIX) || defined(Q_CC_MINGW) || defined (Q_OS_SOLARIS)) && (__GNUC__ < 4) +// gcc 3 version has problems with some of the +// map/filter overloads. +#if defined(Q_CC_GNU) && (__GNUC__ < 4) # define QT_NO_CONCURRENT_MAP # define QT_NO_CONCURRENT_FILTER #endif diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index e0584e5..7770fd6 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -1410,7 +1410,8 @@ public: ToolButtonIconOnly, ToolButtonTextOnly, ToolButtonTextBesideIcon, - ToolButtonTextUnderIcon + ToolButtonTextUnderIcon, + ToolButtonFollowStyle }; enum LayoutDirection { diff --git a/src/corelib/io/qabstractfileengine.cpp b/src/corelib/io/qabstractfileengine.cpp index 93097bc..9eb3305 100644 --- a/src/corelib/io/qabstractfileengine.cpp +++ b/src/corelib/io/qabstractfileengine.cpp @@ -42,7 +42,7 @@ #include "qabstractfileengine.h" #include "private/qabstractfileengine_p.h" #include "qdatetime.h" -#include "qmutex.h" +#include "qreadwritelock.h" #include "qvariant.h" // built-in handlers #include "qfsfileengine.h" @@ -98,14 +98,14 @@ QT_BEGIN_NAMESPACE All application-wide handlers are stored in this list. The mutex must be acquired to ensure thread safety. */ -Q_GLOBAL_STATIC_WITH_ARGS(QMutex, fileEngineHandlerMutex, (QMutex::Recursive)) +Q_GLOBAL_STATIC_WITH_ARGS(QReadWriteLock, fileEngineHandlerMutex, (QReadWriteLock::Recursive)) static bool qt_abstractfileenginehandlerlist_shutDown = false; class QAbstractFileEngineHandlerList : public QList<QAbstractFileEngineHandler *> { public: ~QAbstractFileEngineHandlerList() { - QMutexLocker locker(fileEngineHandlerMutex()); + QWriteLocker locker(fileEngineHandlerMutex()); qt_abstractfileenginehandlerlist_shutDown = true; } }; @@ -122,7 +122,7 @@ Q_GLOBAL_STATIC(QAbstractFileEngineHandlerList, fileEngineHandlers) */ QAbstractFileEngineHandler::QAbstractFileEngineHandler() { - QMutexLocker locker(fileEngineHandlerMutex()); + QWriteLocker locker(fileEngineHandlerMutex()); fileEngineHandlers()->prepend(this); } @@ -132,7 +132,7 @@ QAbstractFileEngineHandler::QAbstractFileEngineHandler() */ QAbstractFileEngineHandler::~QAbstractFileEngineHandler() { - QMutexLocker locker(fileEngineHandlerMutex()); + QWriteLocker locker(fileEngineHandlerMutex()); // Remove this handler from the handler list only if the list is valid. if (!qt_abstractfileenginehandlerlist_shutDown) fileEngineHandlers()->removeAll(this); @@ -166,12 +166,14 @@ QAbstractFileEngineHandler::~QAbstractFileEngineHandler() */ QAbstractFileEngine *QAbstractFileEngine::create(const QString &fileName) { - QMutexLocker locker(fileEngineHandlerMutex()); + { + QReadLocker locker(fileEngineHandlerMutex()); - // check for registered handlers that can load the file - for (int i = 0; i < fileEngineHandlers()->size(); i++) { - if (QAbstractFileEngine *ret = fileEngineHandlers()->at(i)->create(fileName)) - return ret; + // check for registered handlers that can load the file + for (int i = 0; i < fileEngineHandlers()->size(); i++) { + if (QAbstractFileEngine *ret = fileEngineHandlers()->at(i)->create(fileName)) + return ret; + } } #ifdef QT_BUILD_CORE_LIB diff --git a/src/corelib/io/qdiriterator.cpp b/src/corelib/io/qdiriterator.cpp index 582d657..3bfea65 100644 --- a/src/corelib/io/qdiriterator.cpp +++ b/src/corelib/io/qdiriterator.cpp @@ -106,26 +106,29 @@ public: QDir::Filters filters, QDirIterator::IteratorFlags flags); ~QDirIteratorPrivate(); - void pushSubDirectory(const QString &path, const QStringList &nameFilters, - QDir::Filters filters); void advance(); - bool shouldFollowDirectory(const QFileInfo &); + + void pushDirectory(const QFileInfo &fileInfo); + void checkAndPushDirectory(const QFileInfo &); bool matchesFilters(const QString &fileName, const QFileInfo &fi) const; - QSet<QString> visitedLinks; - QAbstractFileEngine *engine; + QAbstractFileEngine * const engine; + + const QString path; + const QStringList nameFilters; + const QDir::Filters filters; + const QDirIterator::IteratorFlags iteratorFlags; + +#ifndef QT_NO_REGEXP + QVector<QRegExp> nameRegExps; +#endif + QStack<QAbstractFileEngineIterator *> fileEngineIterators; - QString path; - QFileInfo nextFileInfo; - //This fileinfo is the current that we will return from the public API QFileInfo currentFileInfo; - QString currentFilePath; - QDirIterator::IteratorFlags iteratorFlags; - QDir::Filters filters; - QStringList nameFilters; - bool followNextDir; - bool first; - bool done; + QFileInfo nextFileInfo; + + // Loop protection + QSet<QString> visitedLinks; QDirIterator *q; }; @@ -135,15 +138,24 @@ public: */ QDirIteratorPrivate::QDirIteratorPrivate(const QString &path, const QStringList &nameFilters, QDir::Filters filters, QDirIterator::IteratorFlags flags) - : engine(0), path(path), nextFileInfo(path), iteratorFlags(flags), followNextDir(false), first(true), done(false) + : engine(QAbstractFileEngine::create(path)) + , path(path) + , nameFilters(nameFilters.contains(QLatin1String("*")) ? QStringList() : nameFilters) + , filters(QDir::NoFilter == filters ? QDir::AllEntries : filters) + , iteratorFlags(flags) { - if (filters == QDir::NoFilter) - filters = QDir::AllEntries; - this->filters = filters; - this->nameFilters = nameFilters; +#ifndef QT_NO_REGEXP + nameRegExps.reserve(nameFilters.size()); + for (int i = 0; i < nameFilters.size(); ++i) + nameRegExps.append( + QRegExp(nameFilters.at(i), + (filters & QDir::CaseSensitive) ? Qt::CaseSensitive : Qt::CaseInsensitive, + QRegExp::Wildcard)); +#endif - pushSubDirectory(nextFileInfo.isSymLink() ? nextFileInfo.canonicalFilePath() : path, - nameFilters, filters); + // Populate fields for hasNext() and next() + pushDirectory(QFileInfo(path)); + advance(); } /*! @@ -157,20 +169,19 @@ QDirIteratorPrivate::~QDirIteratorPrivate() /*! \internal */ -void QDirIteratorPrivate::pushSubDirectory(const QString &path, const QStringList &nameFilters, - QDir::Filters filters) +void QDirIteratorPrivate::pushDirectory(const QFileInfo &fileInfo) { - if (iteratorFlags & QDirIterator::FollowSymlinks) { - if (nextFileInfo.filePath() != path) - nextFileInfo.setFile(path); - if (nextFileInfo.isSymLink()) { - visitedLinks << nextFileInfo.canonicalFilePath(); - } else { - visitedLinks << nextFileInfo.absoluteFilePath(); - } - } - - if (engine || (engine = QAbstractFileEngine::create(this->path))) { + QString path = fileInfo.filePath(); + +#ifdef Q_OS_WIN + if (fileInfo.isSymLink()) + path = fileInfo.canonicalFilePath(); +#endif + + if (iteratorFlags & QDirIterator::FollowSymlinks) + visitedLinks << fileInfo.canonicalFilePath(); + + if (engine) { engine->setFileName(path); QAbstractFileEngineIterator *it = engine->beginEntryList(filters, nameFilters); if (it) { @@ -187,95 +198,64 @@ void QDirIteratorPrivate::pushSubDirectory(const QString &path, const QStringLis */ void QDirIteratorPrivate::advance() { - // Store the current entry - if (!fileEngineIterators.isEmpty()) - currentFilePath = fileEngineIterators.top()->currentFilePath(); - - // Advance to the next entry - if (followNextDir) { - // Start by navigating into the current directory. - followNextDir = false; - - QAbstractFileEngineIterator *it = fileEngineIterators.top(); - - QString subDir = it->currentFilePath(); -#ifdef Q_OS_WIN - if (nextFileInfo.isSymLink()) - subDir = nextFileInfo.canonicalFilePath(); -#endif - pushSubDirectory(subDir, it->nameFilters(), it->filters()); - } - while (!fileEngineIterators.isEmpty()) { - QAbstractFileEngineIterator *it = fileEngineIterators.top(); // Find the next valid iterator that matches the filters. - bool foundDirectory = false; - while (it->hasNext()) { + while (fileEngineIterators.top()->hasNext()) { + QAbstractFileEngineIterator *it = fileEngineIterators.top(); it->next(); + const QFileInfo info = it->currentFileInfo(); + checkAndPushDirectory(it->currentFileInfo()); + if (matchesFilters(it->currentFileName(), info)) { currentFileInfo = nextFileInfo; nextFileInfo = info; - // Signal that we want to follow this entry. - followNextDir = shouldFollowDirectory(nextFileInfo); + //We found a matching entry. return; - - } else if (iteratorFlags & QDirIterator::Subdirectories) { - - if (!shouldFollowDirectory(info)) - continue; - QString subDir = it->currentFilePath(); -#ifdef Q_OS_WIN - if (info.isSymLink()) - subDir = info.canonicalFilePath(); -#endif - pushSubDirectory(subDir, it->nameFilters(), it->filters()); - - foundDirectory = true; - break; } } - if (!foundDirectory) - delete fileEngineIterators.pop(); + + delete fileEngineIterators.pop(); } + currentFileInfo = nextFileInfo; - done = true; + nextFileInfo = QFileInfo(); } /*! \internal */ -bool QDirIteratorPrivate::shouldFollowDirectory(const QFileInfo &fileInfo) +void QDirIteratorPrivate::checkAndPushDirectory(const QFileInfo &fileInfo) { // If we're doing flat iteration, we're done. if (!(iteratorFlags & QDirIterator::Subdirectories)) - return false; - + return; + // Never follow non-directory entries if (!fileInfo.isDir()) - return false; + return; + // Follow symlinks only when asked + if (!(iteratorFlags & QDirIterator::FollowSymlinks) && fileInfo.isSymLink()) + return; // Never follow . and .. - if (fileInfo.fileName() == QLatin1String(".") || fileInfo.fileName() == QLatin1String("..")) - return false; + QString fileName = fileInfo.fileName(); + if (QLatin1String(".") == fileName || QLatin1String("..") == fileName) + return; - - // Check symlinks - if (fileInfo.isSymLink() && !(iteratorFlags & QDirIterator::FollowSymlinks)) { - // Follow symlinks only if FollowSymlinks was passed - return false; - } + // No hidden directories unless requested + if (!(filters & QDir::AllDirs) && !(filters & QDir::Hidden) && fileInfo.isHidden()) + return; // Stop link loops if (visitedLinks.contains(fileInfo.canonicalFilePath())) - return false; - - return true; + return; + + pushDirectory(fileInfo); } - /*! \internal @@ -289,10 +269,7 @@ bool QDirIteratorPrivate::shouldFollowDirectory(const QFileInfo &fileInfo) */ bool QDirIteratorPrivate::matchesFilters(const QString &fileName, const QFileInfo &fi) const { - if (fileName.isEmpty()) { - // invalid entry - return false; - } + Q_ASSERT(!fileName.isEmpty()); // filter . and ..? const int fileNameSize = fileName.size(); @@ -303,16 +280,15 @@ bool QDirIteratorPrivate::matchesFilters(const QString &fileName, const QFileInf return false; // name filter -#ifndef QT_NO_REGEXP - const bool hasNameFilters = !nameFilters.isEmpty() && !(nameFilters.contains(QLatin1String("*"))); +#ifndef QT_NO_REGEXP // Pass all entries through name filters, except dirs if the AllDirs - if (hasNameFilters && !((filters & QDir::AllDirs) && fi.isDir())) { + if (!nameFilters.isEmpty() && !((filters & QDir::AllDirs) && fi.isDir())) { bool matched = false; - for (int i = 0; i < nameFilters.size(); ++i) { - QRegExp regexp(nameFilters.at(i), - (filters & QDir::CaseSensitive) ? Qt::CaseSensitive : Qt::CaseInsensitive, - QRegExp::Wildcard); - if (regexp.exactMatch(fileName)) { + for (QVector<QRegExp>::const_iterator iter = nameRegExps.constBegin(), + end = nameRegExps.constEnd(); + iter != end; ++iter) { + + if (iter->exactMatch(fileName)) { matched = true; break; } @@ -368,7 +344,7 @@ bool QDirIteratorPrivate::matchesFilters(const QString &fileName, const QFileInf || (doExecutable && !fi.isExecutable()))) { return false; } - + return true; } @@ -410,7 +386,7 @@ QDirIterator::QDirIterator(const QDir &dir, IteratorFlags flags) \sa hasNext(), next(), IteratorFlags */ QDirIterator::QDirIterator(const QString &path, QDir::Filters filters, IteratorFlags flags) - : d(new QDirIteratorPrivate(path, QStringList(QLatin1String("*")), filters, flags)) + : d(new QDirIteratorPrivate(path, QStringList(), filters, flags)) { d->q = this; } @@ -428,7 +404,7 @@ QDirIterator::QDirIterator(const QString &path, QDir::Filters filters, IteratorF \sa hasNext(), next(), IteratorFlags */ QDirIterator::QDirIterator(const QString &path, IteratorFlags flags) - : d(new QDirIteratorPrivate(path, QStringList(QLatin1String("*")), QDir::NoFilter, flags)) + : d(new QDirIteratorPrivate(path, QStringList(), QDir::NoFilter, flags)) { d->q = this; } @@ -445,7 +421,7 @@ QDirIterator::QDirIterator(const QString &path, IteratorFlags flags) passed to the flags. \warning This constructor expects \c flags to be left at its default value. Use the - constructors that do not take the \a filters argument instead. + constructors that do not take the \a filters argument instead. \sa hasNext(), next(), IteratorFlags */ @@ -477,8 +453,6 @@ QDirIterator::~QDirIterator() */ QString QDirIterator::next() { - if (!hasNext()) - return QString(); d->advance(); return filePath(); } @@ -491,22 +465,17 @@ QString QDirIterator::next() */ bool QDirIterator::hasNext() const { - if (d->first) { - d->first = false; - d->advance(); - } - return !d->done; + return !d->fileEngineIterators.isEmpty(); } /*! Returns the file name for the current directory entry, without the path - prepended. If the current entry is invalid (i.e., isValid() returns - false), a null QString is returned. + prepended. + + This function is convenient when iterating a single directory. When using + the QDirIterator::Subdirectories flag, you can use filePath() to get the + full path. - This function is provided for the convenience when iterating single - directories. For recursive iteration, you should call filePath() or - fileInfo() instead. - \sa filePath(), fileInfo() */ QString QDirIterator::fileName() const @@ -515,20 +484,17 @@ QString QDirIterator::fileName() const } /*! - Returns the full file path for the current directory entry. If the current - entry is invalid (i.e., isValid() returns false), a null QString is - returned. + Returns the full file path for the current directory entry. \sa fileInfo(), fileName() */ QString QDirIterator::filePath() const { - return d->currentFilePath; + return d->currentFileInfo.filePath(); } /*! - Returns a QFileInfo for the current directory entry. If the current entry - is invalid (i.e., isValid() returns false), a null QFileInfo is returned. + Returns a QFileInfo for the current directory entry. \sa filePath(), fileName() */ diff --git a/src/corelib/io/qfilesystemwatcher_p.h b/src/corelib/io/qfilesystemwatcher_p.h index 850e150..83be197 100644 --- a/src/corelib/io/qfilesystemwatcher_p.h +++ b/src/corelib/io/qfilesystemwatcher_p.h @@ -69,13 +69,14 @@ class QFileSystemWatcherEngine : public QThread Q_OBJECT protected: - inline QFileSystemWatcherEngine() + inline QFileSystemWatcherEngine(bool move = true) { - moveToThread(this); + if (move) + moveToThread(this); } public: - // fills \a files and \a directires with the \a paths it could + // fills \a files and \a directories with the \a paths it could // watch, and returns a list of paths this engine could not watch virtual QStringList addPaths(const QStringList &paths, QStringList *files, diff --git a/src/corelib/io/qfilesystemwatcher_win.cpp b/src/corelib/io/qfilesystemwatcher_win.cpp index c15b1d2..9eeef02 100644 --- a/src/corelib/io/qfilesystemwatcher_win.cpp +++ b/src/corelib/io/qfilesystemwatcher_win.cpp @@ -53,23 +53,268 @@ QT_BEGIN_NAMESPACE +void QWindowsFileSystemWatcherEngine::stop() +{ + foreach(QWindowsFileSystemWatcherEngineThread *thread, threads) + thread->stop(); +} + QWindowsFileSystemWatcherEngine::QWindowsFileSystemWatcherEngine() - : msg(0) + : QFileSystemWatcherEngine(false) { - if (HANDLE h = CreateEvent(0, false, false, 0)) { - handles.reserve(MAXIMUM_WAIT_OBJECTS); - handles.append(h); - } } QWindowsFileSystemWatcherEngine::~QWindowsFileSystemWatcherEngine() { - if (handles.isEmpty()) + if (threads.isEmpty()) return; - stop(); - wait(); + foreach(QWindowsFileSystemWatcherEngineThread *thread, threads) { + thread->stop(); + thread->wait(); + delete thread; + } +} + +QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths, + QStringList *files, + QStringList *directories) +{ + // qDebug()<<"Adding"<<paths.count()<<"to existing"<<(files->count() + directories->count())<<"watchers"; + QStringList p = paths; + QMutableListIterator<QString> it(p); + while (it.hasNext()) { + QString path = it.next(); + QString normalPath = path; + if ((normalPath.endsWith(QLatin1Char('/')) || normalPath.endsWith(QLatin1Char('\\'))) +#ifdef Q_OS_WINCE + && normalPath.size() > 1) +#else + ) +#endif + normalPath.chop(1); + QFileInfo fileInfo(normalPath.toLower()); + if (!fileInfo.exists()) + continue; + + bool isDir = fileInfo.isDir(); + if (isDir) { + if (directories->contains(path)) + continue; + } else { + if (files->contains(path)) + continue; + } + + // qDebug()<<"Looking for a thread/handle for"<<normalPath; + + const QString absolutePath = isDir ? fileInfo.absoluteFilePath() : fileInfo.absolutePath(); + const uint flags = isDir + ? (FILE_NOTIFY_CHANGE_DIR_NAME + | FILE_NOTIFY_CHANGE_FILE_NAME) + : (FILE_NOTIFY_CHANGE_DIR_NAME + | FILE_NOTIFY_CHANGE_FILE_NAME + | FILE_NOTIFY_CHANGE_ATTRIBUTES + | FILE_NOTIFY_CHANGE_SIZE + | FILE_NOTIFY_CHANGE_LAST_WRITE + | FILE_NOTIFY_CHANGE_SECURITY); + + QWindowsFileSystemWatcherEngine::PathInfo pathInfo; + pathInfo.absolutePath = absolutePath; + pathInfo.isDir = isDir; + pathInfo.path = path; + pathInfo = fileInfo; + + // Look for a thread + QWindowsFileSystemWatcherEngineThread *thread = 0; + QWindowsFileSystemWatcherEngine::Handle handle; + QList<QWindowsFileSystemWatcherEngineThread *>::const_iterator jt, end; + end = threads.constEnd(); + for(jt = threads.constBegin(); jt != end; ++jt) { + thread = *jt; + QMutexLocker locker(&(thread->mutex)); + + handle = thread->handleForDir.value(absolutePath); + if (handle.handle != INVALID_HANDLE_VALUE && handle.flags == flags) { + // found a thread now insert... + // qDebug()<<" Found a thread"<<thread; + + QHash<QString, QWindowsFileSystemWatcherEngine::PathInfo> &h + = thread->pathInfoForHandle[handle.handle]; + if (!h.contains(fileInfo.absoluteFilePath())) { + thread->pathInfoForHandle[handle.handle].insert(fileInfo.absoluteFilePath(), pathInfo); + if (isDir) + directories->append(path); + else + files->append(path); + } + it.remove(); + thread->wakeup(); + break; + } + } + + // no thread found, first create a handle + if (handle.handle == INVALID_HANDLE_VALUE || handle.flags != flags) { + // qDebug()<<" No thread found"; + // Volume and folder paths need a trailing slash for proper notification + // (e.g. "c:" -> "c:/"). + const QString effectiveAbsolutePath = + isDir ? (absolutePath + QLatin1Char('/')) : absolutePath; + + handle.handle = FindFirstChangeNotification((wchar_t*) QDir::toNativeSeparators(effectiveAbsolutePath).utf16(), false, flags); + handle.flags = flags; + if (handle.handle == INVALID_HANDLE_VALUE) + continue; + + // now look for a thread to insert + bool found = false; + foreach(QWindowsFileSystemWatcherEngineThread *thread, threads) { + QMutexLocker(&(thread->mutex)); + if (thread->handles.count() < MAXIMUM_WAIT_OBJECTS) { + // qDebug() << " Added handle" << handle.handle << "for" << absolutePath << "to watch" << fileInfo.absoluteFilePath(); + // qDebug()<< " to existing thread"<<thread; + thread->handles.append(handle.handle); + thread->handleForDir.insert(absolutePath, handle); + + thread->pathInfoForHandle[handle.handle].insert(fileInfo.absoluteFilePath(), pathInfo); + if (isDir) + directories->append(path); + else + files->append(path); + + it.remove(); + found = true; + thread->wakeup(); + break; + } + } + if (!found) { + QWindowsFileSystemWatcherEngineThread *thread = new QWindowsFileSystemWatcherEngineThread(); + //qDebug()<<" ###Creating new thread"<<thread<<"("<<(threads.count()+1)<<"threads)"; + thread->handles.append(handle.handle); + thread->handleForDir.insert(absolutePath, handle); + + thread->pathInfoForHandle[handle.handle].insert(fileInfo.absoluteFilePath(), pathInfo); + if (isDir) + directories->append(path); + else + files->append(path); + + connect(thread, SIGNAL(fileChanged(const QString &, bool)), + this, SIGNAL(fileChanged(const QString &, bool))); + connect(thread, SIGNAL(directoryChanged(const QString &, bool)), + this, SIGNAL(directoryChanged(const QString &, bool))); + + thread->msg = '@'; + thread->start(); + threads.append(thread); + it.remove(); + } + } + } + return p; +} + +QStringList QWindowsFileSystemWatcherEngine::removePaths(const QStringList &paths, + QStringList *files, + QStringList *directories) +{ + // qDebug()<<"removePaths"<<paths; + QStringList p = paths; + QMutableListIterator<QString> it(p); + while (it.hasNext()) { + QString path = it.next(); + QString normalPath = path; + if (normalPath.endsWith(QLatin1Char('/')) || normalPath.endsWith(QLatin1Char('\\'))) + normalPath.chop(1); + QFileInfo fileInfo(normalPath.toLower()); + // qDebug()<<"removing"<<normalPath; + QString absolutePath = fileInfo.absoluteFilePath(); + QList<QWindowsFileSystemWatcherEngineThread *>::iterator jt, end; + end = threads.end(); + for(jt = threads.begin(); jt!= end; ++jt) { + QWindowsFileSystemWatcherEngineThread *thread = *jt; + if (*jt == 0) + continue; + + QMutexLocker locker(&(thread->mutex)); + + QWindowsFileSystemWatcherEngine::Handle handle = thread->handleForDir.value(absolutePath); + if (handle.handle == INVALID_HANDLE_VALUE) { + // perhaps path is a file? + absolutePath = fileInfo.absolutePath(); + handle = thread->handleForDir.value(absolutePath); + } + if (handle.handle != INVALID_HANDLE_VALUE) { + QHash<QString, QWindowsFileSystemWatcherEngine::PathInfo> &h = + thread->pathInfoForHandle[handle.handle]; + if (h.remove(fileInfo.absoluteFilePath())) { + // ### + files->removeAll(path); + directories->removeAll(path); + + if (h.isEmpty()) { + // qDebug() << "Closing handle" << handle.handle; + FindCloseChangeNotification(handle.handle); // This one might generate a notification + + int indexOfHandle = thread->handles.indexOf(handle.handle); + Q_ASSERT(indexOfHandle != -1); + thread->handles.remove(indexOfHandle); + + thread->handleForDir.remove(absolutePath); + // h is now invalid + + it.remove(); + + if (thread->handleForDir.isEmpty()) { + // qDebug()<<"Stopping thread "<<thread; + locker.unlock(); + thread->stop(); + thread->wait(); + locker.relock(); + // We can't delete the thread until the mutex locker is + // out of scope + } + } + } + // Found the file, go to next one + break; + } + } + } + + // Remove all threads that we stopped + QList<QWindowsFileSystemWatcherEngineThread *>::iterator jt, end; + end = threads.end(); + for(jt = threads.begin(); jt != end; ++jt) { + if (!(*jt)->isRunning()) { + delete *jt; + *jt = 0; + } + } + + threads.removeAll(0); + return p; +} + +/////////// +// QWindowsFileSystemWatcherEngineThread +/////////// +QWindowsFileSystemWatcherEngineThread::QWindowsFileSystemWatcherEngineThread() + : msg(0) +{ + if (HANDLE h = CreateEvent(0, false, false, 0)) { + handles.reserve(MAXIMUM_WAIT_OBJECTS); + handles.append(h); + } + moveToThread(this); +} + + +QWindowsFileSystemWatcherEngineThread::~QWindowsFileSystemWatcherEngineThread() +{ CloseHandle(handles.at(0)); handles[0] = INVALID_HANDLE_VALUE; @@ -80,13 +325,13 @@ QWindowsFileSystemWatcherEngine::~QWindowsFileSystemWatcherEngine() } } -void QWindowsFileSystemWatcherEngine::run() +void QWindowsFileSystemWatcherEngineThread::run() { QMutexLocker locker(&mutex); forever { QVector<HANDLE> handlesCopy = handles; locker.unlock(); - // qDebug() << "QWindowsFileSystemWatcherEngine: waiting on" << handlesCopy.count() << "handles"; + // qDebug() << "QWindowsFileSystemWatcherThread"<<this<<"waiting on" << handlesCopy.count() << "handles"; DWORD r = WaitForMultipleObjects(handlesCopy.count(), handlesCopy.constData(), false, INFINITE); locker.relock(); do { @@ -94,7 +339,7 @@ void QWindowsFileSystemWatcherEngine::run() int m = msg; msg = 0; if (m == 'q') { - // qDebug() << "thread told to quit"; + // qDebug() << "thread"<<this<<"told to quit"; return; } if (m != '@') { @@ -109,15 +354,15 @@ void QWindowsFileSystemWatcherEngine::run() // When removing a path, FindCloseChangeNotification might actually fire a notification // for some reason, so we must check if the handle exist in the handles vector if (handles.contains(handle)) { - // qDebug("Acknowledged handle: %d, %p", at, handle); + // qDebug()<<"thread"<<this<<"Acknowledged handle:"<<at<<handle; if (!FindNextChangeNotification(handle)) { - qErrnoWarning("QFileSystemWatcher: FindNextChangeNotification failed"); + qErrnoWarning("QFileSystemWatcher: FindNextChangeNotification failed!!"); } - QHash<QString, PathInfo> &h = pathInfoForHandle[handle]; - QMutableHashIterator<QString, PathInfo> it(h); + QHash<QString, QWindowsFileSystemWatcherEngine::PathInfo> &h = pathInfoForHandle[handle]; + QMutableHashIterator<QString, QWindowsFileSystemWatcherEngine::PathInfo> it(h); while (it.hasNext()) { - QHash<QString, PathInfo>::iterator x = it.next(); + QHash<QString, QWindowsFileSystemWatcherEngine::PathInfo>::iterator x = it.next(); QString absolutePath = x.value().absolutePath; QFileInfo fileInfo(x.value().path); // qDebug() << "checking" << x.key(); @@ -162,160 +407,14 @@ void QWindowsFileSystemWatcherEngine::run() } } -QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths, - QStringList *files, - QStringList *directories) -{ - if (handles.isEmpty() || handles.count() == MAXIMUM_WAIT_OBJECTS) - return paths; - - QMutexLocker locker(&mutex); - - QStringList p = paths; - QMutableListIterator<QString> it(p); - while (it.hasNext()) { - QString path = it.next(); - QString normalPath = path; - if ((normalPath.endsWith(QLatin1Char('/')) || normalPath.endsWith(QLatin1Char('\\'))) -#ifdef Q_OS_WINCE - && normalPath.size() > 1) -#else - ) -#endif - normalPath.chop(1); - QFileInfo fileInfo(normalPath.toLower()); - if (!fileInfo.exists()) - continue; - - bool isDir = fileInfo.isDir(); - if (isDir) { - if (directories->contains(path)) - continue; - } else { - if (files->contains(path)) - continue; - } - const QString absolutePath = isDir ? fileInfo.absoluteFilePath() : fileInfo.absolutePath(); - const uint flags = isDir - ? (FILE_NOTIFY_CHANGE_DIR_NAME - | FILE_NOTIFY_CHANGE_FILE_NAME) - : (FILE_NOTIFY_CHANGE_DIR_NAME - | FILE_NOTIFY_CHANGE_FILE_NAME - | FILE_NOTIFY_CHANGE_ATTRIBUTES - | FILE_NOTIFY_CHANGE_SIZE - | FILE_NOTIFY_CHANGE_LAST_WRITE - | FILE_NOTIFY_CHANGE_SECURITY); - - Handle handle = handleForDir.value(absolutePath); - if (handle.handle == INVALID_HANDLE_VALUE || handle.flags != flags) { - // Volume and folder paths need a trailing slash for proper notification - // (e.g. "c:" -> "c:/"). - const QString effectiveAbsolutePath = - isDir ? (absolutePath + QLatin1Char('/')) : absolutePath; - - handle.handle = FindFirstChangeNotification((wchar_t*) QDir::toNativeSeparators(effectiveAbsolutePath).utf16(), false, flags); - handle.flags = flags; - if (handle.handle == INVALID_HANDLE_VALUE) - continue; - // qDebug() << "Added handle" << handle << "for" << absolutePath << "to watch" << fileInfo.absoluteFilePath(); - handles.append(handle.handle); - handleForDir.insert(absolutePath, handle); - } - - PathInfo pathInfo; - pathInfo.absolutePath = absolutePath; - pathInfo.isDir = isDir; - pathInfo.path = path; - pathInfo = fileInfo; - QHash<QString, PathInfo> &h = pathInfoForHandle[handle.handle]; - if (!h.contains(fileInfo.absoluteFilePath())) { - pathInfoForHandle[handle.handle].insert(fileInfo.absoluteFilePath(), pathInfo); - if (isDir) - directories->append(path); - else - files->append(path); - } - - it.remove(); - } - - if (!isRunning()) { - msg = '@'; - start(); - } else { - wakeup(); - } - - return p; -} - -QStringList QWindowsFileSystemWatcherEngine::removePaths(const QStringList &paths, - QStringList *files, - QStringList *directories) -{ - QMutexLocker locker(&mutex); - - QStringList p = paths; - QMutableListIterator<QString> it(p); - while (it.hasNext()) { - QString path = it.next(); - QString normalPath = path; - if (normalPath.endsWith(QLatin1Char('/')) || normalPath.endsWith(QLatin1Char('\\'))) - normalPath.chop(1); - QFileInfo fileInfo(normalPath.toLower()); - - QString absolutePath = fileInfo.absoluteFilePath(); - Handle handle = handleForDir.value(absolutePath); - if (handle.handle == INVALID_HANDLE_VALUE) { - // perhaps path is a file? - absolutePath = fileInfo.absolutePath(); - handle = handleForDir.value(absolutePath); - if (handle.handle == INVALID_HANDLE_VALUE) - continue; - } - - QHash<QString, PathInfo> &h = pathInfoForHandle[handle.handle]; - if (h.remove(fileInfo.absoluteFilePath())) { - // ### - files->removeAll(path); - directories->removeAll(path); - - if (h.isEmpty()) { - // qDebug() << "Closing handle" << handle; - FindCloseChangeNotification(handle.handle); // This one might generate a notification - - int indexOfHandle = handles.indexOf(handle.handle); - Q_ASSERT(indexOfHandle != -1); - handles.remove(indexOfHandle); - - handleForDir.remove(absolutePath); - // h is now invalid - - it.remove(); - } - } - } - - if (handleForDir.isEmpty()) { - stop(); - locker.unlock(); - wait(); - locker.relock(); - } else { - wakeup(); - } - - return p; -} - -void QWindowsFileSystemWatcherEngine::stop() +void QWindowsFileSystemWatcherEngineThread::stop() { msg = 'q'; SetEvent(handles.at(0)); } -void QWindowsFileSystemWatcherEngine::wakeup() +void QWindowsFileSystemWatcherEngineThread::wakeup() { msg = '@'; SetEvent(handles.at(0)); diff --git a/src/corelib/io/qfilesystemwatcher_win_p.h b/src/corelib/io/qfilesystemwatcher_win_p.h index 5d42cac..405d255 100644 --- a/src/corelib/io/qfilesystemwatcher_win_p.h +++ b/src/corelib/io/qfilesystemwatcher_win_p.h @@ -68,27 +68,24 @@ QT_BEGIN_NAMESPACE +class QWindowsFileSystemWatcherEngineThread; + +// Even though QWindowsFileSystemWatcherEngine is derived of QThread +// via QFileSystemWatcher, it does not start a thread. +// Instead QWindowsFileSystemWatcher creates QWindowsFileSystemWatcherEngineThreads +// to do the actually watching. class QWindowsFileSystemWatcherEngine : public QFileSystemWatcherEngine { Q_OBJECT - public: QWindowsFileSystemWatcherEngine(); ~QWindowsFileSystemWatcherEngine(); - void run(); - QStringList addPaths(const QStringList &paths, QStringList *files, QStringList *directories); QStringList removePaths(const QStringList &paths, QStringList *files, QStringList *directories); void stop(); -private: - void wakeup(); - - QMutex mutex; - QVector<HANDLE> handles; - int msg; class Handle { @@ -97,13 +94,12 @@ private: uint flags; Handle() - : handle(INVALID_HANDLE_VALUE), flags(0u) + : handle(INVALID_HANDLE_VALUE), flags(0u) { } Handle(const Handle &other) - : handle(other.handle), flags(other.flags) + : handle(other.handle), flags(other.flags) { } }; - QHash<QString, Handle> handleForDir; class PathInfo { public: @@ -118,7 +114,7 @@ private: QDateTime lastModified; PathInfo &operator=(const QFileInfo &fileInfo) - { + { ownerId = fileInfo.ownerId(); groupId = fileInfo.groupId(); permissions = fileInfo.permissions(); @@ -134,8 +130,35 @@ private: || lastModified != fileInfo.lastModified()); } }; - QHash<HANDLE, QHash<QString, PathInfo> > pathInfoForHandle; +private: + QList<QWindowsFileSystemWatcherEngineThread *> threads; + +}; + +class QWindowsFileSystemWatcherEngineThread : public QThread +{ + Q_OBJECT + +public: + QWindowsFileSystemWatcherEngineThread(); + ~QWindowsFileSystemWatcherEngineThread(); + void run(); + void stop(); + void wakeup(); + + QMutex mutex; + QVector<HANDLE> handles; + int msg; + + QHash<QString, QWindowsFileSystemWatcherEngine::Handle> handleForDir; + + QHash<HANDLE, QHash<QString, QWindowsFileSystemWatcherEngine::PathInfo> > pathInfoForHandle; + +Q_SIGNALS: + void fileChanged(const QString &path, bool removed); + void directoryChanged(const QString &path, bool removed); }; + #endif // QT_NO_FILESYSTEMWATCHER QT_END_NAMESPACE diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp index beafe72..3a43ec7 100644 --- a/src/corelib/io/qfsfileengine.cpp +++ b/src/corelib/io/qfsfileengine.cpp @@ -44,6 +44,7 @@ #include "qdatetime.h" #include "qdiriterator.h" #include "qset.h" +#include <QtCore/qdebug.h> #ifndef QT_NO_FSFILEENGINE @@ -571,7 +572,7 @@ bool QFSFileEnginePrivate::seekFdFh(qint64 pos) } else { // Unbuffered stdio mode. if (QT_LSEEK(fd, pos, SEEK_SET) == -1) { - qWarning("QFile::at: Cannot set file position %lld", pos); + qWarning() << "QFile::at: Cannot set file position" << pos; q->setError(QFile::PositionError, qt_error_string(errno)); return false; } diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp index fcace33..53f0144 100644 --- a/src/corelib/io/qfsfileengine_win.cpp +++ b/src/corelib/io/qfsfileengine_win.cpp @@ -109,9 +109,9 @@ static QString qfsPrivateCurrentDir = QLatin1String(""); QT_BEGIN_INCLUDE_NAMESPACE typedef DWORD (WINAPI *PtrGetNamedSecurityInfoW)(LPWSTR, SE_OBJECT_TYPE, SECURITY_INFORMATION, PSID*, PSID*, PACL*, PACL*, PSECURITY_DESCRIPTOR*); static PtrGetNamedSecurityInfoW ptrGetNamedSecurityInfoW = 0; -typedef DECLSPEC_IMPORT BOOL (WINAPI *PtrLookupAccountSidW)(LPCWSTR, PSID, LPWSTR, LPDWORD, LPWSTR, LPDWORD, PSID_NAME_USE); +typedef BOOL (WINAPI *PtrLookupAccountSidW)(LPCWSTR, PSID, LPWSTR, LPDWORD, LPWSTR, LPDWORD, PSID_NAME_USE); static PtrLookupAccountSidW ptrLookupAccountSidW = 0; -typedef DECLSPEC_IMPORT BOOL (WINAPI *PtrAllocateAndInitializeSid)(PSID_IDENTIFIER_AUTHORITY, BYTE, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, PSID*); +typedef BOOL (WINAPI *PtrAllocateAndInitializeSid)(PSID_IDENTIFIER_AUTHORITY, BYTE, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, PSID*); static PtrAllocateAndInitializeSid ptrAllocateAndInitializeSid = 0; typedef VOID (WINAPI *PtrBuildTrusteeWithSidW)(PTRUSTEE_W, PSID); static PtrBuildTrusteeWithSidW ptrBuildTrusteeWithSidW = 0; @@ -119,7 +119,7 @@ typedef VOID (WINAPI *PtrBuildTrusteeWithNameW)(PTRUSTEE_W, unsigned short*); static PtrBuildTrusteeWithNameW ptrBuildTrusteeWithNameW = 0; typedef DWORD (WINAPI *PtrGetEffectiveRightsFromAclW)(PACL, PTRUSTEE_W, OUT PACCESS_MASK); static PtrGetEffectiveRightsFromAclW ptrGetEffectiveRightsFromAclW = 0; -typedef DECLSPEC_IMPORT PVOID (WINAPI *PtrFreeSid)(PSID); +typedef PVOID (WINAPI *PtrFreeSid)(PSID); static PtrFreeSid ptrFreeSid = 0; static TRUSTEE_W currentUserTrusteeW; @@ -165,11 +165,11 @@ void QFSFileEnginePrivate::resolveLibs() if (ptrBuildTrusteeWithNameW) { HINSTANCE versionHnd = LoadLibraryW(L"version"); if (versionHnd) { - typedef DWORD (WINAPI *PtrGetFileVersionInfoSizeW)(LPWSTR lptstrFilename,LPDWORD lpdwHandle); + typedef DWORD (WINAPI *PtrGetFileVersionInfoSizeW)(LPCWSTR lptstrFilename,LPDWORD lpdwHandle); PtrGetFileVersionInfoSizeW ptrGetFileVersionInfoSizeW = (PtrGetFileVersionInfoSizeW)GetProcAddress(versionHnd, "GetFileVersionInfoSizeW"); - typedef BOOL (WINAPI *PtrGetFileVersionInfoW)(LPWSTR lptstrFilename,DWORD dwHandle,DWORD dwLen,LPVOID lpData); + typedef BOOL (WINAPI *PtrGetFileVersionInfoW)(LPCWSTR lptstrFilename,DWORD dwHandle,DWORD dwLen,LPVOID lpData); PtrGetFileVersionInfoW ptrGetFileVersionInfoW = (PtrGetFileVersionInfoW)GetProcAddress(versionHnd, "GetFileVersionInfoW"); - typedef BOOL (WINAPI *PtrVerQueryValueW)(const LPVOID pBlock,LPWSTR lpSubBlock,LPVOID *lplpBuffer,PUINT puLen); + typedef BOOL (WINAPI *PtrVerQueryValueW)(const LPVOID pBlock,LPCWSTR lpSubBlock,LPVOID *lplpBuffer,PUINT puLen); PtrVerQueryValueW ptrVerQueryValueW = (PtrVerQueryValueW)GetProcAddress(versionHnd, "VerQueryValueW"); if(ptrGetFileVersionInfoSizeW && ptrGetFileVersionInfoW && ptrVerQueryValueW) { DWORD fakeHandle; @@ -527,6 +527,29 @@ qint64 QFSFileEnginePrivate::nativeSize() const WIN32_FILE_ATTRIBUTE_DATA attribData; bool ok = ::GetFileAttributesEx((const wchar_t*)nativeFilePath.constData(), GetFileExInfoStandard, &attribData); + if (!ok) { + int errorCode = GetLastError(); + if (errorCode != ERROR_INVALID_NAME + && errorCode != ERROR_FILE_NOT_FOUND && errorCode != ERROR_PATH_NOT_FOUND) { + QByteArray path = nativeFilePath; + // path for the FindFirstFile should not end with a trailing slash + while (path.endsWith('\\')) + path.chop(1); + + // FindFirstFile can not handle drives + if (!path.endsWith(':')) { + WIN32_FIND_DATA findData; + HANDLE hFind = ::FindFirstFile((const wchar_t*)path.constData(), + &findData); + if (hFind != INVALID_HANDLE_VALUE) { + ::FindClose(hFind); + ok = true; + attribData.nFileSizeHigh = findData.nFileSizeHigh; + attribData.nFileSizeLow = findData.nFileSizeLow; + } + } + } + } if (ok) { qint64 size = attribData.nFileSizeHigh; size <<= 32; @@ -878,6 +901,26 @@ static inline bool isDirPath(const QString &dirPath, bool *existed) path += QLatin1Char('\\'); DWORD fileAttrib = ::GetFileAttributes((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16()); + if (fileAttrib == INVALID_FILE_ATTRIBUTES) { + int errorCode = GetLastError(); + if (errorCode != ERROR_INVALID_NAME + && errorCode != ERROR_FILE_NOT_FOUND && errorCode != ERROR_PATH_NOT_FOUND) { + // path for the FindFirstFile should not end with a trailing slash + while (path.endsWith(QLatin1Char('\\'))) + path.chop(1); + + // FindFirstFile can not handle drives + if (!path.endsWith(QLatin1Char(':'))) { + WIN32_FIND_DATA findData; + HANDLE hFind = ::FindFirstFile((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16(), + &findData); + if (hFind != INVALID_HANDLE_VALUE) { + ::FindClose(hFind); + fileAttrib = findData.dwFileAttributes; + } + } + } + } if (existed) *existed = fileAttrib != INVALID_FILE_ATTRIBUTES; @@ -1149,6 +1192,27 @@ bool QFSFileEnginePrivate::doStat() const #endif } else { fileAttrib = GetFileAttributes((wchar_t*)QFSFileEnginePrivate::longFileName(fname).utf16()); + if (fileAttrib == INVALID_FILE_ATTRIBUTES) { + int errorCode = GetLastError(); + if (errorCode != ERROR_INVALID_NAME + && errorCode != ERROR_FILE_NOT_FOUND && errorCode != ERROR_PATH_NOT_FOUND) { + QString path = QDir::toNativeSeparators(fname); + // path for the FindFirstFile should not end with a trailing slash + while (path.endsWith(QLatin1Char('\\'))) + path.chop(1); + + // FindFirstFile can not handle drives + if (!path.endsWith(QLatin1Char(':'))) { + WIN32_FIND_DATA findData; + HANDLE hFind = ::FindFirstFile((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16(), + &findData); + if (hFind != INVALID_HANDLE_VALUE) { + ::FindClose(hFind); + fileAttrib = findData.dwFileAttributes; + } + } + } + } could_stat = fileAttrib != INVALID_FILE_ATTRIBUTES; if (!could_stat) { #if !defined(Q_OS_WINCE) @@ -1519,8 +1583,8 @@ QString QFSFileEngine::fileName(FileName file) const if (!isRelativePath()) { #if !defined(Q_OS_WINCE) - if (d->filePath.size() > 2 && d->filePath.at(1) == QLatin1Char(':') - && d->filePath.at(2) != QLatin1Char('/') || // It's a drive-relative path, so Z:a.txt -> Z:\currentpath\a.txt + if ((d->filePath.size() > 2 && d->filePath.at(1) == QLatin1Char(':') + && d->filePath.at(2) != QLatin1Char('/')) || // It's a drive-relative path, so Z:a.txt -> Z:\currentpath\a.txt d->filePath.startsWith(QLatin1Char('/')) // It's a absolute path to the current drive, so \a.txt -> Z:\a.txt ) { ret = QDir::fromNativeSeparators(nativeAbsoluteFilePath(d->filePath)); @@ -1744,6 +1808,30 @@ QDateTime QFSFileEngine::fileTime(FileTime time) const } else { WIN32_FILE_ATTRIBUTE_DATA attribData; bool ok = ::GetFileAttributesEx((wchar_t*)QFSFileEnginePrivate::longFileName(d->filePath).utf16(), GetFileExInfoStandard, &attribData); + if (!ok) { + int errorCode = GetLastError(); + if (errorCode != ERROR_INVALID_NAME + && errorCode != ERROR_FILE_NOT_FOUND && errorCode != ERROR_PATH_NOT_FOUND) { + QString path = QDir::toNativeSeparators(d->filePath); + // path for the FindFirstFile should not end with a trailing slash + while (path.endsWith(QLatin1Char('\\'))) + path.chop(1); + + // FindFirstFile can not handle drives + if (!path.endsWith(QLatin1Char(':'))) { + WIN32_FIND_DATA findData; + HANDLE hFind = ::FindFirstFile((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16(), + &findData); + if (hFind != INVALID_HANDLE_VALUE) { + ::FindClose(hFind); + ok = true; + attribData.ftCreationTime = findData.ftCreationTime; + attribData.ftLastWriteTime = findData.ftLastWriteTime; + attribData.ftLastAccessTime = findData.ftLastAccessTime; + } + } + } + } if (ok) { if(time == CreationTime) ret = fileTimeToQDateTime(&attribData.ftCreationTime); diff --git a/src/corelib/io/qresource_iterator.cpp b/src/corelib/io/qresource_iterator.cpp index e97ac59..11f4acf 100644 --- a/src/corelib/io/qresource_iterator.cpp +++ b/src/corelib/io/qresource_iterator.cpp @@ -73,13 +73,11 @@ bool QResourceFileEngineIterator::hasNext() const return false; // Initialize and move to the next entry. - QResourceFileEngineIterator *that = const_cast<QResourceFileEngineIterator *>(this); - that->entries = resource.children(); - if (!that->entries.isEmpty()) - that->index = 0; + entries = resource.children(); + index = 0; } - return index <= entries.size(); + return index < entries.size(); } QString QResourceFileEngineIterator::currentFileName() const diff --git a/src/corelib/io/qresource_iterator_p.h b/src/corelib/io/qresource_iterator_p.h index b5e8382..5165157 100644 --- a/src/corelib/io/qresource_iterator_p.h +++ b/src/corelib/io/qresource_iterator_p.h @@ -71,8 +71,8 @@ public: QString currentFileName() const; private: - QStringList entries; - int index; + mutable QStringList entries; + mutable int index; }; QT_END_NAMESPACE diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index 180e9ec..79cd2f0 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -2336,12 +2336,12 @@ static const NameprepCaseFoldingEntry NameprepCaseFolding[] = { { 0x1D7BB, { 0x03C3, 0x0000, 0x0000, 0x0000 } } }; -static void mapToLowerCase(QString *str) +static void mapToLowerCase(QString *str, int from) { int N = sizeof(NameprepCaseFolding) / sizeof(NameprepCaseFolding[0]); QChar *d = 0; - for (int i = 0; i < str->size(); ++i) { + for (int i = from; i < str->size(); ++i) { int uc = str->at(i).unicode(); if (uc < 0x80) { if (uc <= 'Z' && uc >= 'A') { @@ -2388,11 +2388,11 @@ static bool isMappedToNothing(const QChar &ch) } -static void stripProhibitedOutput(QString *str) +static void stripProhibitedOutput(QString *str, int from) { - ushort *out = (ushort *)str->data(); + ushort *out = (ushort *)str->data() + from; const ushort *in = out; - const ushort *end = out + str->size(); + const ushort *end = (ushort *)str->data() + str->size(); while (in < end) { ushort uc = *in; if (uc < 0x80 || @@ -2901,66 +2901,99 @@ static bool isBidirectionalL(const QChar &ch) return false; } +#ifdef QT_BUILD_INTERNAL +// export for tst_qurl.cpp +Q_AUTOTEST_EXPORT void qt_nameprep(QString *source, int from); +Q_AUTOTEST_EXPORT bool qt_check_std3rules(const QChar *uc, int len); +#else +// non-test build, keep the symbols for ourselves +static void qt_nameprep(QString *source, int from); +static bool qt_check_std3rules(const QChar *uc, int len); +#endif -Q_AUTOTEST_EXPORT QString qt_nameprep(const QString &source) +void qt_nameprep(QString *source, int from) { - QString mapped = source; - - bool simple = true; - for (int i = 0; i < mapped.size(); ++i) { - ushort uc = mapped.at(i).unicode(); + QChar *src = source->data(); // causes a detach, so we're sure the only one using it + QChar *out = src + from; + const QChar *e = src + source->size(); + + for ( ; out < e; ++out) { + register ushort uc = out->unicode(); if (uc > 0x80) { - simple = false; break; } else if (uc >= 'A' && uc <= 'Z') { - mapped[i] = QChar(uc | 0x20); + *out = QChar(uc | 0x20); } } - if (simple) - return mapped; - + if (out == e) + return; // everything was mapped easily (lowercased, actually) + int firstNonAscii = out - src; + // Characters commonly mapped to nothing are simply removed // (Table B.1) - QChar *out = mapped.data(); const QChar *in = out; - const QChar *e = in + mapped.size(); while (in < e) { if (!isMappedToNothing(*in)) *out++ = *in; ++in; } if (out != in) - mapped.truncate(out - mapped.constData()); + source->truncate(out - src); // Map to lowercase (Table B.2) - mapToLowerCase(&mapped); + mapToLowerCase(source, firstNonAscii); // Normalize to Unicode 3.2 form KC - mapped = mapped.normalized(QString::NormalizationForm_KC, QChar::Unicode_3_2); + extern void qt_string_normalize(QString *data, QString::NormalizationForm mode, + QChar::UnicodeVersion version, int from); + qt_string_normalize(source, QString::NormalizationForm_KC, QChar::Unicode_3_2, firstNonAscii); // Strip prohibited output - stripProhibitedOutput(&mapped); + stripProhibitedOutput(source, firstNonAscii); // Check for valid bidirectional characters bool containsLCat = false; bool containsRandALCat = false; - for (int j = 0; j < mapped.size() && (!containsLCat || !containsRandALCat); ++j) { - if (isBidirectionalL(mapped.at(j))) + src = source->data(); + e = src + source->size(); + for (in = src + from; in < e && (!containsLCat || !containsRandALCat); ++in) { + if (isBidirectionalL(*in)) containsLCat = true; - else if (isBidirectionalRorAL(mapped.at(j))) + else if (isBidirectionalRorAL(*in)) containsRandALCat = true; } if (containsRandALCat) { - if (containsLCat || (!isBidirectionalRorAL(mapped.at(0)) - || !isBidirectionalRorAL(mapped.at(mapped.size() - 1)))) - mapped.clear(); + if (containsLCat || (!isBidirectionalRorAL(src[from]) + || !isBidirectionalRorAL(e[-1]))) + source->resize(from); // not allowed, clear the label } +} + +bool qt_check_std3rules(const QChar *uc, int len) +{ + if (len > 63) + return false; - return mapped; + for (int i = 0; i < len; ++i) { + register ushort c = uc[i].unicode(); + if (c == '-' && (i == 0 || i == len - 1)) + return false; + + // verifying the absence of LDH is the same as verifying that + // only LDH is present + if (c == '-' || (c >= '0' && c <= '9') + || (c >= 'A' && c <= 'Z') + || (c >= 'a' && c <= 'z')) + continue; + + return false; + } + + return true; } -static inline char encodeDigit(uint digit) +static inline uint encodeDigit(uint digit) { return digit + 22 + 75 * (digit < 26); } @@ -2977,7 +3010,7 @@ static inline uint adapt(uint delta, uint numpoints, bool firsttime) return k + (((base - tmin + 1) * delta) / (delta + skew)); } -static inline void appendEncode(QByteArray* output, uint& delta, uint& bias, uint& b, uint& h) +static inline void appendEncode(QString* output, uint& delta, uint& bias, uint& b, uint& h) { uint qq; uint k; @@ -2991,17 +3024,17 @@ static inline void appendEncode(QByteArray* output, uint& delta, uint& bias, uin t = (k <= bias) ? tmin : (k >= bias + tmax) ? tmax : k - bias; if (qq < t) break; - *output += encodeDigit(t + (qq - t) % (base - t)); + *output += QChar(encodeDigit(t + (qq - t) % (base - t))); qq = (qq - t) / (base - t); } - *output += encodeDigit(qq); + *output += QChar(encodeDigit(qq)); bias = adapt(delta, h + 1, h == b); delta = 0; ++h; } -static void toPunycodeHelper(const QChar *s, int ucLength, QByteArray *output) +static void toPunycodeHelper(const QChar *s, int ucLength, QString *output) { uint n = initial_n; uint delta = 0; @@ -3010,7 +3043,7 @@ static void toPunycodeHelper(const QChar *s, int ucLength, QByteArray *output) int outLen = output->length(); output->resize(outLen + ucLength); - char *d = output->data() + outLen; + QChar *d = output->data() + outLen; bool skipped = false; // copy all basic code points verbatim to output. for (uint j = 0; j < (uint) ucLength; ++j) { @@ -3035,7 +3068,7 @@ static void toPunycodeHelper(const QChar *s, int ucLength, QByteArray *output) // if basic code points were copied, add the delimiter character. if (h > 0) - *output += 0x2d; + *output += QChar(0x2d); // while there are still unprocessed non-basic code points left in // the input string... @@ -3083,7 +3116,7 @@ static void toPunycodeHelper(const QChar *s, int ucLength, QByteArray *output) } // prepend ACE prefix - output->insert(outLen, "xn--"); + output->insert(outLen, QLatin1String("xn--")); return; } @@ -3144,11 +3177,15 @@ static bool qt_is_idn_enabled(const QString &domain) int idx = domain.lastIndexOf(QLatin1Char('.')); if (idx == -1) return false; - const QChar *tld = domain.constData() + idx + 1; + int len = domain.size() - idx - 1; + QString tldString(domain.constData() + idx + 1, len); + qt_nameprep(&tldString, 0); + + const QChar *tld = tldString.constData(); if (user_idn_whitelist) - return user_idn_whitelist->contains(QString(tld, len)); + return user_idn_whitelist->contains(tldString); int l = 0; int r = sizeof(idn_whitelist)/sizeof(const char *) - 1; @@ -3164,46 +3201,127 @@ static bool qt_is_idn_enabled(const QString &domain) return equal(tld, len, idn_whitelist[i]); } -static QString qt_from_ACE(const QString &domainMC) +static inline bool isDotDelimiter(ushort uc) { - QString domain = domainMC.toLower(); - int idx = domain.indexOf(QLatin1Char('.')); - if (idx != -1) { - if (!domain.contains(QLatin1String("xn--"))) { - bool simple = true; - for (int i = 0; i < domain.size(); ++i) { - ushort ch = domain.at(i).unicode(); - if (ch > 'z' || ch < '-' || ch == '/' || (ch > '9' && ch < 'A') || (ch > 'Z' && ch < 'a')) { + // IDNA / rfc3490 describes these four delimiters used for + // separating labels in unicode international domain + // names. + return uc == 0x2e || uc == 0x3002 || uc == 0xff0e || uc == 0xff61; +} + +static int nextDotDelimiter(const QString &domain, int from = 0) +{ + const QChar *b = domain.unicode(); + const QChar *ch = b + from; + const QChar *e = b + domain.length(); + while (ch < e) { + if (isDotDelimiter(ch->unicode())) + break; + else + ++ch; + } + return ch - b; +} + +enum AceOperation { ToAceOnly, NormalizeAce }; +static QString qt_ACE_do(const QString &domain, AceOperation op) +{ + if (domain.isEmpty()) + return domain; + + QString result; + result.reserve(domain.length()); + + const bool isIdnEnabled = op == NormalizeAce ? qt_is_idn_enabled(domain) : false; + int lastIdx = 0; + QString aceForm; // this variable is here for caching + + while (1) { + int idx = nextDotDelimiter(domain, lastIdx); + int labelLength = idx - lastIdx; + if (labelLength == 0) + return QString(); // two delimiters in a row -- empty label not allowed + + // RFC 3490 says, about the ToASCII operation: + // 3. If the UseSTD3ASCIIRules flag is set, then perform these checks: + // + // (a) Verify the absence of non-LDH ASCII code points; that is, the + // absence of 0..2C, 2E..2F, 3A..40, 5B..60, and 7B..7F. + // + // (b) Verify the absence of leading and trailing hyphen-minus; that + // is, the absence of U+002D at the beginning and end of the + // sequence. + // and: + // 8. Verify that the number of code points is in the range 1 to 63 + // inclusive. + + // copy the label to the destination, which also serves as our scratch area, lowercasing it + int prevLen = result.size(); + bool simple = true; + result.resize(prevLen + labelLength); + { + QChar *out = result.data() + prevLen; + const QChar *in = domain.constData() + lastIdx; + const QChar *e = in + labelLength; + for (; in < e; ++in, ++out) { + register ushort uc = in->unicode(); + if (uc > 0x7f) simple = false; - break; - } + if (uc >= 'A' && uc <= 'Z') + *out = QChar(uc | 0x20); + else + *out = *in; } - if (simple) - return domain; } - - const bool isIdnEnabled = qt_is_idn_enabled(domain); - int lastIdx = 0; - QString result; - while (1) { - // Nameprep the host. If the labels in the hostname are Punycode - // encoded, we decode them immediately, then nameprep them. - QByteArray label; - toPunycodeHelper(domain.constData() + lastIdx, idx - lastIdx, &label); - result += qt_nameprep(isIdnEnabled ? QUrl::fromPunycode(label) : QString::fromLatin1(label)); - lastIdx = idx + 1; - if (lastIdx < domain.size() + 1) - result += QLatin1Char('.'); - else - break; - idx = domain.indexOf(QLatin1Char('.'), lastIdx); - if (idx == -1) - idx = domain.size(); + + if (simple && labelLength > 6) { + // ACE form domains contain only ASCII characters, but we can't consider them simple + // is this an ACE form? + // the shortest valid ACE domain is 6 characters long (U+0080 would be 1, but it's not allowed) + static const ushort acePrefixUtf16[] = { 'x', 'n', '-', '-' }; + if (memcmp(result.constData() + prevLen, acePrefixUtf16, sizeof acePrefixUtf16) == 0) + simple = false; } - return result; - } else { - return qt_nameprep(domain); + + if (simple) { + // fastest case: this is the common case (non IDN-domains) + // so we're done + if (!qt_check_std3rules(result.constData() + prevLen, labelLength)) + return QString(); + } else { + // Punycode encoding and decoding cannot be done in-place + // That means we need one or two temporaries + qt_nameprep(&result, prevLen); + labelLength = result.length() - prevLen; + register int toReserve = labelLength + 4 + 6; // "xn--" plus some extra bytes + if (toReserve > aceForm.capacity()) + aceForm.reserve(toReserve); + toPunycodeHelper(result.constData() + prevLen, result.size() - prevLen, &aceForm); + + // We use resize()+memcpy() here because we're overwriting the data we've copied + if (isIdnEnabled) { + QString tmp = QUrl::fromPunycode(aceForm.toLatin1()); + if (tmp.isEmpty()) + return QString(); // shouldn't happen, since we've just punycode-encoded it + result.resize(prevLen + tmp.size()); + memcpy(result.data() + prevLen, tmp.constData(), tmp.size() * sizeof(QChar)); + } else { + result.resize(prevLen + aceForm.size()); + memcpy(result.data() + prevLen, aceForm.constData(), aceForm.size() * sizeof(QChar)); + } + + if (!qt_check_std3rules(aceForm.constData(), aceForm.size())) + return QString(); + } + + + lastIdx = idx + 1; + if (lastIdx < domain.size() + 1) + result += QLatin1Char('.'); + else + break; } + return result; } @@ -3246,12 +3364,27 @@ QUrlPrivate::QUrlPrivate(const QUrlPrivate ©) QString QUrlPrivate::canonicalHost() const { - if (QURL_HASFLAG(stateFlags, HostCanonicalized)) + if (QURL_HASFLAG(stateFlags, HostCanonicalized) || host.isEmpty()) return host; QUrlPrivate *that = const_cast<QUrlPrivate *>(this); QURL_SETFLAG(that->stateFlags, HostCanonicalized); - that->host = qt_from_ACE(host); + if (host.contains(QLatin1Char(':'))) { + // This is an IP Literal, use _IPLiteral to validate + QByteArray ba = host.toLatin1(); + if (!ba.startsWith('[')) { + // surround the IP Literal with [ ] if it's not already done so + ba.reserve(ba.length() + 2); + ba.prepend('['); + ba.append(']'); + } + + const char *ptr = ba.constData(); + if (!_IPLiteral(&ptr)) + that->host.clear(); + } else { + that->host = qt_ACE_do(host, NormalizeAce); + } return that->host; } @@ -3737,7 +3870,10 @@ QByteArray QUrlPrivate::toEncoded(QUrl::FormattingOptions options) const } } - url += QUrl::toAce(host); + if (host.startsWith(QLatin1Char('['))) + url += host.toLatin1(); + else + url += QUrl::toAce(host); if (!(options & QUrl::RemovePort) && port != -1) { url += ':'; url += QString::number(port).toAscii(); @@ -4412,8 +4548,6 @@ void QUrl::setHost(const QString &host) QURL_UNSETFLAG(d->stateFlags, QUrlPrivate::Validated | QUrlPrivate::Normalized | QUrlPrivate::HostCanonicalized); d->host = host; - if (d->host.contains(QLatin1Char(':'))) - d->host = QLatin1Char('[') + d->host + QLatin1Char(']'); } /*! @@ -5425,9 +5559,9 @@ QByteArray QUrl::toPercentEncoding(const QString &input, const QByteArray &exclu */ QByteArray QUrl::toPunycode(const QString &uc) { - QByteArray output; + QString output; toPunycodeHelper(uc.constData(), uc.size(), &output); - return output; + return output.toLatin1(); } /*! @@ -5528,7 +5662,7 @@ QString QUrl::fromPunycode(const QByteArray &pc) */ QString QUrl::fromAce(const QByteArray &domain) { - return qt_from_ACE(QString::fromLatin1(domain)); + return qt_ACE_do(QString::fromLatin1(domain), NormalizeAce); } /*! @@ -5545,26 +5679,8 @@ QString QUrl::fromAce(const QByteArray &domain) */ QByteArray QUrl::toAce(const QString &domain) { - // IDNA / rfc3490 describes these four delimiters used for - // separating labels in unicode international domain - // names. - QString nameprepped = qt_nameprep(domain); - int lastIdx = 0; - QByteArray result; - for (int i = 0; i < nameprepped.size(); ++i) { - ushort uc = nameprepped.at(i).unicode(); - if (uc == 0x2e || uc == 0x3002 || uc == 0xff0e || uc == 0xff61) { - if (lastIdx) - result += '.'; - toPunycodeHelper(nameprepped.constData() + lastIdx, i - lastIdx, &result); - lastIdx = i + 1; - } - } - if (lastIdx) - result += '.'; - toPunycodeHelper(nameprepped.constData() + lastIdx, nameprepped.size() - lastIdx, &result); - - return result; + QString result = qt_ACE_do(domain, ToAceOnly); + return result.toLatin1(); } /*! diff --git a/src/corelib/kernel/qcore_unix.cpp b/src/corelib/kernel/qcore_unix.cpp index b04abae..c5b0fc7 100644 --- a/src/corelib/kernel/qcore_unix.cpp +++ b/src/corelib/kernel/qcore_unix.cpp @@ -34,7 +34,7 @@ ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. +** contact the sales department at http://www.qtsoftware.com/contact. ** $QT_END_LICENSE$ ** ****************************************************************************/ diff --git a/src/corelib/kernel/qcore_unix_p.h b/src/corelib/kernel/qcore_unix_p.h index 8d43897..dd97841 100644 --- a/src/corelib/kernel/qcore_unix_p.h +++ b/src/corelib/kernel/qcore_unix_p.h @@ -69,10 +69,27 @@ struct sockaddr; -#if defined(Q_OS_LINUX) && defined(O_CLOEXEC) && defined(__GLIBC__) && (__GLIBC__ * 0x100 + __GLIBC_MINOR__) >= 0x0204 +#if defined(Q_OS_LINUX) && defined(__GLIBC__) && (__GLIBC__ * 0x100 + __GLIBC_MINOR__) >= 0x0204 // Linux supports thread-safe FD_CLOEXEC # define QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC 1 +// add defines for the consts for Linux +# ifndef O_CLOEXEC +# define O_CLOEXEC 02000000 +# endif +# ifndef FD_DUPFD_CLOEXEC +# define F_DUPFD_CLOEXEC 1030 +# endif +# ifndef SOCK_CLOEXEC +# define SOCK_CLOEXEC O_CLOEXEC +# endif +# ifndef SOCK_NONBLOCK +# define SOCK_NONBLOCK O_NONBLOCK +# endif +# ifndef MSG_CMSG_CLOEXEC +# define MSG_CMSG_CLOEXEC 0x40000000 +# endif + QT_BEGIN_NAMESPACE namespace QtLibcSupplement { Q_CORE_EXPORT int accept4(int, sockaddr *, QT_SOCKLEN_T *, int flags); diff --git a/src/corelib/kernel/qcoreapplication_win.cpp b/src/corelib/kernel/qcoreapplication_win.cpp index a71f284..bf5716a 100644 --- a/src/corelib/kernel/qcoreapplication_win.cpp +++ b/src/corelib/kernel/qcoreapplication_win.cpp @@ -280,7 +280,7 @@ QT_END_INCLUDE_NAMESPACE // The values below should never change. Note that none of the usual // WM_...FIRST & WM_...LAST values are in the list, as they normally have other // WM_... representations -struct { +struct KnownWM { uint WM; const char* str; } knownWM[] = @@ -582,7 +582,7 @@ struct { { 0,0 }}; // End of known messages // Looks up the WM_ message in the table above -const char* findWMstr(uint msg) +static const char* findWMstr(uint msg) { uint i = 0; const char* result = 0; diff --git a/src/corelib/kernel/qcoreevent.cpp b/src/corelib/kernel/qcoreevent.cpp index 1d70a53..2a317dd 100644 --- a/src/corelib/kernel/qcoreevent.cpp +++ b/src/corelib/kernel/qcoreevent.cpp @@ -219,6 +219,7 @@ QT_BEGIN_NAMESPACE \value WindowStateChange The \l{QWidget::windowState()}{window's state} (minimized, maximized or full-screen) has changed (QWindowStateChangeEvent). \value WindowTitleChange The window title has changed. \value WindowUnblocked The window is unblocked after a modal dialog exited. + \value Wrapped The event is a wrapper for, i.e., contains, another event (QWrappedEvent). \value ZOrderChange The widget's z-order has changed. This event is never sent to top level windows. \value KeyboardLayoutChange The keyboard layout has changed. \value DynamicPropertyChange A dynamic property was added, changed or removed from the object. @@ -267,7 +268,6 @@ QT_BEGIN_NAMESPACE \omitvalue NetworkReplyUpdated \omitvalue FutureCallOut \omitvalue CocoaRequestModal - \omitvalue Wrapped \omitvalue Signal \omitvalue WinGesture */ diff --git a/src/corelib/kernel/qeventdispatcher_unix.cpp b/src/corelib/kernel/qeventdispatcher_unix.cpp index 0eeea04..9deb78f 100644 --- a/src/corelib/kernel/qeventdispatcher_unix.cpp +++ b/src/corelib/kernel/qeventdispatcher_unix.cpp @@ -59,6 +59,10 @@ # include <sys/times.h> #endif +#ifdef Q_OS_MAC +#include <mach/mach_time.h> +#endif + QT_BEGIN_NAMESPACE Q_CORE_EXPORT bool qt_disable_lowpriority_timers=false; @@ -259,7 +263,7 @@ int QEventDispatcherUNIXPrivate::doSelect(QEventLoop::ProcessEventsFlags flags, QTimerInfoList::QTimerInfoList() { -#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) +#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC) useMonotonicTimers = false; # if (_POSIX_MONOTONIC_CLOCK == 0) @@ -287,6 +291,9 @@ QTimerInfoList::QTimerInfoList() msPerTick = 0; } #else +# if defined(Q_OS_MAC) + useMonotonicTimers = true; +# endif // using monotonic timers unconditionally getTime(currentTime); #endif @@ -335,7 +342,19 @@ bool QTimerInfoList::timeChanged(timeval *delta) void QTimerInfoList::getTime(timeval &t) { -#if !defined(QT_NO_CLOCK_MONOTONIC) && !defined(QT_BOOTSTRAPPED) +#if defined(Q_OS_MAC) + { + static mach_timebase_info_data_t info = {0,0}; + if (info.denom == 0) + mach_timebase_info(&info); + + uint64_t cpu_time = mach_absolute_time(); + uint64_t nsecs = cpu_time * (info.numer / info.denom); + t.tv_sec = nsecs * 1e-9; + t.tv_usec = nsecs * 1e-3 - (t.tv_sec * 1e6); + return; + } +#elif !defined(QT_NO_CLOCK_MONOTONIC) && !defined(QT_BOOTSTRAPPED) if (useMonotonicTimers) { timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index a4c4ba2..fc17e00 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -2350,6 +2350,8 @@ QMetaMethod QMetaProperty::notifySignal() const } /*! + \since 4.6 + Returns the index of the property change notifying signal if one was specified, otherwise returns -1. diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index 91266db..bd27ec2 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -171,6 +171,11 @@ QT_BEGIN_NAMESPACE \value QBitmap QBitmap \value QMatrix QMatrix \value QTransform QTransform + \value QMatrix4x4 QMatrix4x4 + \value QVector2D QVector2D + \value QVector3D QVector3D + \value QVector4D QVector4D + \value QQuaternion QQuaternion \value User Base value for user types @@ -272,6 +277,11 @@ static const struct { const char * typeName; int type; } types[] = { {"QTextFormat", QMetaType::QTextFormat}, {"QMatrix", QMetaType::QMatrix}, {"QTransform", QMetaType::QTransform}, + {"QMatrix4x4", QMetaType::QMatrix4x4}, + {"QVector2D", QMetaType::QVector2D}, + {"QVector3D", QMetaType::QVector3D}, + {"QVector4D", QMetaType::QVector4D}, + {"QQuaternion", QMetaType::QQuaternion}, /* All Metatype builtins */ {"void*", QMetaType::VoidStar}, @@ -430,16 +440,15 @@ int QMetaType::registerType(const char *typeName, Destructor destructor, #endif QWriteLocker locker(customTypesLock()); - static int currentIdx = User; int idx = qMetaTypeType_unlocked(normalizedTypeName); if (!idx) { - idx = currentIdx++; - ct->resize(ct->count() + 1); - QCustomTypeInfo &inf = (*ct)[idx - User]; + QCustomTypeInfo inf; inf.typeName = normalizedTypeName; inf.constr = constructor; inf.destr = destructor; + idx = ct->size() + User; + ct->append(inf); } return idx; } @@ -671,6 +680,11 @@ bool QMetaType::save(QDataStream &stream, int type, const void *data) case QMetaType::QTextFormat: case QMetaType::QMatrix: case QMetaType::QTransform: + case QMetaType::QMatrix4x4: + case QMetaType::QVector2D: + case QMetaType::QVector3D: + case QMetaType::QVector4D: + case QMetaType::QQuaternion: if (!qMetaTypeGuiHelper) return false; qMetaTypeGuiHelper[type - FirstGuiType].saveOp(stream, data); @@ -863,6 +877,11 @@ bool QMetaType::load(QDataStream &stream, int type, void *data) case QMetaType::QTextFormat: case QMetaType::QMatrix: case QMetaType::QTransform: + case QMetaType::QMatrix4x4: + case QMetaType::QVector2D: + case QMetaType::QVector3D: + case QMetaType::QVector4D: + case QMetaType::QQuaternion: if (!qMetaTypeGuiHelper) return false; qMetaTypeGuiHelper[type - FirstGuiType].loadOp(stream, data); diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index 497c014..052312c 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -79,7 +79,9 @@ public: QIcon = 69, QImage = 70, QPolygon = 71, QRegion = 72, QBitmap = 73, QCursor = 74, QSizePolicy = 75, QKeySequence = 76, QPen = 77, QTextLength = 78, QTextFormat = 79, QMatrix = 80, QTransform = 81, - LastGuiType = 81 /* QTransform */, + QMatrix4x4 = 82, QVector2D = 83, QVector3D = 84, QVector4D = 85, + QQuaternion = 86, + LastGuiType = 86 /* QQuaternion */, FirstCoreExtType = 128 /* VoidStar */, VoidStar = 128, Long = 129, Short = 130, Char = 131, ULong = 132, @@ -292,6 +294,11 @@ class QTextLength; class QTextFormat; class QMatrix; class QTransform; +class QMatrix4x4; +class QVector2D; +class QVector3D; +class QVector4D; +class QQuaternion; QT_END_NAMESPACE @@ -354,6 +361,11 @@ Q_DECLARE_BUILTIN_METATYPE(QTextLength, QTextLength) Q_DECLARE_BUILTIN_METATYPE(QTextFormat, QTextFormat) Q_DECLARE_BUILTIN_METATYPE(QMatrix, QMatrix) Q_DECLARE_BUILTIN_METATYPE(QTransform, QTransform) +Q_DECLARE_BUILTIN_METATYPE(QMatrix4x4, QMatrix4x4) +Q_DECLARE_BUILTIN_METATYPE(QVector2D, QVector2D) +Q_DECLARE_BUILTIN_METATYPE(QVector3D, QVector3D) +Q_DECLARE_BUILTIN_METATYPE(QVector4D, QVector4D) +Q_DECLARE_BUILTIN_METATYPE(QQuaternion, QQuaternion) QT_END_HEADER diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 8517897..ab91799 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -881,7 +881,7 @@ QObject::~QObject() QObjectPrivate::Connection::~Connection() { if (argumentTypes != &DIRECT_CONNECTION_ONLY) - delete [] argumentTypes; + delete [] static_cast<int *>(argumentTypes); } diff --git a/src/corelib/kernel/qsharedmemory_unix.cpp b/src/corelib/kernel/qsharedmemory_unix.cpp index 04739ff..05369c4 100644 --- a/src/corelib/kernel/qsharedmemory_unix.cpp +++ b/src/corelib/kernel/qsharedmemory_unix.cpp @@ -85,7 +85,7 @@ void QSharedMemoryPrivate::setErrorString(const QString &function) error = QSharedMemory::AlreadyExists; break; case ENOENT: - errorString = QSharedMemory::tr("%1: doesn't exists").arg(function); + errorString = QSharedMemory::tr("%1: doesn't exist").arg(function); error = QSharedMemory::NotFound; break; case EMFILE: @@ -124,7 +124,7 @@ key_t QSharedMemoryPrivate::handle() // ftok requires that an actual file exists somewhere QString fileName = makePlatformSafeKey(key); if (!QFile::exists(fileName)) { - errorString = QSharedMemory::tr("%1: unix key file doesn't exists").arg(QLatin1String("QSharedMemory::handle:")); + errorString = QSharedMemory::tr("%1: UNIX key file doesn't exist").arg(QLatin1String("QSharedMemory::handle:")); error = QSharedMemory::NotFound; return 0; } diff --git a/src/corelib/kernel/qsharedmemory_win.cpp b/src/corelib/kernel/qsharedmemory_win.cpp index c88149a..ae64806 100644 --- a/src/corelib/kernel/qsharedmemory_win.cpp +++ b/src/corelib/kernel/qsharedmemory_win.cpp @@ -71,7 +71,7 @@ void QSharedMemoryPrivate::setErrorString(const QString &function) case ERROR_INVALID_PARAMETER: #endif error = QSharedMemory::NotFound; - errorString = QSharedMemory::tr("%1: doesn't exists").arg(function); + errorString = QSharedMemory::tr("%1: doesn't exist").arg(function); break; case ERROR_COMMITMENT_LIMIT: error = QSharedMemory::InvalidSize; diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 2ef9de4..2b5ea0a 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -1264,6 +1264,7 @@ const QVariant::Handler *QVariant::handler = &qt_kernel_variant_handler; \value Map a QVariantMap \value Matrix a QMatrix \value Transform a QTransform + \value Matrix4x4 a QMatrix4x4 \value Palette a QPalette \value Pen a QPen \value Pixmap a QPixmap @@ -1271,6 +1272,7 @@ const QVariant::Handler *QVariant::handler = &qt_kernel_variant_handler; \value PointArray a QPointArray \value PointF a QPointF \value Polygon a QPolygon + \value Quaternion a QQuaternion \value Rect a QRect \value RectF a QRectF \value RegExp a QRegExp @@ -1286,6 +1288,9 @@ const QVariant::Handler *QVariant::handler = &qt_kernel_variant_handler; \value UInt a \l uint \value ULongLong a \l qulonglong \value Url a QUrl + \value Vector2D a QVector2D + \value Vector3D a QVector3D + \value Vector4D a QVector4D \value UserType Base value for user-defined types. @@ -1677,7 +1682,7 @@ QVariant::QVariant(Qt::GlobalColor color) { create(62, &color); } Note that return values in the ranges QVariant::Char through QVariant::RegExp and QVariant::Font through QVariant::Transform correspond to the values in the ranges QMetaType::QChar through - QMetaType::QRegExp and QMetaType::QFont through QMetaType::QTransform. + QMetaType::QRegExp and QMetaType::QFont through QMetaType::QQuaternion. Pay particular attention when working with char and QChar variants. Note that there is no QVariant constructor specifically diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h index e923844..a68939d 100644 --- a/src/corelib/kernel/qvariant.h +++ b/src/corelib/kernel/qvariant.h @@ -154,7 +154,12 @@ class Q_CORE_EXPORT QVariant TextFormat = 79, Matrix = 80, Transform = 81, - LastGuiType = Transform, + Matrix4x4 = 82, + Vector2D = 83, + Vector3D = 84, + Vector4D = 85, + Quaternion = 86, + LastGuiType = Quaternion, UserType = 127, #ifdef QT3_SUPPORT diff --git a/src/corelib/statemachine/qabstracttransition.cpp b/src/corelib/statemachine/qabstracttransition.cpp index 670aa7d..0004d3e 100644 --- a/src/corelib/statemachine/qabstracttransition.cpp +++ b/src/corelib/statemachine/qabstracttransition.cpp @@ -115,13 +115,10 @@ QAbstractTransitionPrivate *QAbstractTransitionPrivate::get(QAbstractTransition QStateMachine *QAbstractTransitionPrivate::machine() const { - QObject *par = parent; - while (par != 0) { - if (QStateMachine *mach = qobject_cast<QStateMachine*>(par)) - return mach; - par = par->parent(); - } - return 0; + QState *source = sourceState(); + if (!source) + return 0; + return source->machine(); } bool QAbstractTransitionPrivate::callEventTest(QEvent *e) @@ -256,10 +253,6 @@ void QAbstractTransition::setTargetStates(const QList<QAbstractState*> &targets) qWarning("QAbstractTransition::setTargetStates: target state(s) cannot be null"); return; } - if (target->machine() != 0 && target->machine()->rootState() == target) { - qWarning("QAbstractTransition::setTargetStates: root state cannot be target of transition"); - return; - } } d->targetStates.clear(); diff --git a/src/corelib/statemachine/qstate.cpp b/src/corelib/statemachine/qstate.cpp index 83dd869..f74edc3 100644 --- a/src/corelib/statemachine/qstate.cpp +++ b/src/corelib/statemachine/qstate.cpp @@ -71,7 +71,7 @@ QT_BEGIN_NAMESPACE The assignProperty() function is used for defining property assignments that should be performed when a state is entered. - Top-level states must be passed QStateMachine::rootState() as their parent + Top-level states must be passed a QStateMachine object as their parent state, or added to a state machine using QStateMachine::addState(). \section1 States with Child States @@ -242,7 +242,7 @@ void QState::assignProperty(QObject *object, const char *name, /*! Returns this state's error state. - \sa QStateMachine::errorState(), QStateMachine::setErrorState() + \sa QStateMachine::error() */ QAbstractState *QState::errorState() const { @@ -256,19 +256,17 @@ QAbstractState *QState::errorState() const state recursively. If no error state is set for the state itself or any of its ancestors, an error will cause the machine to stop executing and an error will be printed to the console. - - \sa QStateMachine::setErrorState(), QStateMachine::errorState() */ void QState::setErrorState(QAbstractState *state) { Q_D(QState); - if (state != 0 && state->machine() != machine()) { - qWarning("QState::setErrorState: error state cannot belong " - "to a different state machine"); + if (state != 0 && qobject_cast<QStateMachine*>(state)) { + qWarning("QStateMachine::setErrorState: root state cannot be error state"); return; } - if (state != 0 && state->machine() != 0 && state->machine()->rootState() == state) { - qWarning("QStateMachine::setErrorState: root state cannot be error state"); + if (state != 0 && (!state->machine() || ((state->machine() != machine()) && !qobject_cast<QStateMachine*>(this)))) { + qWarning("QState::setErrorState: error state cannot belong " + "to a different state machine"); return; } @@ -288,12 +286,7 @@ QAbstractTransition *QState::addTransition(QAbstractTransition *transition) return 0; } - // machine() will always be non-null for root state - if (machine() != 0 && machine()->rootState() == this) { - qWarning("QState::addTransition: cannot add transition from root state"); - return 0; - } - + transition->setParent(this); const QList<QPointer<QAbstractState> > &targets = QAbstractTransitionPrivate::get(transition)->targetStates; for (int i = 0; i < targets.size(); ++i) { QAbstractState *t = targets.at(i); @@ -308,7 +301,6 @@ QAbstractTransition *QState::addTransition(QAbstractTransition *transition) return 0; } } - transition->setParent(this); if (machine() != 0 && machine()->configuration().contains(this)) QStateMachinePrivate::get(machine())->registerTransitions(this); return transition; diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index bf3ee31..5402b04 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -102,14 +102,9 @@ QT_BEGIN_NAMESPACE Framework}{overview} gives several state graphs and the code to build them. - The rootState() is the parent of all top-level states in the - machine; it is used, for instance, when the state graph is - deleted. It is created by the machine. - - Use the addState() function to add a state to the state machine. - All top-level states are added to the root state. States are - removed with the removeState() function. Removing states while the - machine is running is discouraged. + Use the addState() function to add a top-level state to the state machine. + States are removed with the removeState() function. Removing states while + the machine is running is discouraged. Before the machine can be started, the \l{initialState}{initial state} must be set. The initial state is the state that the @@ -179,26 +174,6 @@ This is */ /*! - \property QStateMachine::rootState - - \brief the root state of this state machine -*/ - -/*! - \property QStateMachine::initialState - - \brief the initial state of this state machine - - The initial state must be one of the rootState()'s child states. -*/ - -/*! - \property QStateMachine::errorState - - \brief the error state of this state machine -*/ - -/*! \property QStateMachine::errorString \brief the error string of this state machine @@ -235,7 +210,6 @@ QStateMachinePrivate::QStateMachinePrivate() stop = false; error = QStateMachine::NoError; globalRestorePolicy = QStateMachine::DoNotRestoreProperties; - rootState = 0; signalEventGenerator = 0; #ifndef QT_NO_ANIMATION animationsEnabled = true; @@ -255,6 +229,11 @@ QStateMachinePrivate *QStateMachinePrivate::get(QStateMachine *q) return 0; } +QState *QStateMachinePrivate::rootState() const +{ + return const_cast<QStateMachine*>(q_func()); +} + static QEvent *cloneEvent(QEvent *e) { switch (e->type()) { @@ -302,7 +281,9 @@ bool QStateMachinePrivate::stateEntryLessThan(QAbstractState *s1, QAbstractState } else if (isDescendantOf(s2, s1)) { return true; } else { - QState *lca = findLCA(QList<QAbstractState*>() << s1 << s2); + Q_ASSERT(s1->machine() != 0); + QStateMachinePrivate *mach = QStateMachinePrivate::get(s1->machine()); + QState *lca = mach->findLCA(QList<QAbstractState*>() << s1 << s2); Q_ASSERT(lca != 0); return (indexOfDescendant(lca, s1) < indexOfDescendant(lca, s2)); } @@ -318,17 +299,19 @@ bool QStateMachinePrivate::stateExitLessThan(QAbstractState *s1, QAbstractState } else if (isDescendantOf(s2, s1)) { return false; } else { - QState *lca = findLCA(QList<QAbstractState*>() << s1 << s2); + Q_ASSERT(s1->machine() != 0); + QStateMachinePrivate *mach = QStateMachinePrivate::get(s1->machine()); + QState *lca = mach->findLCA(QList<QAbstractState*>() << s1 << s2); Q_ASSERT(lca != 0); return (indexOfDescendant(lca, s1) < indexOfDescendant(lca, s2)); } } -QState *QStateMachinePrivate::findLCA(const QList<QAbstractState*> &states) +QState *QStateMachinePrivate::findLCA(const QList<QAbstractState*> &states) const { if (states.isEmpty()) return 0; - QList<QState*> ancestors = properAncestors(states.at(0), 0); + QList<QState*> ancestors = properAncestors(states.at(0), rootState()->parentState()); for (int i = 0; i < ancestors.size(); ++i) { QState *anc = ancestors.at(i); bool ok = true; @@ -376,7 +359,7 @@ QSet<QAbstractTransition*> QStateMachinePrivate::selectTransitions(QEvent *event continue; if (isPreempted(state, enabledTransitions)) continue; - QList<QState*> lst = properAncestors(state, 0); + QList<QState*> lst = properAncestors(state, rootState()->parentState()); if (QState *grp = qobject_cast<QState*>(state)) lst.prepend(grp); bool found = false; @@ -557,11 +540,13 @@ QList<QAbstractState*> QStateMachinePrivate::enterStates(QEvent *event, const QL if (isFinal(s)) { QState *parent = s->parentState(); if (parent) { - QState *grandparent = parent->parentState(); + if (parent != rootState()) { #ifdef QSTATEMACHINE_DEBUG - qDebug() << q << ": emitting finished signal for" << parent; + qDebug() << q << ": emitting finished signal for" << parent; #endif - QStatePrivate::get(parent)->emitFinished(); + QStatePrivate::get(parent)->emitFinished(); + } + QState *grandparent = parent->parentState(); if (grandparent && isParallel(grandparent)) { bool allChildStatesFinal = true; QList<QAbstractState*> childStates = QStatePrivate::get(grandparent)->childStates(); @@ -572,7 +557,7 @@ QList<QAbstractState*> QStateMachinePrivate::enterStates(QEvent *event, const QL break; } } - if (allChildStatesFinal) { + if (allChildStatesFinal && (grandparent != rootState())) { #ifdef QSTATEMACHINE_DEBUG qDebug() << q << ": emitting finished signal for" << grandparent; #endif @@ -585,7 +570,7 @@ QList<QAbstractState*> QStateMachinePrivate::enterStates(QEvent *event, const QL { QSet<QAbstractState*>::const_iterator it; for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) { - if (isFinal(*it) && (*it)->parentState() == rootState) { + if (isFinal(*it) && (*it)->parentState() == rootState()) { processing = false; stopProcessingReason = Finished; break; @@ -630,6 +615,11 @@ void QStateMachinePrivate::addStatesToEnter(QAbstractState *s, QState *root, } } } else { + if (s == rootState()) { + // Error has already been set by exitStates(). + Q_ASSERT(error != QStateMachine::NoError); + return; + } statesToEnter.insert(s); if (isParallel(s)) { QState *grp = qobject_cast<QState*>(s); @@ -643,6 +633,7 @@ void QStateMachinePrivate::addStatesToEnter(QAbstractState *s, QState *root, QState *grp = qobject_cast<QState*>(s); QAbstractState *initial = grp->initialState(); if (initial != 0) { + Q_ASSERT(initial->machine() == q_func()); addStatesToEnter(initial, grp, statesToEnter, statesForDefaultEntry); } else { setError(QStateMachine::NoInitialStateError, grp); @@ -873,20 +864,26 @@ bool QStateMachinePrivate::isParallel(const QAbstractState *s) return ss && (QStatePrivate::get(ss)->childMode == QState::ParallelStates); } -bool QStateMachinePrivate::isCompound(const QAbstractState *s) +bool QStateMachinePrivate::isCompound(const QAbstractState *s) const { const QState *group = qobject_cast<const QState*>(s); if (!group) return false; + bool isMachine = (qobject_cast<const QStateMachine*>(group) != 0); + // Don't treat the machine as compound if it's a sub-state of this machine + if (isMachine && (group != rootState())) + return false; return (!isParallel(group) && !QStatePrivate::get(group)->childStates().isEmpty()) - || (qobject_cast<QStateMachine*>(group->parent()) != 0); + || isMachine; } -bool QStateMachinePrivate::isAtomic(const QAbstractState *s) +bool QStateMachinePrivate::isAtomic(const QAbstractState *s) const { const QState *ss = qobject_cast<const QState*>(s); return (ss && QStatePrivate::get(ss)->childStates().isEmpty()) - || isFinal(s); + || isFinal(s) + // Treat the machine as atomic if it's a sub-state of this machine + || (ss && (qobject_cast<const QStateMachine*>(ss) != 0) && (ss != rootState())); } @@ -1034,7 +1031,7 @@ void QStateMachinePrivate::setError(QStateMachine::Error errorCode, QAbstractSta if (currentContext == currentErrorState) currentErrorState = 0; - Q_ASSERT(currentErrorState != rootState); + Q_ASSERT(currentErrorState != rootState()); if (currentErrorState != 0) { QState *lca = findLCA(QList<QAbstractState*>() << currentErrorState << currentContext); @@ -1141,11 +1138,8 @@ void QStateMachinePrivate::_q_start() { Q_Q(QStateMachine); Q_ASSERT(state == Starting); - if (!rootState) { - state = NotRunning; - return; - } - QAbstractState *initial = rootState->initialState(); + Q_ASSERT(rootState() != 0); + QAbstractState *initial = rootState()->initialState(); configuration.clear(); qDeleteAll(internalEventQueue); internalEventQueue.clear(); @@ -1159,7 +1153,7 @@ void QStateMachinePrivate::_q_start() processingScheduled = true; // we call _q_process() below emit q->started(); - StartState *start = new StartState(rootState); + StartState *start = new StartState(rootState()); QAbstractTransition *initialTransition = new InitialTransition(initial); start->addTransition(initialTransition); QList<QAbstractTransition*> transitions; @@ -1371,15 +1365,22 @@ void QStateMachinePrivate::unregisterSignalTransition(QSignalTransition *transit void QStateMachinePrivate::unregisterAllTransitions() { + Q_Q(QStateMachine); { - QList<QSignalTransition*> transitions = qFindChildren<QSignalTransition*>(rootState); - for (int i = 0; i < transitions.size(); ++i) - unregisterSignalTransition(transitions.at(i)); + QList<QSignalTransition*> transitions = qFindChildren<QSignalTransition*>(rootState()); + for (int i = 0; i < transitions.size(); ++i) { + QSignalTransition *t = transitions.at(i); + if (t->machine() == q) + unregisterSignalTransition(t); + } } { - QList<QEventTransition*> transitions = qFindChildren<QEventTransition*>(rootState); - for (int i = 0; i < transitions.size(); ++i) - unregisterEventTransition(transitions.at(i)); + QList<QEventTransition*> transitions = qFindChildren<QEventTransition*>(rootState()); + for (int i = 0; i < transitions.size(); ++i) { + QEventTransition *t = transitions.at(i); + if (t->machine() == q) + unregisterEventTransition(t); + } } } @@ -1457,16 +1458,20 @@ void QStateMachinePrivate::handleTransitionSignal(const QObject *sender, int sig Constructs a new state machine with the given \a parent. */ QStateMachine::QStateMachine(QObject *parent) - : QObject(*new QStateMachinePrivate, parent) + : QState(*new QStateMachinePrivate, /*parentState=*/0) { + // Can't pass the parent to the QState constructor, as it expects a QState + // But this works as expected regardless of whether parent is a QState or not + setParent(parent); } /*! \internal */ QStateMachine::QStateMachine(QStateMachinePrivate &dd, QObject *parent) - : QObject(dd, parent) + : QState(dd, /*parentState=*/0) { + setParent(parent); } /*! @@ -1476,69 +1481,6 @@ QStateMachine::~QStateMachine() { } -namespace { - -class RootState : public QState -{ -public: - RootState(QState *parent) - : QState(parent) - { - } - - void onEntry(QEvent *) {} - void onExit(QEvent *) {} -}; - -} // namespace - -/*! - Returns this state machine's root state. -*/ -QState *QStateMachine::rootState() const -{ - Q_D(const QStateMachine); - if (!d->rootState) { - const_cast<QStateMachinePrivate*>(d)->rootState = new RootState(0); - d->rootState->setParent(const_cast<QStateMachine*>(this)); - } - return d->rootState; -} - -/*! - Returns the error state of the state machine's root state. - - \sa QState::errorState() -*/ -QAbstractState *QStateMachine::errorState() const -{ - return rootState()->errorState(); -} - -/*! - Sets the error state of this state machine's root state to be \a state. When a running state - machine encounters an error which puts it in an undefined state, it will enter an error state - based on the context of the error that occurred. It will enter this state regardless of what - is currently in the event queue. - - If the erroneous state has an error state set, this will be entered by the machine. If no error - state has been set, the state machine will search the parent hierarchy recursively for an - error state. The error state of the root state can thus be seen as a global error state that - applies for all states for which a more specific error state has not been set. - - Before entering the error state, the state machine will set the error code returned by error() and - error message returned by errorString(). - - If there is no error state available for the erroneous state, the state machine will print a - warning message on the console and stop executing. - - \sa QState::setErrorState(), rootState() -*/ -void QStateMachine::setErrorState(QAbstractState *state) -{ - rootState()->setErrorState(state); -} - /*! \enum QStateMachine::Error This enum type defines errors that can occur in the state machine at run time. When the state @@ -1640,39 +1582,13 @@ void QStateMachine::setGlobalRestorePolicy(QStateMachine::RestorePolicy restoreP } /*! - Returns this state machine's initial state, or 0 if no initial state has - been set. -*/ -QAbstractState *QStateMachine::initialState() const -{ - Q_D(const QStateMachine); - if (!d->rootState) - return 0; - return d->rootState->initialState(); -} - -/*! - Sets this state machine's initial \a state. -*/ -void QStateMachine::setInitialState(QAbstractState *state) -{ - Q_D(QStateMachine); - if (!d->rootState) { - if (!state) - return; - rootState()->setInitialState(state); - } - d->rootState->setInitialState(state); -} - -/*! Adds the given \a state to this state machine. The state becomes a top-level - state (i.e. a child of the rootState()). + state. If the state is already in a different machine, it will first be removed from its old machine, and then added to this machine. - \sa removeState(), rootState(), setInitialState() + \sa removeState(), setInitialState() */ void QStateMachine::addState(QAbstractState *state) { @@ -1684,7 +1600,7 @@ void QStateMachine::addState(QAbstractState *state) qWarning("QStateMachine::addState: state has already been added to this machine"); return; } - state->setParent(rootState()); + state->setParent(this); } /*! @@ -1730,7 +1646,7 @@ void QStateMachine::start() { Q_D(QStateMachine); - if (rootState()->initialState() == 0) { + if (initialState() == 0) { qWarning("QStateMachine::start: No initial state set for machine. Refusing to start."); return; } @@ -1821,7 +1737,7 @@ void QStateMachine::postInternalEvent(QEvent *event) Returns the maximal consistent set of states (including parallel and final states) that this state machine is currently in. If a state \c s is in the configuration, it is always the case that the parent of \c s is also in - c. Note, however, that the rootState() is not an explicit member of the + c. Note, however, that the machine itself is not an explicit member of the configuration. */ QSet<QAbstractState*> QStateMachine::configuration() const @@ -1840,15 +1756,6 @@ QSet<QAbstractState*> QStateMachine::configuration() const */ /*! - \fn QStateMachine::finished() - - This signal is emitted when the state machine has reached a top-level final - state (QFinalState). - - \sa QStateMachine::started() -*/ - -/*! \fn QStateMachine::stopped() This signal is emitted when the state machine has stopped. @@ -1872,14 +1779,6 @@ bool QStateMachine::event(QEvent *e) d->scheduleProcess(); return true; } - } else if (e->type() == QEvent::ChildAdded) { - QChildEvent *ce = static_cast<QChildEvent*>(e); - if (QAbstractState *state = qobject_cast<QAbstractState*>(ce->child())) { - if (state != rootState()) { - state->setParent(rootState()); - return true; - } - } } return QObject::event(e); } @@ -1949,6 +1848,24 @@ void QStateMachine::endMicrostep(QEvent *event) Q_UNUSED(event); } +/*! + \reimp +*/ +void QStateMachine::onEntry(QEvent *event) +{ + start(); + QState::onEntry(event); +} + +/*! + \reimp +*/ +void QStateMachine::onExit(QEvent *event) +{ + stop(); + QState::onExit(event); +} + #ifndef QT_NO_ANIMATION /*! @@ -2155,6 +2072,8 @@ QSignalEvent::~QSignalEvent() Constructs a new QWrappedEvent object with the given \a object and \a event. + + The QWrappedEvent object takes ownership of \a event. */ QWrappedEvent::QWrappedEvent(QObject *object, QEvent *event) : QEvent(QEvent::Wrapped), m_object(object), m_event(event) @@ -2166,6 +2085,7 @@ QWrappedEvent::QWrappedEvent(QObject *object, QEvent *event) */ QWrappedEvent::~QWrappedEvent() { + delete m_event; } /*! diff --git a/src/corelib/statemachine/qstatemachine.h b/src/corelib/statemachine/qstatemachine.h index 30d0e3a..230d852 100644 --- a/src/corelib/statemachine/qstatemachine.h +++ b/src/corelib/statemachine/qstatemachine.h @@ -42,7 +42,7 @@ #ifndef QSTATEMACHINE_H #define QSTATEMACHINE_H -#include <QtCore/qabstractstate.h> +#include <QtCore/qstate.h> #include <QtCore/qlist.h> #include <QtCore/qobject.h> @@ -57,18 +57,12 @@ QT_MODULE(Core) #ifndef QT_NO_STATEMACHINE class QEvent; -class QAbstractState; -class QState; class QStateMachinePrivate; class QAbstractAnimation; -class QAbstractState; -class Q_CORE_EXPORT QStateMachine : public QObject +class Q_CORE_EXPORT QStateMachine : public QState { Q_OBJECT - Q_PROPERTY(QState* rootState READ rootState) - Q_PROPERTY(QAbstractState* initialState READ initialState WRITE setInitialState) - Q_PROPERTY(QAbstractState* errorState READ errorState WRITE setErrorState) Q_PROPERTY(QString errorString READ errorString) Q_PROPERTY(RestorePolicy globalRestorePolicy READ globalRestorePolicy WRITE setGlobalRestorePolicy) Q_ENUMS(RestorePolicy) @@ -94,14 +88,6 @@ public: void addState(QAbstractState *state); void removeState(QAbstractState *state); - QState *rootState() const; - - QAbstractState *initialState() const; - void setInitialState(QAbstractState *state); - - QAbstractState *errorState() const; - void setErrorState(QAbstractState *state); - Error error() const; QString errorString() const; void clearError(); @@ -135,9 +121,11 @@ public Q_SLOTS: Q_SIGNALS: void started(); void stopped(); - void finished(); protected: + void onEntry(QEvent *event); + void onExit(QEvent *event); + void postInternalEvent(QEvent *event); virtual void beginSelectTransitions(QEvent *event); diff --git a/src/corelib/statemachine/qstatemachine_p.h b/src/corelib/statemachine/qstatemachine_p.h index 1335b93..21e405d 100644 --- a/src/corelib/statemachine/qstatemachine_p.h +++ b/src/corelib/statemachine/qstatemachine_p.h @@ -53,7 +53,8 @@ // We mean it. // -#include <private/qobject_p.h> +#include "private/qstate_p.h" + #include <QtCore/qcoreevent.h> #include <QtCore/qhash.h> #include <QtCore/qlist.h> @@ -61,9 +62,6 @@ #include <QtCore/qset.h> #include <QtCore/qvector.h> -#include "qstate.h" -#include "private/qstate_p.h" - QT_BEGIN_NAMESPACE class QEvent; @@ -81,7 +79,7 @@ class QAbstractAnimation; #endif class QStateMachine; -class QStateMachinePrivate : public QObjectPrivate +class QStateMachinePrivate : public QStatePrivate { Q_DECLARE_PUBLIC(QStateMachine) public: @@ -101,7 +99,7 @@ public: static QStateMachinePrivate *get(QStateMachine *q); - static QState *findLCA(const QList<QAbstractState*> &states); + QState *findLCA(const QList<QAbstractState*> &states) const; static bool stateEntryLessThan(QAbstractState *s1, QAbstractState *s2); static bool stateExitLessThan(QAbstractState *s1, QAbstractState *s2); @@ -116,6 +114,8 @@ public: void _q_animationFinished(); #endif + QState *rootState() const; + void microstep(QEvent *event, const QList<QAbstractTransition*> &transitionList); bool isPreempted(const QAbstractState *s, const QSet<QAbstractTransition*> &transitions) const; QSet<QAbstractTransition*> selectTransitions(QEvent *event) const; @@ -133,8 +133,8 @@ public: bool isInFinalState(QAbstractState *s) const; static bool isFinal(const QAbstractState *s); static bool isParallel(const QAbstractState *s); - static bool isCompound(const QAbstractState *s); - static bool isAtomic(const QAbstractState *s); + bool isCompound(const QAbstractState *s) const; + bool isAtomic(const QAbstractState *s) const; static bool isDescendantOf(const QAbstractState *s, const QAbstractState *other); static QList<QState*> properAncestors(const QAbstractState *s, const QState *upperBound); @@ -164,7 +164,6 @@ public: bool processingScheduled; bool stop; StopProcessingReason stopProcessingReason; - QState *rootState; QSet<QAbstractState*> configuration; QList<QEvent*> internalEventQueue; QList<QEvent*> externalEventQueue; diff --git a/src/corelib/thread/qreadwritelock.h b/src/corelib/thread/qreadwritelock.h index 51d42b5..4742bea 100644 --- a/src/corelib/thread/qreadwritelock.h +++ b/src/corelib/thread/qreadwritelock.h @@ -190,7 +190,8 @@ inline QWriteLocker::QWriteLocker(QReadWriteLock *areadWriteLock) class Q_CORE_EXPORT QReadWriteLock { public: - inline explicit QReadWriteLock() { } + enum RecursionMode { NonRecursive, Recursive }; + inline explicit QReadWriteLock(RecursionMode = NonRecursive) { } inline ~QReadWriteLock() { } static inline void lockForRead() { } diff --git a/src/corelib/tools/qbytedata_p.h b/src/corelib/tools/qbytedata_p.h new file mode 100644 index 0000000..cc10ea2 --- /dev/null +++ b/src/corelib/tools/qbytedata_p.h @@ -0,0 +1,203 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QBYTEDATA_H +#define QBYTEDATA_H + +#include <qbytearray.h> + + +QT_BEGIN_NAMESPACE + +// this class handles a list of QByteArrays. It is a variant of QRingBuffer +// that avoid malloc/realloc/memcpy. +class QByteDataBuffer +{ +private: + QList<QByteArray> buffers; + qint64 bufferCompleteSize; +public: + QByteDataBuffer() : bufferCompleteSize(0) + { + } + + ~QByteDataBuffer() + { + clear(); + } + + inline void append(QByteDataBuffer& other) + { + if (other.isEmpty()) + return; + + buffers.append(other.buffers); + bufferCompleteSize += other.byteAmount(); + } + + + inline void append(QByteArray& bd) + { + if (bd.isEmpty()) + return; + + buffers.append(bd); + bufferCompleteSize += bd.size(); + } + + inline void prepend(QByteArray& bd) + { + if (bd.isEmpty()) + return; + + buffers.prepend(bd); + bufferCompleteSize += bd.size(); + } + + // return the first QByteData. User of this function has to qFree() its .data! + // preferably use this function to read data. + inline QByteArray read() + { + bufferCompleteSize -= buffers.first().size(); + return buffers.takeFirst(); + } + + // return everything. User of this function has to qFree() its .data! + // avoid to use this, it might malloc and memcpy. + inline QByteArray readAll() + { + return read(byteAmount()); + } + + // return amount. User of this function has to qFree() its .data! + // avoid to use this, it might malloc and memcpy. + inline QByteArray read(qint64 amount) + { + amount = qMin(byteAmount(), amount); + QByteArray byteData; + byteData.resize(amount); + read(byteData.data(), byteData.size()); + return byteData; + } + + // return amount bytes. User of this function has to qFree() its .data! + // avoid to use this, it will memcpy. + qint64 read(char* dst, qint64 amount) + { + amount = qMin(amount, byteAmount()); + qint64 originalAmount = amount; + char *writeDst = dst; + + while (amount > 0) { + QByteArray first = buffers.takeFirst(); + if (amount >= first.size()) { + // take it completely + bufferCompleteSize -= first.size(); + amount -= first.size(); + memcpy(writeDst, first.constData(), first.size()); + writeDst += first.size(); + first.clear(); + } else { + // take a part of it & it is the last one to take + bufferCompleteSize -= amount; + memcpy(writeDst, first.constData(), amount); + + qint64 newFirstSize = first.size() - amount; + QByteArray newFirstData; + newFirstData.resize(newFirstSize); + memcpy(newFirstData.data(), first.constData() + amount, newFirstSize); + buffers.prepend(newFirstData); + + amount = 0; + first.clear(); + } + } + + return originalAmount; + } + + inline char getChar() + { + char c; + read(&c, 1); + return c; + } + + inline void clear() + { + buffers.clear(); + bufferCompleteSize = 0; + } + + // The byte count of all QByteArrays + inline qint64 byteAmount() const + { + return bufferCompleteSize; + } + + // the number of QByteArrays + inline qint64 bufferCount() const + { + return buffers.length(); + } + + inline bool isEmpty() const + { + return byteAmount() == 0; + } + + inline qint64 sizeNextBlock() const + { + if(buffers.isEmpty()) + return 0; + else + return buffers.first().size(); + } + + inline QByteArray& operator[](int i) + { + return buffers[i]; + } +}; + +QT_END_NAMESPACE + +#endif // QBYTEDATA_H diff --git a/src/corelib/tools/qchar.cpp b/src/corelib/tools/qchar.cpp index 88053d6..458a383 100644 --- a/src/corelib/tools/qchar.cpp +++ b/src/corelib/tools/qchar.cpp @@ -1421,16 +1421,15 @@ QDataStream &operator>>(QDataStream &in, QChar &chr) // --------------------------------------------------------------------------- -static QString decomposeHelper - (const QString &str, bool canonical, QChar::UnicodeVersion version) +static void decomposeHelper(QString *str, bool canonical, QChar::UnicodeVersion version, int from) { unsigned short buffer[3]; - QString s = str; + QString &s = *str; - const unsigned short *utf16 = s.utf16(); + const unsigned short *utf16 = reinterpret_cast<unsigned short *>(s.data()); const unsigned short *uc = utf16 + s.length(); - while (uc != utf16) { + while (uc != utf16 + from) { uint ucs4 = *(--uc); if (QChar(ucs4).isLowSurrogate() && uc != utf16) { ushort high = *(uc - 1); @@ -1450,11 +1449,9 @@ static QString decomposeHelper s.replace(uc - utf16, ucs4 > 0x10000 ? 2 : 1, (const QChar *)d, length); // since the insert invalidates the pointers and we do decomposition recursive int pos = uc - utf16; - utf16 = s.utf16(); + utf16 = reinterpret_cast<unsigned short *>(s.data()); uc = utf16 + pos + length; } - - return s; } @@ -1489,21 +1486,21 @@ static ushort ligatureHelper(ushort u1, ushort u2) return 0; } -static QString composeHelper(const QString &str) +static void composeHelper(QString *str, int from) { - QString s = str; + QString &s = *str; - if (s.length() < 2) - return s; + if (s.length() - from < 2) + return; // the loop can partly ignore high Unicode as all ligatures are in the BMP int starter = 0; int lastCombining = 0; - int pos = 0; + int pos = from; while (pos < s.length()) { - uint uc = s.utf16()[pos]; + uint uc = s.at(pos).unicode(); if (QChar(uc).isHighSurrogate() && pos < s.length()-1) { - ushort low = s.utf16()[pos+1]; + ushort low = s.at(pos+1).unicode(); if (QChar(low).isLowSurrogate()) { uc = QChar::surrogateToUcs4(uc, low); ++pos; @@ -1512,7 +1509,7 @@ static QString composeHelper(const QString &str) int combining = QChar::combiningClass(uc); if (starter == pos - 1 || combining > lastCombining) { // allowed to form ligature with S - QChar ligature = ligatureHelper(s.utf16()[starter], uc); + QChar ligature = ligatureHelper(s.at(starter).unicode(), uc); if (ligature.unicode()) { s[starter] = ligature; s.remove(pos, 1); @@ -1524,16 +1521,14 @@ static QString composeHelper(const QString &str) lastCombining = combining; ++pos; } - return s; } -static QString canonicalOrderHelper - (const QString &str, QChar::UnicodeVersion version) +static void canonicalOrderHelper(QString *str, QChar::UnicodeVersion version, int from) { - QString s = str; + QString &s = *str; const int l = s.length()-1; - int pos = 0; + int pos = from; while (pos < l) { int p2 = pos+1; uint u1 = s.at(pos).unicode(); @@ -1593,7 +1588,6 @@ static QString canonicalOrderHelper ++pos; } } - return s; } int QT_FASTCALL QUnicodeTables::script(unsigned int uc) diff --git a/src/corelib/tools/qcontiguouscache.cpp b/src/corelib/tools/qcontiguouscache.cpp index e738ec8..f42b7a0 100644 --- a/src/corelib/tools/qcontiguouscache.cpp +++ b/src/corelib/tools/qcontiguouscache.cpp @@ -61,6 +61,7 @@ void QContiguousCacheData::dump() const \ingroup tools \ingroup shared \reentrant + \since 4.6 The QContiguousCache class provides an efficient way of caching items for display in a user interface view. Unlike QCache, it adds a restriction @@ -95,7 +96,7 @@ MyRecord record(int row) const in the case where the requested row is a long way from the currently cached items. If there is a gap between where the new item is inserted and the currently cached items then the existing cached items are first removed to retain - the contiguous nature of the cache. Hence it is important to take some care then + the contiguous nature of the cache. Hence it is important to take some care then when using insert() in order to avoid unwanted clearing of the cache. The range of valid indexes for the QContiguousCache class are from @@ -104,9 +105,9 @@ MyRecord record(int row) const than INT_MAX can result in the indexes of the cache being invalid. When the cache indexes are invalid it is important to call normalizeIndexes() before calling any of containsIndex(), firstIndex(), - lastIndex(), at() or the [] operator. Calling these - functions when the cache has invalid indexes will result in undefined - behavior. The indexes can be checked by using areIndexesValid() + lastIndex(), at() or \l{QContiguousCache::operator[]()}{operator[]()}. + Calling these functions when the cache has invalid indexes will result in + undefined behavior. The indexes can be checked by using areIndexesValid() In most cases the indexes will not exceed 0 to INT_MAX, and normalizeIndexes() will not need to be used. @@ -190,8 +191,6 @@ MyRecord record(int row) const /*! \fn int QContiguousCache::count() const - \overload - Same as size(). */ @@ -258,14 +257,15 @@ MyRecord record(int row) const /*! \fn T &QContiguousCache::operator[](int i) - Returns the item at index position \a i as a modifiable reference. If + Returns the item at index position \a i as a modifiable reference. If the cache does not contain an item at the given index position \a i then it will first insert an empty item at that position. In most cases it is better to use either at() or insert(). - Note that using non-const operators can cause QContiguousCache to do a deep - copy. + \note This non-const overload of operator[] requires QContiguousCache + to make a deep copy. Use at() for read-only access to a non-const + QContiguousCache. \sa insert(), at() */ diff --git a/src/corelib/tools/qcontiguouscache.h b/src/corelib/tools/qcontiguouscache.h index 7d52f1e..0020d22 100644 --- a/src/corelib/tools/qcontiguouscache.h +++ b/src/corelib/tools/qcontiguouscache.h @@ -166,8 +166,8 @@ void QContiguousCache<T>::detach_helper() T *dest = x.d->array + x.d->start; T *src = d->array + d->start; - int count = x.d->count; - while (count--) { + int oldcount = x.d->count; + while (oldcount--) { if (QTypeInfo<T>::isComplex) { new (dest) T(*src); } else { @@ -200,8 +200,8 @@ void QContiguousCache<T>::setCapacity(int asize) x.d->start = x.d->offset % x.d->alloc; T *dest = x.d->array + (x.d->start + x.d->count-1) % x.d->alloc; T *src = d->array + (d->start + d->count-1) % d->alloc; - int count = x.d->count; - while (count--) { + int oldcount = x.d->count; + while (oldcount--) { if (QTypeInfo<T>::isComplex) { new (dest) T(*src); } else { @@ -224,10 +224,10 @@ void QContiguousCache<T>::clear() { if (d->ref == 1) { if (QTypeInfo<T>::isComplex) { - int count = d->count; + int oldcount = d->count; T * i = d->array + d->start; T * e = d->array + d->alloc; - while (count--) { + while (oldcount--) { i->~T(); i++; if (i == e) @@ -254,11 +254,11 @@ inline QContiguousCacheData *QContiguousCache<T>::malloc(int aalloc) } template <typename T> -QContiguousCache<T>::QContiguousCache(int capacity) +QContiguousCache<T>::QContiguousCache(int cap) { - p = malloc(capacity); + p = malloc(cap); d->ref = 1; - d->alloc = capacity; + d->alloc = cap; d->count = d->start = d->offset = 0; d->sharable = true; } @@ -295,10 +295,10 @@ template <typename T> void QContiguousCache<T>::free(Data *x) { if (QTypeInfo<T>::isComplex) { - int count = d->count; + int oldcount = d->count; T * i = d->array + d->start; T * e = d->array + d->alloc; - while (count--) { + while (oldcount--) { i->~T(); i++; if (i == e) diff --git a/src/corelib/tools/qeasingcurve.cpp b/src/corelib/tools/qeasingcurve.cpp index 18a252a..0828c61 100644 --- a/src/corelib/tools/qeasingcurve.cpp +++ b/src/corelib/tools/qeasingcurve.cpp @@ -60,8 +60,10 @@ Easing curves describe a function that controls how the speed of the interpolation between 0 and 1 should be. Easing curves allow transitions from one value to another to appear more natural than a simple constant speed would allow. - The QEasingCurve class is usually used in conjunction with the QAnimation class, - but can be used on its own. + The QEasingCurve class is usually used in conjunction with the QVariantAnimation and + QPropertyAnimation classes but can be used on its own. It is usually used to accelerate + the interpolation from zero velocity (ease in) or decelerate to zero velocity (ease out). + Ease in and ease out can also be combined in the same easing curve. To calculate the speed of the interpolation, the easing curve provides the function valueForProgress(), where the \a progress argument specifies the progress of the @@ -80,10 +82,10 @@ \endcode will print the effective progress of the interpolation between 0 and 1. - When using a QAnimation, the easing curve will be used to control the + When using a QPropertyAnimation, the associated easing curve will be used to control the progress of the interpolation between startValue and endValue: \code - QAnimation animation; + QPropertyAnimation animation; animation.setStartValue(0); animation.setEndValue(1000); animation.setDuration(1000); @@ -98,189 +100,191 @@ \value Linear \inlineimage qeasingcurve-linear.png \br - Easing equation function for a simple linear tweening, - with no easing. + Easing curve for a linear (t) function: + velocity is constant. \value InQuad \inlineimage qeasingcurve-inquad.png \br - Easing equation function for a quadratic (t^2) easing - in: accelerating from zero velocity. + Easing curve for a quadratic (t^2) function: + accelerating from zero velocity. \value OutQuad \inlineimage qeasingcurve-outquad.png \br - Easing equation function for a quadratic (t^2) easing - out: decelerating to zero velocity. + Easing curve for a quadratic (t^2) function: + decelerating to zero velocity. \value InOutQuad \inlineimage qeasingcurve-inoutquad.png \br - Easing equation function for a quadratic (t^2) easing - in/out: acceleration until halfway, then deceleration. + Easing curve for a quadratic (t^2) function: + acceleration until halfway, then deceleration. \value OutInQuad \inlineimage qeasingcurve-outinquad.png \br - Easing equation function for a quadratic (t^2) easing - out/in: deceleration until halfway, then acceleration. + Easing curve for a quadratic (t^2) function: + deceleration until halfway, then acceleration. \value InCubic \inlineimage qeasingcurve-incubic.png \br - Easing equation function for a cubic (t^3) easing - in: accelerating from zero velocity. + Easing curve for a cubic (t^3) function: + accelerating from zero velocity. \value OutCubic \inlineimage qeasingcurve-outcubic.png \br - Easing equation function for a cubic (t^3) easing - out: decelerating from zero velocity. + Easing curve for a cubic (t^3) function: + decelerating from zero velocity. \value InOutCubic \inlineimage qeasingcurve-inoutcubic.png \br - Easing equation function for a cubic (t^3) easing - in/out: acceleration until halfway, then deceleration. + Easing curve for a cubic (t^3) function: + acceleration until halfway, then deceleration. \value OutInCubic \inlineimage qeasingcurve-outincubic.png \br - Easing equation function for a cubic (t^3) easing - out/in: deceleration until halfway, then acceleration. + Easing curve for a cubic (t^3) function: + deceleration until halfway, then acceleration. \value InQuart \inlineimage qeasingcurve-inquart.png \br - Easing equation function for a quartic (t^4) easing - in: accelerating from zero velocity. + Easing curve for a quartic (t^4) function: + accelerating from zero velocity. \value OutQuart \inlineimage qeasingcurve-outquart.png \br - Easing equation function for a quartic (t^4) easing - out: decelerating from zero velocity. + Easing curve for a cubic (t^4) function: + decelerating from zero velocity. \value InOutQuart \inlineimage qeasingcurve-inoutquart.png \br - Easing equation function for a quartic (t^4) easing - in/out: acceleration until halfway, then deceleration. + Easing curve for a cubic (t^4) function: + acceleration until halfway, then deceleration. \value OutInQuart \inlineimage qeasingcurve-outinquart.png \br - Easing equation function for a quartic (t^4) easing - out/in: deceleration until halfway, then acceleration. + Easing curve for a cubic (t^4) function: + deceleration until halfway, then acceleration. \value InQuint \inlineimage qeasingcurve-inquint.png \br - Easing equation function for a quintic (t^5) easing + Easing curve for a quintic (t^5) easing in: accelerating from zero velocity. \value OutQuint \inlineimage qeasingcurve-outquint.png \br - Easing equation function for a quintic (t^5) easing - out: decelerating from zero velocity. + Easing curve for a cubic (t^5) function: + decelerating from zero velocity. \value InOutQuint \inlineimage qeasingcurve-inoutquint.png \br - Easing equation function for a quintic (t^5) easing - in/out: acceleration until halfway, then deceleration. + Easing curve for a cubic (t^5) function: + acceleration until halfway, then deceleration. \value OutInQuint \inlineimage qeasingcurve-outinquint.png \br - Easing equation function for a quintic (t^5) easing - out/in: deceleration until halfway, then acceleration. + Easing curve for a cubic (t^5) function: + deceleration until halfway, then acceleration. \value InSine \inlineimage qeasingcurve-insine.png \br - Easing equation function for a sinusoidal (sin(t)) easing - in: accelerating from zero velocity. + Easing curve for a sinusoidal (sin(t)) function: + accelerating from zero velocity. \value OutSine \inlineimage qeasingcurve-outsine.png \br - Easing equation function for a sinusoidal (sin(t)) easing - out: decelerating from zero velocity. + Easing curve for a sinusoidal (sin(t)) function: + decelerating from zero velocity. \value InOutSine \inlineimage qeasingcurve-inoutsine.png \br - Easing equation function for a sinusoidal (sin(t)) easing - in/out: acceleration until halfway, then deceleration. + Easing curve for a sinusoidal (sin(t)) function: + acceleration until halfway, then deceleration. \value OutInSine \inlineimage qeasingcurve-outinsine.png \br - Easing equation function for a sinusoidal (sin(t)) easing - out/in: deceleration until halfway, then acceleration. + Easing curve for a sinusoidal (sin(t)) function: + deceleration until halfway, then acceleration. \value InExpo \inlineimage qeasingcurve-inexpo.png \br - Easing equation function for an exponential (2^t) easing - in: accelerating from zero velocity. + Easing curve for an exponential (2^t) function: + accelerating from zero velocity. \value OutExpo \inlineimage qeasingcurve-outexpo.png \br - Easing equation function for an exponential (2^t) easing - out: decelerating from zero velocity. + Easing curve for an exponential (2^t) function: + decelerating from zero velocity. \value InOutExpo \inlineimage qeasingcurve-inoutexpo.png \br - Easing equation function for an exponential (2^t) easing - in/out: acceleration until halfway, then deceleration. + Easing curve for an exponential (2^t) function: + acceleration until halfway, then deceleration. \value OutInExpo \inlineimage qeasingcurve-outinexpo.png \br - Easing equation function for an exponential (2^t) easing - out/in: deceleration until halfway, then acceleration. + Easing curve for an exponential (2^t) function: + deceleration until halfway, then acceleration. \value InCirc \inlineimage qeasingcurve-incirc.png \br - Easing equation function for a circular (sqrt(1-t^2)) easing - in: accelerating from zero velocity. + Easing curve for a circular (sqrt(1-t^2)) function: + accelerating from zero velocity. \value OutCirc \inlineimage qeasingcurve-outcirc.png \br - Easing equation function for a circular (sqrt(1-t^2)) easing - out: decelerating from zero velocity. + Easing curve for a circular (sqrt(1-t^2)) function: + decelerating from zero velocity. \value InOutCirc \inlineimage qeasingcurve-inoutcirc.png \br - Easing equation function for a circular (sqrt(1-t^2)) easing - in/out: acceleration until halfway, then deceleration. + Easing curve for a circular (sqrt(1-t^2)) function: + acceleration until halfway, then deceleration. \value OutInCirc \inlineimage qeasingcurve-outincirc.png \br - Easing equation function for a circular (sqrt(1-t^2)) easing - out/in: deceleration until halfway, then acceleration. + Easing curve for a circular (sqrt(1-t^2)) function: + deceleration until halfway, then acceleration. \value InElastic \inlineimage qeasingcurve-inelastic.png \br - Easing equation function for an elastic - (exponentially decaying sine wave) easing in: + Easing curve for an elastic + (exponentially decaying sine wave) function: accelerating from zero velocity. The peak amplitude can be set with the \e amplitude parameter, and the period of decay by the \e period parameter. \value OutElastic \inlineimage qeasingcurve-outelastic.png \br - Easing equation function for an elastic - (exponentially decaying sine wave) easing out: + Easing curve for an elastic + (exponentially decaying sine wave) function: decelerating from zero velocity. The peak amplitude can be set with the \e amplitude parameter, and the period of decay by the \e period parameter. \value InOutElastic \inlineimage qeasingcurve-inoutelastic.png \br - Easing equation function for an elastic - (exponentially decaying sine wave) easing in/out: + Easing curve for an elastic + (exponentially decaying sine wave) function: acceleration until halfway, then deceleration. \value OutInElastic \inlineimage qeasingcurve-outinelastic.png \br - Easing equation function for an elastic - (exponentially decaying sine wave) easing out/in: + Easing curve for an elastic + (exponentially decaying sine wave) function: deceleration until halfway, then acceleration. \value InBack \inlineimage qeasingcurve-inback.png \br - Easing equation function for a back (overshooting - cubic easing: (s+1)*t^3 - s*t^2) easing in: + Easing curve for a back (overshooting + cubic function: (s+1)*t^3 - s*t^2) easing in: accelerating from zero velocity. \value OutBack \inlineimage qeasingcurve-outback.png \br - Easing equation function for a back (overshooting - cubic easing: (s+1)*t^3 - s*t^2) easing out: - decelerating from zero velocity. + Easing curve for a back (overshooting + cubic function: (s+1)*t^3 - s*t^2) easing out: + decelerating to zero velocity. \value InOutBack \inlineimage qeasingcurve-inoutback.png \br - Easing equation function for a back (overshooting - cubic easing: (s+1)*t^3 - s*t^2) easing in/out: + Easing curve for a back (overshooting + cubic function: (s+1)*t^3 - s*t^2) easing in/out: acceleration until halfway, then deceleration. \value OutInBack \inlineimage qeasingcurve-outinback.png \br - Easing equation function for a back (overshooting + Easing curve for a back (overshooting cubic easing: (s+1)*t^3 - s*t^2) easing out/in: deceleration until halfway, then acceleration. \value InBounce \inlineimage qeasingcurve-inbounce.png \br - Easing equation function for a bounce (exponentially - decaying parabolic bounce) easing in: accelerating + Easing curve for a bounce (exponentially + decaying parabolic bounce) function: accelerating from zero velocity. \value OutBounce \inlineimage qeasingcurve-outbounce.png \br - Easing equation function for a bounce (exponentially - decaying parabolic bounce) easing out: decelerating + Easing curve for a bounce (exponentially + decaying parabolic bounce) function: decelerating from zero velocity. \value InOutBounce \inlineimage qeasingcurve-inoutbounce.png \br - Easing equation function for a bounce (exponentially - decaying parabolic bounce) easing in/out: + Easing curve for a bounce (exponentially + decaying parabolic bounce) function easing in/out: acceleration until halfway, then deceleration. \value OutInBounce \inlineimage qeasingcurve-outinbounce.png \br - Easing equation function for a bounce (exponentially - decaying parabolic bounce) easing out/in: + Easing curve for a bounce (exponentially + decaying parabolic bounce) function easing out/in: deceleration until halfway, then acceleration. \omitvalue InCurve \omitvalue OutCurve \omitvalue SineCurve \omitvalue CosineCurve - \value Custom This is returned if the user have specified a custom curve type with setCustomType(). Note that you cannot call setType() with this value, but type() can return it. + \value Custom This is returned if the user specified a custom curve type with + setCustomType(). Note that you cannot call setType() with this value, + but type() can return it. \omitvalue NCurveTypes */ diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp index fef1931..85e49c7 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -413,8 +413,8 @@ QByteArray getWinLocaleName(LCID id = LOCALE_USER_DEFAULT) result = envVarLocale(); QChar lang[3]; QChar cntry[2]; - if ( result == "C" || !result.isEmpty() - && splitLocaleName(QString::fromLocal8Bit(result), lang, cntry) ) { + if ( result == "C" || (!result.isEmpty() + && splitLocaleName(QString::fromLocal8Bit(result), lang, cntry)) ) { long id = 0; bool ok = false; id = qstrtoll(result.data(), 0, 0, &ok); @@ -5299,7 +5299,11 @@ struct p5s_deleter { ~p5s_deleter() { - Bfree(p5s); + while (p5s) { + Bigint *next = p5s->next; + Bfree(p5s); + p5s = next; + } } }; diff --git a/src/corelib/tools/qpoint.cpp b/src/corelib/tools/qpoint.cpp index 49afdca..af60f52 100644 --- a/src/corelib/tools/qpoint.cpp +++ b/src/corelib/tools/qpoint.cpp @@ -444,6 +444,8 @@ QDebug operator<<(QDebug d, const QPointF &p) /*! + \since 4.6 + Returns the sum of the absolute values of x() and y(), traditionally known as the "Manhattan length" of the vector from the origin to the point. diff --git a/src/corelib/tools/qregexp.cpp b/src/corelib/tools/qregexp.cpp index 3108f31..3527308 100644 --- a/src/corelib/tools/qregexp.cpp +++ b/src/corelib/tools/qregexp.cpp @@ -70,6 +70,8 @@ int qFindString(const QChar *haystack, int haystackLen, int from, #define RXERR_LEFTDELIM QT_TRANSLATE_NOOP("QRegExp", "missing left delim") #define RXERR_END QT_TRANSLATE_NOOP("QRegExp", "unexpected end") #define RXERR_LIMIT QT_TRANSLATE_NOOP("QRegExp", "met internal limit") +#define RXERR_INTERVAL QT_TRANSLATE_NOOP("QRegExp", "invalid interval") +#define RXERR_CATEGORY QT_TRANSLATE_NOOP("QRegExp", "invalid category") /* WARNING! Be sure to read qregexp.tex before modifying this file. @@ -1116,6 +1118,7 @@ private: bool valid; // is the regular expression valid? Qt::CaseSensitivity cs; // case sensitive? bool greedyQuantifiers; // RegExp2? + bool xmlSchemaExtensions; #ifndef QT_NO_REGEXP_BACKREF int nbrefs; // number of back-references #endif @@ -1193,6 +1196,8 @@ private: friend class Box; + void setupCategoriesRangeMap(); + /* This is the lexical analyzer for regular expressions. */ @@ -1232,6 +1237,7 @@ private: int yyTok; // the last token read bool yyMayCapture; // set this to false to disable capturing + QHash<QByteArray, QPair<int, int> > categoriesRangeMap; // fast lookup hash for xml schema extensions friend struct QRegExpMatchState; }; @@ -1253,7 +1259,8 @@ struct QRegExpLookahead #endif QRegExpEngine::QRegExpEngine(const QRegExpEngineKey &key) - : cs(key.cs), greedyQuantifiers(key.patternSyntax == QRegExp::RegExp2) + : cs(key.cs), greedyQuantifiers(key.patternSyntax == QRegExp::RegExp2), + xmlSchemaExtensions(false) { setup(); @@ -1268,6 +1275,8 @@ QRegExpEngine::QRegExpEngine(const QRegExpEngineKey &key) case QRegExp::FixedString: rx = QRegExp::escape(key.pattern); break; + case QRegExp::W3CXmlSchema11: + xmlSchemaExtensions = true; default: rx = key.pattern; } @@ -1479,9 +1488,8 @@ int QRegExpEngine::anchorAlternation(int a, int b) return Anchor_Alternation | (n - 1); #endif - aa.resize(n + 1); - aa[n].a = a; - aa[n].b = b; + QRegExpAnchorAlternation element = {a, b}; + aa.append(element); return Anchor_Alternation | n; } @@ -2621,6 +2629,152 @@ void QRegExpEngine::Box::addAnchorsToEngine(const Box &to) const } } +void QRegExpEngine::setupCategoriesRangeMap() +{ + categoriesRangeMap.insert("IsBasicLatin", qMakePair(0x0000, 0x007F)); + categoriesRangeMap.insert("IsLatin-1Supplement", qMakePair(0x0080, 0x00FF)); + categoriesRangeMap.insert("IsLatinExtended-A", qMakePair(0x0100, 0x017F)); + categoriesRangeMap.insert("IsLatinExtended-B", qMakePair(0x0180, 0x024F)); + categoriesRangeMap.insert("IsIPAExtensions", qMakePair(0x0250, 0x02AF)); + categoriesRangeMap.insert("IsSpacingModifierLetters", qMakePair(0x02B0, 0x02FF)); + categoriesRangeMap.insert("IsCombiningDiacriticalMarks", qMakePair(0x0300, 0x036F)); + categoriesRangeMap.insert("IsGreek", qMakePair(0x0370, 0x03FF)); + categoriesRangeMap.insert("IsCyrillic", qMakePair(0x0400, 0x04FF)); + categoriesRangeMap.insert("IsCyrillicSupplement", qMakePair(0x0500, 0x052F)); + categoriesRangeMap.insert("IsArmenian", qMakePair(0x0530, 0x058F)); + categoriesRangeMap.insert("IsHebrew", qMakePair(0x0590, 0x05FF)); + categoriesRangeMap.insert("IsArabic", qMakePair(0x0600, 0x06FF)); + categoriesRangeMap.insert("IsSyriac", qMakePair(0x0700, 0x074F)); + categoriesRangeMap.insert("IsArabicSupplement", qMakePair(0x0750, 0x077F)); + categoriesRangeMap.insert("IsThaana", qMakePair(0x0780, 0x07BF)); + categoriesRangeMap.insert("IsDevanagari", qMakePair(0x0900, 0x097F)); + categoriesRangeMap.insert("IsBengali", qMakePair(0x0980, 0x09FF)); + categoriesRangeMap.insert("IsGurmukhi", qMakePair(0x0A00, 0x0A7F)); + categoriesRangeMap.insert("IsGujarati", qMakePair(0x0A80, 0x0AFF)); + categoriesRangeMap.insert("IsOriya", qMakePair(0x0B00, 0x0B7F)); + categoriesRangeMap.insert("IsTamil", qMakePair(0x0B80, 0x0BFF)); + categoriesRangeMap.insert("IsTelugu", qMakePair(0x0C00, 0x0C7F)); + categoriesRangeMap.insert("IsKannada", qMakePair(0x0C80, 0x0CFF)); + categoriesRangeMap.insert("IsMalayalam", qMakePair(0x0D00, 0x0D7F)); + categoriesRangeMap.insert("IsSinhala", qMakePair(0x0D80, 0x0DFF)); + categoriesRangeMap.insert("IsThai", qMakePair(0x0E00, 0x0E7F)); + categoriesRangeMap.insert("IsLao", qMakePair(0x0E80, 0x0EFF)); + categoriesRangeMap.insert("IsTibetan", qMakePair(0x0F00, 0x0FFF)); + categoriesRangeMap.insert("IsMyanmar", qMakePair(0x1000, 0x109F)); + categoriesRangeMap.insert("IsGeorgian", qMakePair(0x10A0, 0x10FF)); + categoriesRangeMap.insert("IsHangulJamo", qMakePair(0x1100, 0x11FF)); + categoriesRangeMap.insert("IsEthiopic", qMakePair(0x1200, 0x137F)); + categoriesRangeMap.insert("IsEthiopicSupplement", qMakePair(0x1380, 0x139F)); + categoriesRangeMap.insert("IsCherokee", qMakePair(0x13A0, 0x13FF)); + categoriesRangeMap.insert("IsUnifiedCanadianAboriginalSyllabics", qMakePair(0x1400, 0x167F)); + categoriesRangeMap.insert("IsOgham", qMakePair(0x1680, 0x169F)); + categoriesRangeMap.insert("IsRunic", qMakePair(0x16A0, 0x16FF)); + categoriesRangeMap.insert("IsTagalog", qMakePair(0x1700, 0x171F)); + categoriesRangeMap.insert("IsHanunoo", qMakePair(0x1720, 0x173F)); + categoriesRangeMap.insert("IsBuhid", qMakePair(0x1740, 0x175F)); + categoriesRangeMap.insert("IsTagbanwa", qMakePair(0x1760, 0x177F)); + categoriesRangeMap.insert("IsKhmer", qMakePair(0x1780, 0x17FF)); + categoriesRangeMap.insert("IsMongolian", qMakePair(0x1800, 0x18AF)); + categoriesRangeMap.insert("IsLimbu", qMakePair(0x1900, 0x194F)); + categoriesRangeMap.insert("IsTaiLe", qMakePair(0x1950, 0x197F)); + categoriesRangeMap.insert("IsNewTaiLue", qMakePair(0x1980, 0x19DF)); + categoriesRangeMap.insert("IsKhmerSymbols", qMakePair(0x19E0, 0x19FF)); + categoriesRangeMap.insert("IsBuginese", qMakePair(0x1A00, 0x1A1F)); + categoriesRangeMap.insert("IsPhoneticExtensions", qMakePair(0x1D00, 0x1D7F)); + categoriesRangeMap.insert("IsPhoneticExtensionsSupplement", qMakePair(0x1D80, 0x1DBF)); + categoriesRangeMap.insert("IsCombiningDiacriticalMarksSupplement", qMakePair(0x1DC0, 0x1DFF)); + categoriesRangeMap.insert("IsLatinExtendedAdditional", qMakePair(0x1E00, 0x1EFF)); + categoriesRangeMap.insert("IsGreekExtended", qMakePair(0x1F00, 0x1FFF)); + categoriesRangeMap.insert("IsGeneralPunctuation", qMakePair(0x2000, 0x206F)); + categoriesRangeMap.insert("IsSuperscriptsandSubscripts", qMakePair(0x2070, 0x209F)); + categoriesRangeMap.insert("IsCurrencySymbols", qMakePair(0x20A0, 0x20CF)); + categoriesRangeMap.insert("IsCombiningMarksforSymbols", qMakePair(0x20D0, 0x20FF)); + categoriesRangeMap.insert("IsLetterlikeSymbols", qMakePair(0x2100, 0x214F)); + categoriesRangeMap.insert("IsNumberForms", qMakePair(0x2150, 0x218F)); + categoriesRangeMap.insert("IsArrows", qMakePair(0x2190, 0x21FF)); + categoriesRangeMap.insert("IsMathematicalOperators", qMakePair(0x2200, 0x22FF)); + categoriesRangeMap.insert("IsMiscellaneousTechnical", qMakePair(0x2300, 0x23FF)); + categoriesRangeMap.insert("IsControlPictures", qMakePair(0x2400, 0x243F)); + categoriesRangeMap.insert("IsOpticalCharacterRecognition", qMakePair(0x2440, 0x245F)); + categoriesRangeMap.insert("IsEnclosedAlphanumerics", qMakePair(0x2460, 0x24FF)); + categoriesRangeMap.insert("IsBoxDrawing", qMakePair(0x2500, 0x257F)); + categoriesRangeMap.insert("IsBlockElements", qMakePair(0x2580, 0x259F)); + categoriesRangeMap.insert("IsGeometricShapes", qMakePair(0x25A0, 0x25FF)); + categoriesRangeMap.insert("IsMiscellaneousSymbols", qMakePair(0x2600, 0x26FF)); + categoriesRangeMap.insert("IsDingbats", qMakePair(0x2700, 0x27BF)); + categoriesRangeMap.insert("IsMiscellaneousMathematicalSymbols-A", qMakePair(0x27C0, 0x27EF)); + categoriesRangeMap.insert("IsSupplementalArrows-A", qMakePair(0x27F0, 0x27FF)); + categoriesRangeMap.insert("IsBraillePatterns", qMakePair(0x2800, 0x28FF)); + categoriesRangeMap.insert("IsSupplementalArrows-B", qMakePair(0x2900, 0x297F)); + categoriesRangeMap.insert("IsMiscellaneousMathematicalSymbols-B", qMakePair(0x2980, 0x29FF)); + categoriesRangeMap.insert("IsSupplementalMathematicalOperators", qMakePair(0x2A00, 0x2AFF)); + categoriesRangeMap.insert("IsMiscellaneousSymbolsandArrows", qMakePair(0x2B00, 0x2BFF)); + categoriesRangeMap.insert("IsGlagolitic", qMakePair(0x2C00, 0x2C5F)); + categoriesRangeMap.insert("IsCoptic", qMakePair(0x2C80, 0x2CFF)); + categoriesRangeMap.insert("IsGeorgianSupplement", qMakePair(0x2D00, 0x2D2F)); + categoriesRangeMap.insert("IsTifinagh", qMakePair(0x2D30, 0x2D7F)); + categoriesRangeMap.insert("IsEthiopicExtended", qMakePair(0x2D80, 0x2DDF)); + categoriesRangeMap.insert("IsSupplementalPunctuation", qMakePair(0x2E00, 0x2E7F)); + categoriesRangeMap.insert("IsCJKRadicalsSupplement", qMakePair(0x2E80, 0x2EFF)); + categoriesRangeMap.insert("IsKangxiRadicals", qMakePair(0x2F00, 0x2FDF)); + categoriesRangeMap.insert("IsIdeographicDescriptionCharacters", qMakePair(0x2FF0, 0x2FFF)); + categoriesRangeMap.insert("IsCJKSymbolsandPunctuation", qMakePair(0x3000, 0x303F)); + categoriesRangeMap.insert("IsHiragana", qMakePair(0x3040, 0x309F)); + categoriesRangeMap.insert("IsKatakana", qMakePair(0x30A0, 0x30FF)); + categoriesRangeMap.insert("IsBopomofo", qMakePair(0x3100, 0x312F)); + categoriesRangeMap.insert("IsHangulCompatibilityJamo", qMakePair(0x3130, 0x318F)); + categoriesRangeMap.insert("IsKanbun", qMakePair(0x3190, 0x319F)); + categoriesRangeMap.insert("IsBopomofoExtended", qMakePair(0x31A0, 0x31BF)); + categoriesRangeMap.insert("IsCJKStrokes", qMakePair(0x31C0, 0x31EF)); + categoriesRangeMap.insert("IsKatakanaPhoneticExtensions", qMakePair(0x31F0, 0x31FF)); + categoriesRangeMap.insert("IsEnclosedCJKLettersandMonths", qMakePair(0x3200, 0x32FF)); + categoriesRangeMap.insert("IsCJKCompatibility", qMakePair(0x3300, 0x33FF)); + categoriesRangeMap.insert("IsCJKUnifiedIdeographsExtensionA", qMakePair(0x3400, 0x4DB5)); + categoriesRangeMap.insert("IsYijingHexagramSymbols", qMakePair(0x4DC0, 0x4DFF)); + categoriesRangeMap.insert("IsCJKUnifiedIdeographs", qMakePair(0x4E00, 0x9FFF)); + categoriesRangeMap.insert("IsYiSyllables", qMakePair(0xA000, 0xA48F)); + categoriesRangeMap.insert("IsYiRadicals", qMakePair(0xA490, 0xA4CF)); + categoriesRangeMap.insert("IsModifierToneLetters", qMakePair(0xA700, 0xA71F)); + categoriesRangeMap.insert("IsSylotiNagri", qMakePair(0xA800, 0xA82F)); + categoriesRangeMap.insert("IsHangulSyllables", qMakePair(0xAC00, 0xD7A3)); + categoriesRangeMap.insert("IsPrivateUse", qMakePair(0xE000, 0xF8FF)); + categoriesRangeMap.insert("IsCJKCompatibilityIdeographs", qMakePair(0xF900, 0xFAFF)); + categoriesRangeMap.insert("IsAlphabeticPresentationForms", qMakePair(0xFB00, 0xFB4F)); + categoriesRangeMap.insert("IsArabicPresentationForms-A", qMakePair(0xFB50, 0xFDFF)); + categoriesRangeMap.insert("IsVariationSelectors", qMakePair(0xFE00, 0xFE0F)); + categoriesRangeMap.insert("IsVerticalForms", qMakePair(0xFE10, 0xFE1F)); + categoriesRangeMap.insert("IsCombiningHalfMarks", qMakePair(0xFE20, 0xFE2F)); + categoriesRangeMap.insert("IsCJKCompatibilityForms", qMakePair(0xFE30, 0xFE4F)); + categoriesRangeMap.insert("IsSmallFormVariants", qMakePair(0xFE50, 0xFE6F)); + categoriesRangeMap.insert("IsArabicPresentationForms-B", qMakePair(0xFE70, 0xFEFF)); + categoriesRangeMap.insert("IsHalfwidthandFullwidthForms", qMakePair(0xFF00, 0xFFEF)); + categoriesRangeMap.insert("IsSpecials", qMakePair(0xFFF0, 0xFFFF)); + categoriesRangeMap.insert("IsLinearBSyllabary", qMakePair(0x10000, 0x1007F)); + categoriesRangeMap.insert("IsLinearBIdeograms", qMakePair(0x10080, 0x100FF)); + categoriesRangeMap.insert("IsAegeanNumbers", qMakePair(0x10100, 0x1013F)); + categoriesRangeMap.insert("IsAncientGreekNumbers", qMakePair(0x10140, 0x1018F)); + categoriesRangeMap.insert("IsOldItalic", qMakePair(0x10300, 0x1032F)); + categoriesRangeMap.insert("IsGothic", qMakePair(0x10330, 0x1034F)); + categoriesRangeMap.insert("IsUgaritic", qMakePair(0x10380, 0x1039F)); + categoriesRangeMap.insert("IsOldPersian", qMakePair(0x103A0, 0x103DF)); + categoriesRangeMap.insert("IsDeseret", qMakePair(0x10400, 0x1044F)); + categoriesRangeMap.insert("IsShavian", qMakePair(0x10450, 0x1047F)); + categoriesRangeMap.insert("IsOsmanya", qMakePair(0x10480, 0x104AF)); + categoriesRangeMap.insert("IsCypriotSyllabary", qMakePair(0x10800, 0x1083F)); + categoriesRangeMap.insert("IsKharoshthi", qMakePair(0x10A00, 0x10A5F)); + categoriesRangeMap.insert("IsByzantineMusicalSymbols", qMakePair(0x1D000, 0x1D0FF)); + categoriesRangeMap.insert("IsMusicalSymbols", qMakePair(0x1D100, 0x1D1FF)); + categoriesRangeMap.insert("IsAncientGreekMusicalNotation", qMakePair(0x1D200, 0x1D24F)); + categoriesRangeMap.insert("IsTaiXuanJingSymbols", qMakePair(0x1D300, 0x1D35F)); + categoriesRangeMap.insert("IsMathematicalAlphanumericSymbols", qMakePair(0x1D400, 0x1D7FF)); + categoriesRangeMap.insert("IsCJKUnifiedIdeographsExtensionB", qMakePair(0x20000, 0x2A6DF)); + categoriesRangeMap.insert("IsCJKCompatibilityIdeographsSupplement", qMakePair(0x2F800, 0x2FA1F)); + categoriesRangeMap.insert("IsTags", qMakePair(0xE0000, 0xE007F)); + categoriesRangeMap.insert("IsVariationSelectorsSupplement", qMakePair(0xE0100, 0xE01EF)); + categoriesRangeMap.insert("IsSupplementaryPrivateUseArea-A", qMakePair(0xF0000, 0xFFFFF)); + categoriesRangeMap.insert("IsSupplementaryPrivateUseArea-B", qMakePair(0x100000, 0x10FFFF)); +} + int QRegExpEngine::getChar() { return (yyPos == yyLen) ? EOS : yyIn[yyPos++].unicode(); @@ -2713,6 +2867,177 @@ int QRegExpEngine::getEscape() yyCharClass->addCategories(0x000f807e); yyCharClass->addSingleton(0x005f); // '_' return Tok_CharClass; + case 'I': + if (xmlSchemaExtensions) { + yyCharClass->setNegative(!yyCharClass->negative()); + // fall through + } + case 'i': + if (xmlSchemaExtensions) { + yyCharClass->addCategories(0x000f807e); + yyCharClass->addSingleton(0x003a); // ':' + yyCharClass->addSingleton(0x005f); // '_' + yyCharClass->addRange(0x0041, 0x005a); // [A-Z] + yyCharClass->addRange(0x0061, 0x007a); // [a-z] + yyCharClass->addRange(0xc0, 0xd6); + yyCharClass->addRange(0xd8, 0xf6); + yyCharClass->addRange(0xf8, 0x2ff); + yyCharClass->addRange(0x370, 0x37d); + yyCharClass->addRange(0x37f, 0x1fff); + yyCharClass->addRange(0x200c, 0x200d); + yyCharClass->addRange(0x2070, 0x218f); + yyCharClass->addRange(0x2c00, 0x2fef); + yyCharClass->addRange(0x3001, 0xd7ff); + yyCharClass->addRange(0xf900, 0xfdcf); + yyCharClass->addRange(0xfdf0, 0xfffd); + yyCharClass->addRange((ushort)0x10000, (ushort)0xeffff); + } + return Tok_CharClass; + case 'C': + if (xmlSchemaExtensions) { + yyCharClass->setNegative(!yyCharClass->negative()); + // fall through + } + case 'c': + if (xmlSchemaExtensions) { + yyCharClass->addCategories(0x000f807e); + yyCharClass->addSingleton(0x002d); // '-' + yyCharClass->addSingleton(0x002e); // '.' + yyCharClass->addSingleton(0x003a); // ':' + yyCharClass->addSingleton(0x005f); // '_' + yyCharClass->addSingleton(0xb7); + yyCharClass->addRange(0x0030, 0x0039); // [0-9] + yyCharClass->addRange(0x0041, 0x005a); // [A-Z] + yyCharClass->addRange(0x0061, 0x007a); // [a-z] + yyCharClass->addRange(0xc0, 0xd6); + yyCharClass->addRange(0xd8, 0xf6); + yyCharClass->addRange(0xf8, 0x2ff); + yyCharClass->addRange(0x370, 0x37d); + yyCharClass->addRange(0x37f, 0x1fff); + yyCharClass->addRange(0x200c, 0x200d); + yyCharClass->addRange(0x2070, 0x218f); + yyCharClass->addRange(0x2c00, 0x2fef); + yyCharClass->addRange(0x3001, 0xd7ff); + yyCharClass->addRange(0xf900, 0xfdcf); + yyCharClass->addRange(0xfdf0, 0xfffd); + yyCharClass->addRange((ushort)0x10000, (ushort)0xeffff); + yyCharClass->addRange(0x0300, 0x036f); + yyCharClass->addRange(0x203f, 0x2040); + } + return Tok_CharClass; + case 'P': + if (xmlSchemaExtensions) { + yyCharClass->setNegative(!yyCharClass->negative()); + // fall through + } + case 'p': + if (xmlSchemaExtensions) { + if (yyCh != '{') { + error(RXERR_CHARCLASS); + return Tok_CharClass; + } + + QByteArray category; + yyCh = getChar(); + while (yyCh != '}') { + if (yyCh == EOS) { + error(RXERR_END); + return Tok_CharClass; + } + category.append(yyCh); + yyCh = getChar(); + } + yyCh = getChar(); // skip closing '}' + + if (category == "M") { + yyCharClass->addCategories(0x0000000e); + } else if (category == "Mn") { + yyCharClass->addCategories(0x00000002); + } else if (category == "Mc") { + yyCharClass->addCategories(0x00000004); + } else if (category == "Me") { + yyCharClass->addCategories(0x00000008); + } else if (category == "N") { + yyCharClass->addCategories(0x00000070); + } else if (category == "Nd") { + yyCharClass->addCategories(0x00000010); + } else if (category == "Nl") { + yyCharClass->addCategories(0x00000020); + } else if (category == "No") { + yyCharClass->addCategories(0x00000040); + } else if (category == "Z") { + yyCharClass->addCategories(0x00000380); + } else if (category == "Zs") { + yyCharClass->addCategories(0x00000080); + } else if (category == "Zl") { + yyCharClass->addCategories(0x00000100); + } else if (category == "Zp") { + yyCharClass->addCategories(0x00000200); + } else if (category == "C") { + yyCharClass->addCategories(0x00006c00); + } else if (category == "Cc") { + yyCharClass->addCategories(0x00000400); + } else if (category == "Cf") { + yyCharClass->addCategories(0x00000800); + } else if (category == "Cs") { + yyCharClass->addCategories(0x00001000); + } else if (category == "Co") { + yyCharClass->addCategories(0x00002000); + } else if (category == "Cn") { + yyCharClass->addCategories(0x00004000); + } else if (category == "L") { + yyCharClass->addCategories(0x000f8000); + } else if (category == "Lu") { + yyCharClass->addCategories(0x00008000); + } else if (category == "Ll") { + yyCharClass->addCategories(0x00010000); + } else if (category == "Lt") { + yyCharClass->addCategories(0x00020000); + } else if (category == "Lm") { + yyCharClass->addCategories(0x00040000); + } else if (category == "Lo") { + yyCharClass->addCategories(0x00080000); + } else if (category == "P") { + yyCharClass->addCategories(0x4f580780); + } else if (category == "Pc") { + yyCharClass->addCategories(0x00100000); + } else if (category == "Pd") { + yyCharClass->addCategories(0x00200000); + } else if (category == "Ps") { + yyCharClass->addCategories(0x00400000); + } else if (category == "Pe") { + yyCharClass->addCategories(0x00800000); + } else if (category == "Pi") { + yyCharClass->addCategories(0x01000000); + } else if (category == "Pf") { + yyCharClass->addCategories(0x02000000); + } else if (category == "Po") { + yyCharClass->addCategories(0x04000000); + } else if (category == "S") { + yyCharClass->addCategories(0x78000000); + } else if (category == "Sm") { + yyCharClass->addCategories(0x08000000); + } else if (category == "Sc") { + yyCharClass->addCategories(0x10000000); + } else if (category == "Sk") { + yyCharClass->addCategories(0x20000000); + } else if (category == "So") { + yyCharClass->addCategories(0x40000000); + } else if (category.startsWith("Is")) { + if (categoriesRangeMap.isEmpty()) + setupCategoriesRangeMap(); + + if (categoriesRangeMap.contains(category)) { + const QPair<int, int> range = categoriesRangeMap.value(category); + yyCharClass->addRange(range.first, range.second); + } else { + error(RXERR_CATEGORY); + } + } else { + error(RXERR_CATEGORY); + } + } + return Tok_CharClass; #endif #ifndef QT_NO_REGEXP_ESCAPE case 'x': @@ -2934,7 +3259,7 @@ int QRegExpEngine::getToken() yyMaxRep = getRep(InftyRep); } if (yyMaxRep < yyMinRep) - qSwap(yyMinRep, yyMaxRep); + error(RXERR_INTERVAL); if (yyCh != '}') error(RXERR_REPETITION); yyCh = getChar(); @@ -3296,7 +3621,7 @@ static void prepareEngine_helper(QRegExpPrivate *priv) { bool initMatchState = !priv->eng; #if !defined(QT_NO_REGEXP_OPTIM) - if (!priv->eng) { + if (!priv->eng && globalEngineCache()) { QMutexLocker locker(mutex()); priv->eng = globalEngineCache()->take(priv->engineKey); if (priv->eng != 0) @@ -3374,6 +3699,9 @@ static void invalidateEngine(QRegExpPrivate *priv) equivalent to using the RegExp pattern on a string in which all metacharacters are escaped using escape(). + \value W3CXmlSchema11 The pattern is a regular expression as + defined by the W3C XML Schema 1.1 specification. + \sa setPatternSyntax() */ diff --git a/src/corelib/tools/qregexp.h b/src/corelib/tools/qregexp.h index 057eec2..16682a3 100644 --- a/src/corelib/tools/qregexp.h +++ b/src/corelib/tools/qregexp.h @@ -61,7 +61,7 @@ class QStringList; class Q_CORE_EXPORT QRegExp { public: - enum PatternSyntax { RegExp, Wildcard, FixedString, RegExp2 }; + enum PatternSyntax { RegExp, Wildcard, FixedString, RegExp2, W3CXmlSchema11 }; enum CaretMode { CaretAtZero, CaretAtOffset, CaretWontMatch }; QRegExp(); diff --git a/src/corelib/tools/qsharedpointer.cpp b/src/corelib/tools/qsharedpointer.cpp index fe3d9e0..85085c5 100644 --- a/src/corelib/tools/qsharedpointer.cpp +++ b/src/corelib/tools/qsharedpointer.cpp @@ -341,6 +341,7 @@ /*! \fn QSharedPointer<X> QSharedPointer::objectCast() const + \since 4.6 Performs a \l qobject_cast() from this pointer's type to \tt X and returns a QSharedPointer that shares the reference. If this @@ -737,6 +738,7 @@ /*! \fn QSharedPointer<X> qSharedPointerObjectCast(const QSharedPointer<T> &other) \relates QSharedPointer + \since 4.6 Returns a shared pointer to the pointer held by \a other, using a \l qobject_cast() to type \tt X to obtain an internal pointer of the @@ -754,6 +756,7 @@ \fn QSharedPointer<X> qSharedPointerObjectCast(const QWeakPointer<T> &other) \relates QSharedPointer \relates QWeakPointer + \since 4.6 Returns a shared pointer to the pointer held by \a other, using a \l qobject_cast() to type \tt X to obtain an internal pointer of the diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index b160b90..99fbaa9 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -45,6 +45,7 @@ #ifndef QT_NO_TEXTCODEC #include <qtextcodec.h> #endif +#include <private/qutfcodec_p.h> #include <qdatastream.h> #include <qlist.h> #include "qlocale.h" @@ -964,7 +965,8 @@ int QString::toWCharArray(wchar_t *array) const Constructs a string initialized with the first \a size characters of the QChar array \a unicode. - QString makes a deep copy of the string data. + QString makes a deep copy of the string data. The unicode data is copied as + is and the Byte Order Mark is preserved if present. */ QString::QString(const QChar *unicode, int size) { @@ -3480,7 +3482,7 @@ QByteArray QString::toAscii() const return toLatin1(); } -#ifndef Q_WS_MAC +#if !defined(Q_WS_MAC) && defined(Q_OS_UNIX) static QByteArray toLocal8Bit_helper(const QChar *data, int length) { #ifndef QT_NO_TEXTCODEC @@ -3843,74 +3845,7 @@ QString QString::fromUtf8(const char *str, int size) if (size < 0) size = qstrlen(str); - QString result(size, Qt::Uninitialized); // worst case - ushort *qch = result.d->data; - uint uc = 0; - uint min_uc = 0; - int need = 0; - int error = -1; - uchar ch; - int i = 0; - - // skip utf8-encoded byte order mark - if (size >= 3 - && (uchar)str[0] == 0xef && (uchar)str[1] == 0xbb && (uchar)str[2] == 0xbf) - i += 3; - - for (; i < size; ++i) { - ch = str[i]; - if (need) { - if ((ch&0xc0) == 0x80) { - uc = (uc << 6) | (ch & 0x3f); - need--; - if (!need) { - if (uc > 0xffffU && uc < 0x110000U) { - // surrogate pair - *qch++ = QChar::highSurrogate(uc); - uc = QChar::lowSurrogate(uc); - } else if ((uc < min_uc) || (uc >= 0xd800 && uc <= 0xdfff) || (uc >= 0xfffe)) { - // overlong seqence, UTF16 surrogate or BOM - uc = QChar::ReplacementCharacter; - } - *qch++ = uc; - } - } else { - i = error; - need = 0; - *qch++ = QChar::ReplacementCharacter; - } - } else { - if (ch < 128) { - *qch++ = ch; - } else if ((ch & 0xe0) == 0xc0) { - uc = ch & 0x1f; - need = 1; - error = i; - min_uc = 0x80; - } else if ((ch & 0xf0) == 0xe0) { - uc = ch & 0x0f; - need = 2; - error = i; - min_uc = 0x800; - } else if ((ch&0xf8) == 0xf0) { - uc = ch & 0x07; - need = 3; - error = i; - min_uc = 0x10000; - } else { - // Error - *qch++ = QChar::ReplacementCharacter; - } - } - } - if (need) { - // we have some invalid characters remaining we need to add to the string - for (int i = error; i < size; ++i) - *qch++ = QChar::ReplacementCharacter; - } - - result.truncate(qch - result.d->data); - return result; + return QUtf8::convertToUnicode(str, size, 0); } /*! @@ -3933,7 +3868,7 @@ QString QString::fromUtf16(const ushort *unicode, int size) while (unicode[size] != 0) ++size; } - return QString((const QChar *)unicode, size); + return QUtf16::convertToUnicode((const char *)unicode, size*2, 0); } @@ -3957,20 +3892,7 @@ QString QString::fromUcs4(const uint *unicode, int size) while (unicode[size] != 0) ++size; } - - QString s(size * 2, Qt::Uninitialized); // worst case - ushort *uc = s.d->data; - for (int i = 0; i < size; ++i) { - uint u = unicode[i]; - if (u > 0xffff) { - // decompose into a surrogate pair - *uc++ = QChar::highSurrogate(u); - u = QChar::lowSurrogate(u); - } - *uc++ = u; - } - s.resize(uc - s.d->data); - return s; + return QUtf32::convertToUnicode((const char *)unicode, size*4, 0); } /*! @@ -6106,6 +6028,7 @@ QString QString::repeated(int times) const return result; } +void qt_string_normalize(QString *data, QString::NormalizationForm mode, QChar::UnicodeVersion version, int from); /*! \overload \fn QString QString::normalized(NormalizationForm mode, QChar::UnicodeVersion version) const @@ -6115,42 +6038,48 @@ QString QString::repeated(int times) const */ QString QString::normalized(QString::NormalizationForm mode, QChar::UnicodeVersion version) const { + QString copy = *this; + qt_string_normalize(©, mode, version, 0); + return copy; +} + +void qt_string_normalize(QString *data, QString::NormalizationForm mode, QChar::UnicodeVersion version, int from) +{ bool simple = true; - for (int i = 0; i < d->size; ++i) { - if (d->data[i] >= 0x80) { + const QChar *p = data->constData(); + int len = data->length(); + for (int i = from; i < len; ++i) { + if (p[i].unicode() >= 0x80) { simple = false; break; } } if (simple) - return *this; + return; - QString s = *this; + QString &s = *data; if (version != CURRENT_VERSION) { for (int i = 0; i < NumNormalizationCorrections; ++i) { const NormalizationCorrection &n = uc_normalization_corrections[i]; if (n.version > version) { + int pos = from; if (n.ucs4 > 0xffff) { ushort ucs4High = QChar::highSurrogate(n.ucs4); ushort ucs4Low = QChar::lowSurrogate(n.ucs4); ushort oldHigh = QChar::highSurrogate(n.old_mapping); ushort oldLow = QChar::lowSurrogate(n.old_mapping); - int pos = 0; - while (pos < s.d->size - 1) { - if (s.d->data[pos] == ucs4High && s.d->data[pos + 1] == ucs4Low) { - s.detach(); - s.d->data[pos] = oldHigh; - s.d->data[pos + 1] = oldLow; + while (pos < s.length() - 1) { + if (s.at(pos).unicode() == ucs4High && s.at(pos + 1).unicode() == ucs4Low) { + s[pos] = oldHigh; + s[pos + 1] = oldLow; ++pos; } ++pos; } } else { - int pos = 0; - while (pos < s.d->size) { - if (s.d->data[pos] == n.ucs4) { - s.detach(); - s.d->data[pos] = n.old_mapping; + while (pos < s.length()) { + if (s.at(pos).unicode() == n.ucs4) { + s[pos] = n.old_mapping; } ++pos; } @@ -6158,15 +6087,14 @@ QString QString::normalized(QString::NormalizationForm mode, QChar::UnicodeVersi } } } - s = decomposeHelper(s, mode < QString::NormalizationForm_KD, version); + decomposeHelper(data, mode < QString::NormalizationForm_KD, version, from); - s = canonicalOrderHelper(s, version); + canonicalOrderHelper(data, version, from); if (mode == QString::NormalizationForm_D || mode == QString::NormalizationForm_KD) - return s; - - return composeHelper(s); + return; + composeHelper(data, from); } @@ -6551,7 +6479,7 @@ QString QString::arg(qlonglong a, int fieldWidth, int base, const QChar &fillCha ArgEscapeData d = findArgEscapes(*this); if (d.occurrences == 0) { - qWarning("QString::arg: Argument missing: %s, %lld", toLocal8Bit().data(), a); + qWarning() << "QString::arg: Argument missing:" << *this << ',' << a; return *this; } @@ -6594,7 +6522,7 @@ QString QString::arg(qulonglong a, int fieldWidth, int base, const QChar &fillCh ArgEscapeData d = findArgEscapes(*this); if (d.occurrences == 0) { - qWarning("QString::arg: Argument missing: %s, %llu", toLocal8Bit().data(), a); + qWarning() << "QString::arg: Argument missing:" << *this << ',' << a; return *this; } diff --git a/src/corelib/tools/qstringlist.cpp b/src/corelib/tools/qstringlist.cpp index 5a2b37a..5c550af 100644 --- a/src/corelib/tools/qstringlist.cpp +++ b/src/corelib/tools/qstringlist.cpp @@ -41,6 +41,7 @@ #include <qstringlist.h> #include <qset.h> +#include <qstringmatcher.h> QT_BEGIN_NAMESPACE diff --git a/src/corelib/tools/qstringlist.h b/src/corelib/tools/qstringlist.h index 665c0d0..f36567a 100644 --- a/src/corelib/tools/qstringlist.h +++ b/src/corelib/tools/qstringlist.h @@ -47,7 +47,6 @@ #include <QtCore/qlist.h> #include <QtCore/qregexp.h> #include <QtCore/qstring.h> -#include <QtCore/qstringmatcher.h> #ifdef QT_INCLUDE_COMPAT #include <Qt3Support/q3valuelist.h> #endif diff --git a/src/corelib/tools/qstringmatcher.h b/src/corelib/tools/qstringmatcher.h index 2b8edc9..61b7a95 100644 --- a/src/corelib/tools/qstringmatcher.h +++ b/src/corelib/tools/qstringmatcher.h @@ -81,13 +81,14 @@ private: // explicitely allow anonymous unions for RVCT to prevent compiler warnings #pragma anon_unions #endif + struct Data { + uchar q_skiptable[256]; + const QChar *uc; + int len; + }; union { uint q_data[256]; - struct { - uchar q_skiptable[256]; - const QChar *uc; - int len; - } p; + Data p; }; }; diff --git a/src/corelib/tools/qtimeline.cpp b/src/corelib/tools/qtimeline.cpp index 04aed39..e32fc03 100644 --- a/src/corelib/tools/qtimeline.cpp +++ b/src/corelib/tools/qtimeline.cpp @@ -555,6 +555,8 @@ void QTimeLine::setCurveShape(CurveShape shape) /*! \property QTimeLine::easingCurve + \since 4.6 + Specifies the easing curve that the timeline will use. If both easing curve and curveShape are set, the last set property will override the previous one. (If valueForTime() is reimplemented it will diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h index 19b8da4..51a6709 100644 --- a/src/corelib/tools/qvector.h +++ b/src/corelib/tools/qvector.h @@ -415,7 +415,9 @@ void QVector<T>::free(Data *x) { if (QTypeInfo<T>::isComplex) { T* b = x->array; - T* i = b + reinterpret_cast<QVectorData *>(x)->size; + union { QVectorData *d; Data *p; } u; + u.p = x; + T* i = b + u.d->size; while (i-- != b) i->~T(); } diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri index c93a065..08c94ac 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -5,6 +5,7 @@ HEADERS += \ tools/qbitarray.h \ tools/qbytearray.h \ tools/qbytearraymatcher.h \ + tools/qbytedata_p.h \ tools/qcache.h \ tools/qchar.h \ tools/qcontainerfwd.h \ diff --git a/src/corelib/xml/qxmlstream.cpp b/src/corelib/xml/qxmlstream.cpp index 1fc2a9f..42ed04e 100644 --- a/src/corelib/xml/qxmlstream.cpp +++ b/src/corelib/xml/qxmlstream.cpp @@ -568,7 +568,7 @@ bool QXmlStreamReader::atEnd() const returns true, hasError() returns true, and this function returns QXmlStreamReader::Invalid. - The exception is when error() return PrematureEndOfDocumentError. + The exception is when error() returns PrematureEndOfDocumentError. This error is reported when the end of an otherwise well-formed chunk of XML is reached, but the chunk doesn't represent a complete XML document. In that case, parsing \e can be resumed by calling diff --git a/src/dbus/qdbusmarshaller.cpp b/src/dbus/qdbusmarshaller.cpp index bb7fa6b..7207b4c 100644 --- a/src/dbus/qdbusmarshaller.cpp +++ b/src/dbus/qdbusmarshaller.cpp @@ -397,16 +397,6 @@ bool QDBusMarshaller::appendVariantInternal(const QVariant &arg) case DBUS_TYPE_DOUBLE: qIterAppend(&iterator, ba, *signature, arg.constData()); return true; - - case DBUS_TYPE_STRING: - case DBUS_TYPE_OBJECT_PATH: - case DBUS_TYPE_SIGNATURE: { - const QByteArray data = - reinterpret_cast<const QString *>(arg.constData())->toUtf8(); - const char *rawData = data.constData(); - qIterAppend(&iterator, ba, *signature, &rawData); - return true; - } #else case DBUS_TYPE_BYTE: append( qvariant_cast<uchar>(arg) ); @@ -435,6 +425,8 @@ bool QDBusMarshaller::appendVariantInternal(const QVariant &arg) case DBUS_TYPE_DOUBLE: append( arg.toDouble() ); return true; +#endif + case DBUS_TYPE_STRING: append( arg.toString() ); return true; @@ -444,7 +436,6 @@ bool QDBusMarshaller::appendVariantInternal(const QVariant &arg) case DBUS_TYPE_SIGNATURE: append( qvariant_cast<QDBusSignature>(arg) ); return true; -#endif // compound types: case DBUS_TYPE_VARIANT: diff --git a/src/gui/accessible/qaccessible.h b/src/gui/accessible/qaccessible.h index 19080de..8dc8159 100644 --- a/src/gui/accessible/qaccessible.h +++ b/src/gui/accessible/qaccessible.h @@ -210,6 +210,7 @@ public: PageTabList = 0x0000003C, Clock = 0x0000003D, Splitter = 0x0000003E, + // Additional Qt roles where enum value does not map directly to MSAA: LayeredPane = 0x0000003F, UserRole = 0x0000ffff }; diff --git a/src/gui/accessible/qaccessible_win.cpp b/src/gui/accessible/qaccessible_win.cpp index bfacb94..85f1a8d 100644 --- a/src/gui/accessible/qaccessible_win.cpp +++ b/src/gui/accessible/qaccessible_win.cpp @@ -1051,6 +1051,8 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accRole(VARIANT varID, VARIANT Role role = accessible->role(varID.lVal); if (role != NoRole) { + if (role == LayeredPane) + role = QAccessible::Pane; (*pvarRole).vt = VT_I4; (*pvarRole).lVal = role; } else { diff --git a/src/gui/dialogs/qfiledialog.cpp b/src/gui/dialogs/qfiledialog.cpp index 849f4b3..8b4e1b1 100644 --- a/src/gui/dialogs/qfiledialog.cpp +++ b/src/gui/dialogs/qfiledialog.cpp @@ -1604,12 +1604,7 @@ QString QFileDialog::getOpenFileName(QWidget *parent, args.parent = parent; args.caption = caption; args.directory = QFileDialogPrivate::workingDirectory(dir); - //If workingDirectory returned a different path than the initial one, - //it means that the initial path was invalid. There is no point to try select a file - if (args.directory != QFileInfo(dir).path()) - args.selection = QString(); - else - args.selection = QFileDialogPrivate::initialSelection(dir); + args.selection = QFileDialogPrivate::initialSelection(dir); args.filter = filter; args.mode = ExistingFile; args.options = options; @@ -1687,18 +1682,13 @@ QStringList QFileDialog::getOpenFileNames(QWidget *parent, QString *selectedFilter, Options options) { - if (qt_filedialog_open_filenames_hook) + if (qt_filedialog_open_filenames_hook && !(options & DontUseNativeDialog)) return qt_filedialog_open_filenames_hook(parent, caption, dir, filter, selectedFilter, options); QFileDialogArgs args; args.parent = parent; args.caption = caption; args.directory = QFileDialogPrivate::workingDirectory(dir); - //If workingDirectory returned a different path than the initial one, - //it means that the initial path was invalid. There is no point to try select a file - if (args.directory != QFileInfo(dir).path()) - args.selection = QString(); - else - args.selection = QFileDialogPrivate::initialSelection(dir); + args.selection = QFileDialogPrivate::initialSelection(dir); args.filter = filter; args.mode = ExistingFiles; args.options = options; @@ -1778,18 +1768,13 @@ QString QFileDialog::getSaveFileName(QWidget *parent, QString *selectedFilter, Options options) { - if (qt_filedialog_save_filename_hook) + if (qt_filedialog_save_filename_hook && !(options & DontUseNativeDialog)) return qt_filedialog_save_filename_hook(parent, caption, dir, filter, selectedFilter, options); QFileDialogArgs args; args.parent = parent; args.caption = caption; args.directory = QFileDialogPrivate::workingDirectory(dir); - //If workingDirectory returned a different path than the initial one, - //it means that the initial path was invalid. There is no point to try select a file - if (args.directory != QFileInfo(dir).path()) - args.selection = QString(); - else - args.selection = QFileDialogPrivate::initialSelection(dir); + args.selection = QFileDialogPrivate::initialSelection(dir); args.filter = filter; args.mode = AnyFile; args.options = options; @@ -1858,7 +1843,7 @@ QString QFileDialog::getExistingDirectory(QWidget *parent, const QString &dir, Options options) { - if (qt_filedialog_existing_directory_hook) + if (qt_filedialog_existing_directory_hook && !(options & DontUseNativeDialog)) return qt_filedialog_existing_directory_hook(parent, caption, dir, options); QFileDialogArgs args; args.parent = parent; diff --git a/src/gui/dialogs/qfiledialog_win.cpp b/src/gui/dialogs/qfiledialog_win.cpp index 6883bf9..9bf82c3 100644 --- a/src/gui/dialogs/qfiledialog_win.cpp +++ b/src/gui/dialogs/qfiledialog_win.cpp @@ -60,6 +60,13 @@ #include <shlobj.h> +#include <objbase.h> + +#if defined(__IFileDialog_INTERFACE_DEFINED__) \ + && defined(__IFileOpenDialog_INTERFACE_DEFINED__) +#define USE_COMMON_ITEM_DIALOG +#endif + #ifdef Q_WS_WINCE #include <commdlg.h> # ifndef BFFM_SETSELECTION @@ -401,14 +408,202 @@ QString qt_win_get_save_file_name(const QFileDialogArgs &args, return fi.absoluteFilePath(); } + +#if defined(USE_COMMON_ITEM_DIALOG) + +typedef HRESULT (WINAPI *PtrSHCreateItemFromParsingName)(PCWSTR pszPath, IBindCtx *pbc, REFIID riid, void **ppv); +static PtrSHCreateItemFromParsingName pSHCreateItemFromParsingName = 0; + +static bool qt_win_set_IFileDialogOptions(IFileDialog *pfd, + const QString& initialSelection, + const QString& initialDirectory, + const QString& title, + const QStringList& filterLst, + QFileDialog::FileMode mode, + QFileDialog::Options options) +{ + if (!pSHCreateItemFromParsingName) { + // This function is available only in Vista & above. + QLibrary shellLib(QLatin1String("Shell32")); + pSHCreateItemFromParsingName = (PtrSHCreateItemFromParsingName) + shellLib.resolve("SHCreateItemFromParsingName"); + if (!pSHCreateItemFromParsingName) + return false; + } + HRESULT hr; + QString winfilters; + int numFilters = 0; + quint32 currentOffset = 0; + QList<quint32> offsets; + QStringList::ConstIterator it = filterLst.begin(); + // Create the native filter string and save offset to each entry. + for (; it != filterLst.end(); ++it) { + QString subfilter = *it; + if (!subfilter.isEmpty()) { + offsets<<currentOffset; + winfilters += subfilter; // The name of the filter. + winfilters += QChar(); + currentOffset += subfilter.size()+1; + offsets<<currentOffset; + QString spec = qt_win_extract_filter(subfilter); + winfilters += spec; // The actual filter spec. + winfilters += QChar(); + currentOffset += spec.size()+1; + numFilters++; + } + } + // Add the filters to the file dialog. + if (numFilters) { + wchar_t *szData = (wchar_t*)winfilters.utf16(); + COMDLG_FILTERSPEC *filterSpec = new COMDLG_FILTERSPEC[numFilters]; + for(int i = 0; i<numFilters; i++) { + filterSpec[i].pszName = szData+offsets[i*2]; + filterSpec[i].pszSpec = szData+offsets[(i*2)+1]; + } + hr = pfd->SetFileTypes(numFilters, filterSpec); + delete []filterSpec; + } + // Set the starting folder. + tInitDir = QDir::toNativeSeparators(initialDirectory); + if (!tInitDir.isEmpty()) { + IShellItem *psiDefaultFolder; + hr = pSHCreateItemFromParsingName((wchar_t*)tInitDir.utf16(), + NULL, + IID_PPV_ARGS(&psiDefaultFolder)); + + if (SUCCEEDED(hr)) { + hr = pfd->SetFolder(psiDefaultFolder); + psiDefaultFolder->Release(); + } + } + // Set the currently selected file. + QString initSel = QDir::toNativeSeparators(initialSelection); + if (!initSel.isEmpty()) { + initSel.remove(QLatin1Char('<')); + initSel.remove(QLatin1Char('>')); + initSel.remove(QLatin1Char('\"')); + initSel.remove(QLatin1Char('|')); + } + if (!initSel.isEmpty()) { + hr = pfd->SetFileName((wchar_t*)initSel.utf16()); + } + // Set the title for the file dialog. + if (!title.isEmpty()) { + hr = pfd->SetTitle((wchar_t*)title.utf16()); + } + // Set other flags for the dialog. + DWORD newOptions; + hr = pfd->GetOptions(&newOptions); + if (SUCCEEDED(hr)) { + newOptions |= (FOS_NOCHANGEDIR | FOS_NOREADONLYRETURN); + if (mode == QFileDialog::ExistingFile || + mode == QFileDialog::ExistingFiles) + newOptions |= (FOS_FILEMUSTEXIST | FOS_PATHMUSTEXIST); + if (mode == QFileDialog::ExistingFiles) + newOptions |= FOS_ALLOWMULTISELECT; + if (!(options & QFileDialog::DontConfirmOverwrite)) + newOptions |= FOS_OVERWRITEPROMPT; + hr = pfd->SetOptions(newOptions); + } + return SUCCEEDED(hr); +} + +QStringList qt_win_CID_get_open_file_names(const QFileDialogArgs &args, + QString *initialDirectory, + const QStringList &filterList, + QString *selectedFilter, + int selectedFilterIndex) +{ + QStringList result; + QDialog modal_widget; + modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true); + modal_widget.setParent(args.parent, Qt::Window); + QApplicationPrivate::enterModal(&modal_widget); + // Multiple selection is allowed only in IFileOpenDialog. + IFileOpenDialog *pfd; + HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, + NULL, + CLSCTX_INPROC_SERVER, + IID_PPV_ARGS(&pfd)); + + if (SUCCEEDED(hr)) { + qt_win_set_IFileDialogOptions(pfd, args.selection, + args.directory, args.caption, + filterList, QFileDialog::ExistingFiles, + args.options); + // Set the currently selected filter (one-based index). + hr = pfd->SetFileTypeIndex(selectedFilterIndex+1); + QWidget *parentWindow = args.parent; + if (parentWindow) + parentWindow = parentWindow->window(); + else + parentWindow = QApplication::activeWindow(); + // Show the file dialog. + hr = pfd->Show(parentWindow ? parentWindow->winId() : 0); + if (SUCCEEDED(hr)) { + // Retrieve the results. + IShellItemArray *psiaResults; + hr = pfd->GetResults(&psiaResults); + if (SUCCEEDED(hr)) { + DWORD numItems = 0; + psiaResults->GetCount(&numItems); + for (DWORD i = 0; i<numItems; i++) { + IShellItem *psi = 0; + hr = psiaResults->GetItemAt(i, &psi); + if (SUCCEEDED(hr)) { + // Retrieve the file name from shell item. + wchar_t *pszPath; + hr = psi->GetDisplayName(SIGDN_FILESYSPATH, &pszPath); + if (SUCCEEDED(hr)) { + QString fileName = QString::fromWCharArray(pszPath); + result.append(fileName); + CoTaskMemFree(pszPath); + } + psi->Release(); // Free the current item. + } + } + psiaResults->Release(); // Free the array of items. + } + } + } + QApplicationPrivate::leaveModal(&modal_widget); + + qt_win_eatMouseMove(); + + if (!result.isEmpty()) { + // Retrieve the current folder name. + IShellItem *psi = 0; + hr = pfd->GetFolder(&psi); + if (SUCCEEDED(hr)) { + wchar_t *pszPath; + hr = psi->GetDisplayName(SIGDN_FILESYSPATH, &pszPath); + if (SUCCEEDED(hr)) { + *initialDirectory = QString::fromWCharArray(pszPath); + CoTaskMemFree(pszPath); + } + psi->Release(); + } + // Retrieve the currently selected filter. + if (selectedFilter) { + quint32 filetype = 0; + hr = pfd->GetFileTypeIndex(&filetype); + if (SUCCEEDED(hr) && filetype && filetype <= (quint32)filterList.length()) { + // This is a one-based index, not zero-based. + *selectedFilter = filterList[filetype-1]; + } + } + } + return result; +} + +#endif + QStringList qt_win_get_open_file_names(const QFileDialogArgs &args, QString *initialDirectory, QString *selectedFilter) { - QStringList result; QFileInfo fi; QDir dir; - QString isel; if (initialDirectory && initialDirectory->left(5) == QLatin1String("file:")) initialDirectory->remove(0, 5); @@ -416,7 +611,6 @@ QStringList qt_win_get_open_file_names(const QFileDialogArgs &args, if (initialDirectory && !fi.isDir()) { *initialDirectory = fi.absolutePath(); - isel = fi.fileName(); } if (!fi.exists()) @@ -424,12 +618,21 @@ QStringList qt_win_get_open_file_names(const QFileDialogArgs &args, DWORD selFilIdx = 0; + QStringList filterLst = qt_win_make_filters_list(args.filter); int idx = 0; if (selectedFilter) { - QStringList filterLst = qt_win_make_filters_list(args.filter); idx = filterLst.indexOf(*selectedFilter); } + // Windows Vista (& above) allows users to search from file dialogs. If user selects + // multiple files belonging to different folders from these search results, the + // GetOpenFileName() will return only one folder name for all the files. To retrieve + // the correct path for all selected files, we have to use Common Item Dialog interfaces. +#if defined(USE_COMMON_ITEM_DIALOG) + if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based) + return qt_win_CID_get_open_file_names(args, initialDirectory, filterLst, selectedFilter, idx); +#endif + QStringList result; QDialog modal_widget; modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true); modal_widget.setParent(args.parent, Qt::Window); diff --git a/src/gui/dialogs/qmessagebox.cpp b/src/gui/dialogs/qmessagebox.cpp index b7fa420..31f73b9 100644 --- a/src/gui/dialogs/qmessagebox.cpp +++ b/src/gui/dialogs/qmessagebox.cpp @@ -1362,8 +1362,10 @@ void QMessageBox::setVisible(bool visible) /*! \overload - Opens the dialog and connects its accepted() signal to the slot specified - by \a receiver and \a member. + Opens the dialog and connects its finished() or buttonClicked() signal to + the slot specified by \a receiver and \a member. If the slot in \a member + has a pointer for its first parameter the connection is to buttonClicked(), + otherwise the connection is to finished(). The signal will be disconnected from the slot when the dialog is closed. */ diff --git a/src/gui/dialogs/qpagesetupdialog_win.cpp b/src/gui/dialogs/qpagesetupdialog_win.cpp index a84a7ce..3f2fb34 100644 --- a/src/gui/dialogs/qpagesetupdialog_win.cpp +++ b/src/gui/dialogs/qpagesetupdialog_win.cpp @@ -78,8 +78,8 @@ int QPageSetupDialog::exec() psd.lStructSize = sizeof(PAGESETUPDLG); // we need a temp DEVMODE struct if we don't have a global DEVMODE - HGLOBAL hDevMode; - int devModeSize; + HGLOBAL hDevMode = 0; + int devModeSize = 0; if (!ep->globalDevMode) { devModeSize = sizeof(DEVMODE) + ep->devMode->dmDriverExtra; hDevMode = GlobalAlloc(GHND, devModeSize); diff --git a/src/gui/dialogs/qwizard.cpp b/src/gui/dialogs/qwizard.cpp index a7dccd8..a97aedd 100644 --- a/src/gui/dialogs/qwizard.cpp +++ b/src/gui/dialogs/qwizard.cpp @@ -343,8 +343,8 @@ void QWizardHeader::setup(const QWizardLayoutInfo &info, const QString &title, { bool modern = ((info.wizStyle == QWizard::ModernStyle) #if !defined(QT_NO_STYLE_WINDOWSVISTA) - || ((info.wizStyle == QWizard::AeroStyle) - && (QVistaHelper::vistaState() == QVistaHelper::Classic) || vistaDisabled()) + || ((info.wizStyle == QWizard::AeroStyle + && QVistaHelper::vistaState() == QVistaHelper::Classic) || vistaDisabled()) #endif ); diff --git a/src/gui/dialogs/qwizard_win.cpp b/src/gui/dialogs/qwizard_win.cpp index 840149b..1def47f 100644 --- a/src/gui/dialogs/qwizard_win.cpp +++ b/src/gui/dialogs/qwizard_win.cpp @@ -616,7 +616,7 @@ bool QVistaHelper::drawTitleText(QPainter *painter, const QString &text, const Q // Set up a memory DC and bitmap that we'll draw into HDC dcMem; HBITMAP bmp; - BITMAPINFO dib = {0}; + BITMAPINFO dib = {{0}}; dcMem = CreateCompatibleDC(hdc); dib.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); @@ -662,7 +662,7 @@ bool QVistaHelper::drawBlackRect(const QRect &rect, HDC hdc) // Set up a memory DC and bitmap that we'll draw into HDC dcMem; HBITMAP bmp; - BITMAPINFO dib = {0}; + BITMAPINFO dib = {{0}}; dcMem = CreateCompatibleDC(hdc); dib.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); diff --git a/src/gui/embedded/qscreenproxy_qws.cpp b/src/gui/embedded/qscreenproxy_qws.cpp index ade16ca..3d7451b 100644 --- a/src/gui/embedded/qscreenproxy_qws.cpp +++ b/src/gui/embedded/qscreenproxy_qws.cpp @@ -537,7 +537,7 @@ int QProxyScreen::transformOrientation() const } /*! -\reimp +\internal */ int QProxyScreen::memoryNeeded(const QString &str) { @@ -548,7 +548,7 @@ int QProxyScreen::memoryNeeded(const QString &str) } /*! -\reimp +\internal */ int QProxyScreen::sharedRamSize(void *ptr) { @@ -559,7 +559,7 @@ int QProxyScreen::sharedRamSize(void *ptr) } /*! -\reimp +\internal */ void QProxyScreen::haltUpdates() { @@ -568,7 +568,7 @@ void QProxyScreen::haltUpdates() } /*! -\reimp +\internal */ void QProxyScreen::resumeUpdates() { diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 638f20f..37c034a 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -1274,7 +1274,7 @@ QGraphicsItem *QGraphicsItem::topLevelItem() const } /*! - \since 4.4 + \since 4.6 Returns a pointer to the item's parent, cast to a QGraphicsObject. returns 0 if the parent item is not a QGraphicsObject. @@ -2346,8 +2346,8 @@ void QGraphicsItem::setAcceptsHoverEvents(bool enabled) /*! \since 4.6 - Returns true if an item accepts touch events (QTouchEvent); otherwise, returns false. By - default, items do not accept touch events. + Returns true if an item accepts \l{QTouchEvent}{touch events}; + otherwise, returns false. By default, items do not accept touch events. \sa setAcceptTouchEvents() */ @@ -2359,7 +2359,7 @@ bool QGraphicsItem::acceptTouchEvents() const /*! \since 4.6 - If \a enabled is true, this item will accept touch events; + If \a enabled is true, this item will accept \l{QTouchEvent}{touch events}; otherwise, it will ignore them. By default, items do not accept touch events. */ @@ -2375,6 +2375,8 @@ void QGraphicsItem::setAcceptTouchEvents(bool enabled) } /*! + \since 4.6 + Returns true if this item filters child events (i.e., all events intended for any of its children are instead sent to this item); otherwise, false is returned. @@ -2389,13 +2391,15 @@ bool QGraphicsItem::filtersChildEvents() const } /*! + \since 4.6 + If \a enabled is true, this item is set to filter all events for all its children (i.e., all events intented for any of its children are instead sent to this item); otherwise, if \a enabled is false, this item will only handle its own events. The default value is false. - \sa filtersChildEvents() + \sa filtersChildEvents() */ void QGraphicsItem::setFiltersChildEvents(bool enabled) { @@ -2675,10 +2679,12 @@ QPointF QGraphicsItem::pos() const */ /*! - Set's the \a x coordinate of the item's position. Equivalent to - calling setPos(x, y()). + \since 4.6 + + Set's the \a x coordinate of the item's position. Equivalent to + calling setPos(x, y()). - \sa x(), setPos() + \sa x(), setPos() */ void QGraphicsItem::setX(qreal x) { @@ -2694,10 +2700,12 @@ void QGraphicsItem::setX(qreal x) */ /*! - Set's the \a y coordinate of the item's position. Equivalent to - calling setPos(x(), y). + \since 4.6 - \sa x(), setPos() + Set's the \a y coordinate of the item's position. Equivalent to + calling setPos(x(), y). + + \sa x(), setPos() */ void QGraphicsItem::setY(qreal y) { @@ -3195,7 +3203,7 @@ void QGraphicsItem::setShear(qreal sh, qreal sv) /*! \since 4.6 - Returns the origin point used for transformation in item coordinate. + Returns the origin point for the transformation in item coordinates. The default is QPointF(0,0). @@ -3211,7 +3219,7 @@ QPointF QGraphicsItem::transformOrigin() const /*! \since 4.6 - Sets the \a origin for transformation in item coordinate + Sets the \a origin point for the transformation in item coordinates. \sa transformOrigin(), {Transformations} */ @@ -3232,9 +3240,9 @@ void QGraphicsItem::setTransformOrigin(const QPointF &origin) \since 4.6 \overload - Sets the origin for the transformation to the point - composed of \a x and \a y. - + Sets the origin point for the transformation in item coordinates. + This is equivalent to calling setTransformOrigin(QPointF(\a x, \a y)). + \sa setTransformOrigin(), {Transformations} */ diff --git a/src/gui/graphicsview/qgraphicslayoutitem.cpp b/src/gui/graphicsview/qgraphicslayoutitem.cpp index 656af33..e280162 100644 --- a/src/gui/graphicsview/qgraphicslayoutitem.cpp +++ b/src/gui/graphicsview/qgraphicslayoutitem.cpp @@ -808,6 +808,8 @@ bool QGraphicsLayoutItem::isLayout() const } /*! + \since 4.6 + Returns whether a layout should delete this item in its destructor. If its true, then the layout will delete it. If its false, then it is assumed that another object has the ownership of it, and the layout won't @@ -834,6 +836,8 @@ bool QGraphicsLayoutItem::ownedByLayout() const return d_func()->ownedByLayout; } /*! + \since 4.6 + Sets whether a layout should delete this item in its destructor or not. \a ownership must be true to in order for the layout to delete it. \sa ownedByLayout() diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 6488265..8eb21a3 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -1587,10 +1587,16 @@ QList<QGraphicsItem *> QGraphicsScene::items(Qt::SortOrder order) const } /*! + \obsolete + Returns all visible items at position \a pos in the scene. The items are listed in descending stacking order (i.e., the first item in the list is the top-most item, and the last item is the bottom-most item). + This function is deprecated and returns incorrect results if the scene + contains items that ignore transformations. Use the overload that takes + a QTransform instead. + \sa itemAt() */ QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos) const @@ -1600,9 +1606,8 @@ QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos) const } /*! - \fn QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rectangle, Qt::ItemSelectionMode mode) const - \overload + \obsolete Returns all visible items that, depending on \a mode, are either inside or intersect with the specified \a rectangle. @@ -1610,23 +1615,47 @@ QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos) const The default value for \a mode is Qt::IntersectsItemShape; all items whose exact shape intersects with or is contained by \a rectangle are returned. + This function is deprecated and returns incorrect results if the scene + contains items that ignore transformations. Use the overload that takes + a QTransform instead. + \sa itemAt() */ -QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rect, Qt::ItemSelectionMode mode) const +QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rectangle, Qt::ItemSelectionMode mode) const { Q_D(const QGraphicsScene); - return d->index->items(rect, mode, Qt::AscendingOrder); + return d->index->items(rectangle, mode, Qt::AscendingOrder); } /*! \fn QList<QGraphicsItem *> QGraphicsScene::items(qreal x, qreal y, qreal w, qreal h, Qt::ItemSelectionMode mode) const + \obsolete \since 4.3 This convenience function is equivalent to calling items(QRectF(\a x, \a y, \a w, \a h), \a mode). + + This function is deprecated and returns incorrect results if the scene + contains items that ignore transformations. Use the overload that takes + a QTransform instead. +*/ + +/*! + \fn QList<QGraphicsItem *> QGraphicsScene::items(qreal x, qreal y, qreal w, qreal h, + Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const + \overload + \since 4.6 + + Returns all visible items that, depending on \a mode, are either inside or + intersect with the rectangle defined by \a x, \a y, \a w and \a h, in a list + sorted using \a order. + + \a deviceTransform is the transformation that applies to the view, and needs to + be provided if the scene contains items that ignore transformations. */ /*! \overload + \obsolete Returns all visible items that, depending on \a mode, are either inside or intersect with the polygon \a polygon. @@ -1634,6 +1663,10 @@ QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rect, Qt::ItemSelecti The default value for \a mode is Qt::IntersectsItemShape; all items whose exact shape intersects with or is contained by \a polygon are returned. + This function is deprecated and returns incorrect results if the scene + contains items that ignore transformations. Use the overload that takes + a QTransform instead. + \sa itemAt() */ QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode) const @@ -1644,6 +1677,7 @@ QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemS /*! \overload + \obsolete Returns all visible items that, depending on \a path, are either inside or intersect with the path \a path. @@ -1651,6 +1685,10 @@ QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemS The default value for \a mode is Qt::IntersectsItemShape; all items whose exact shape intersects with or is contained by \a path are returned. + This function is deprecated and returns incorrect results if the scene + contains items that ignore transformations. Use the overload that takes + a QTransform instead. + \sa itemAt() */ QList<QGraphicsItem *> QGraphicsScene::items(const QPainterPath &path, Qt::ItemSelectionMode mode) const @@ -1660,13 +1698,16 @@ QList<QGraphicsItem *> QGraphicsScene::items(const QPainterPath &path, Qt::ItemS } /*! + \since 4.6 + Returns all visible items that, depending on \a mode, are at the specified \a pos - and return a list sorted using \a order. + in a list sorted using \a order. The default value for \a mode is Qt::IntersectsItemShape; all items whose exact shape intersects with \a pos are returned. - \a deviceTransform is the transformation apply to the view. + \a deviceTransform is the transformation that applies to the view, and needs to + be provided if the scene contains items that ignore transformations. \sa itemAt() */ @@ -1679,6 +1720,7 @@ QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos, Qt::ItemSelecti /*! \overload + \since 4.6 Returns all visible items that, depending on \a mode, are either inside or intersect with the specified \a rect and return a list sorted using \a order. @@ -1686,7 +1728,8 @@ QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos, Qt::ItemSelecti The default value for \a mode is Qt::IntersectsItemShape; all items whose exact shape intersects with or is contained by \a rect are returned. - \a deviceTransform is the transformation apply to the view. + \a deviceTransform is the transformation that applies to the view, and needs to + be provided if the scene contains items that ignore transformations. \sa itemAt() */ @@ -1699,6 +1742,7 @@ QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rect, Qt::ItemSelecti /*! \overload + \since 4.6 Returns all visible items that, depending on \a mode, are either inside or intersect with the specified \a polygon and return a list sorted using \a order. @@ -1706,7 +1750,8 @@ QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rect, Qt::ItemSelecti The default value for \a mode is Qt::IntersectsItemShape; all items whose exact shape intersects with or is contained by \a polygon are returned. - \a deviceTransform is the transformation apply to the view. + \a deviceTransform is the transformation that applies to the view, and needs to + be provided if the scene contains items that ignore transformations. \sa itemAt() */ @@ -1718,7 +1763,8 @@ QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemS } /*! - \overload + \overload + \since 4.6 Returns all visible items that, depending on \a mode, are either inside or intersect with the specified \a path and return a list sorted using \a order. @@ -1726,7 +1772,8 @@ QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemS The default value for \a mode is Qt::IntersectsItemShape; all items whose exact shape intersects with or is contained by \a path are returned. - \a deviceTransform is the transformation apply to the view. + \a deviceTransform is the transformation that applies to the view, and needs to + be provided if the scene contains items that ignore transformations. \sa itemAt() */ @@ -1767,31 +1814,67 @@ QList<QGraphicsItem *> QGraphicsScene::collidingItems(const QGraphicsItem *item, } /*! - \fn QGraphicsItem *QGraphicsScene::itemAt(const QPointF &position) const + \overload + \obsolete Returns the topmost visible item at the specified \a position, or 0 if there are no items at this position. \note The topmost item is the one with the highest Z-value. + This function is deprecated and returns incorrect results if the scene + contains items that ignore transformations. Use the overload that takes + a QTransform instead. + \sa items(), collidingItems(), QGraphicsItem::setZValue() */ -QGraphicsItem *QGraphicsScene::itemAt(const QPointF &pos) const +QGraphicsItem *QGraphicsScene::itemAt(const QPointF &position) const { - QList<QGraphicsItem *> itemsAtPoint = items(pos); + QList<QGraphicsItem *> itemsAtPoint = items(position); return itemsAtPoint.isEmpty() ? 0 : itemsAtPoint.first(); } -QGraphicsItem *QGraphicsScene::itemAt(const QPointF &pos, const QTransform &deviceTransform) const +/*! + \since 4.6 + + Returns the topmost visible item at the specified \a position, or 0 + if there are no items at this position. + + \a deviceTransform is the transformation that applies to the view, and needs to + be provided if the scene contains items that ignore transformations. + + \note The topmost item is the one with the highest Z-value. + + \sa items(), collidingItems(), QGraphicsItem::setZValue() + */ +QGraphicsItem *QGraphicsScene::itemAt(const QPointF &position, const QTransform &deviceTransform) const { - QList<QGraphicsItem *> itemsAtPoint = items(pos, Qt::IntersectsItemShape, + QList<QGraphicsItem *> itemsAtPoint = items(position, Qt::IntersectsItemShape, Qt::AscendingOrder, deviceTransform); return itemsAtPoint.isEmpty() ? 0 : itemsAtPoint.first(); } /*! + \fn QGraphicsScene::itemAt(qreal x, qreal y, const QTransform &deviceTransform) const + \overload + \since 4.6 + + Returns the topmost item at the position specified by (\a x, \a + y), or 0 if there are no items at this position. + + \a deviceTransform is the transformation that applies to the view, and needs to + be provided if the scene contains items that ignore transformations. + + This convenience function is equivalent to calling \c + {itemAt(QPointF(x, y), deviceTransform)}. + + \note The topmost item is the one with the highest Z-value. +*/ + +/*! \fn QGraphicsScene::itemAt(qreal x, qreal y) const \overload + \obsolete Returns the topmost item at the position specified by (\a x, \a y), or 0 if there are no items at this position. @@ -1799,6 +1882,10 @@ QGraphicsItem *QGraphicsScene::itemAt(const QPointF &pos, const QTransform &devi This convenience function is equivalent to calling \c {itemAt(QPointF(x, y))}. + This function is deprecated and returns incorrect results if the scene + contains items that ignore transformations. Use the overload that takes + a QTransform instead. + \note The topmost item is the one with the highest Z-value. */ @@ -1839,21 +1926,42 @@ QPainterPath QGraphicsScene::selectionArea() const } /*! + \since 4.6 + Sets the selection area to \a path. All items within this area are immediately selected, and all items outside are unselected. You can get the list of all selected items by calling selectedItems(). + \a deviceTransform is the transformation that applies to the view, and needs to + be provided if the scene contains items that ignore transformations. + For an item to be selected, it must be marked as \e selectable (QGraphicsItem::ItemIsSelectable). \sa clearSelection(), selectionArea() */ +void QGraphicsScene::setSelectionArea(const QPainterPath &path, const QTransform &deviceTransform) +{ + setSelectionArea(path, Qt::IntersectsItemShape, deviceTransform); +} + +/*! + \obsolete + \overload + + Sets the selection area to \a path. + + This function is deprecated and leads to incorrect results if the scene + contains items that ignore transformations. Use the overload that takes + a QTransform instead. +*/ void QGraphicsScene::setSelectionArea(const QPainterPath &path) { - setSelectionArea(path, Qt::IntersectsItemShape); + setSelectionArea(path, Qt::IntersectsItemShape, QTransform()); } /*! + \obsolete \overload \since 4.3 @@ -1869,11 +1977,14 @@ void QGraphicsScene::setSelectionArea(const QPainterPath &path, Qt::ItemSelectio /*! \overload - \since 4.3 + \since 4.6 Sets the selection area to \a path using \a mode to determine if items are included in the selection area. + \a deviceTransform is the transformation that applies to the view, and needs to + be provided if the scene contains items that ignore transformations. + \sa clearSelection(), selectionArea() */ void QGraphicsScene::setSelectionArea(const QPainterPath &path, Qt::ItemSelectionMode mode, @@ -2665,13 +2776,17 @@ void QGraphicsScene::clearFocus() /*! \property QGraphicsScene::stickyFocus - \brief whether or not clicking the scene will clear focus + \brief whether clicking into the scene background will clear focus + + \since 4.6 + + In a QGraphicsScene with stickyFocus set to true, focus will remain + unchanged when the user clicks into the scene background or on an item + that does not accept focus. Otherwise, focus will be cleared. - If this property is false (the default), then clicking on the scene - background or on an item that does not accept focus, will clear - focus. Otherwise, focus will remain unchanged. + By default, this property is false. - The focus change happens in response to a mouse press. You can reimplement + Focus changes in response to a mouse press. You can reimplement mousePressEvent() in a subclass of QGraphicsScene to toggle this property based on where the user has clicked. diff --git a/src/gui/graphicsview/qgraphicsscene.h b/src/gui/graphicsview/qgraphicsscene.h index e599652..2fe58b9 100644 --- a/src/gui/graphicsview/qgraphicsscene.h +++ b/src/gui/graphicsview/qgraphicsscene.h @@ -182,8 +182,9 @@ public: QList<QGraphicsItem *> selectedItems() const; QPainterPath selectionArea() const; - void setSelectionArea(const QPainterPath &path); - void setSelectionArea(const QPainterPath &path, Qt::ItemSelectionMode mode); + void setSelectionArea(const QPainterPath &path); // ### obsolete + void setSelectionArea(const QPainterPath &path, const QTransform &deviceTransform); + void setSelectionArea(const QPainterPath &path, Qt::ItemSelectionMode mode); // ### obsolete void setSelectionArea(const QPainterPath &path, Qt::ItemSelectionMode mode, const QTransform &deviceTransform); QGraphicsItemGroup *createItemGroup(const QList<QGraphicsItem *> &items); diff --git a/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp b/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp index a54ade9..3cb33d1 100644 --- a/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp +++ b/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp @@ -34,7 +34,7 @@ ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. +** contact the sales department at http://www.qtsoftware.com/contact. ** $QT_END_LICENSE$ ** ****************************************************************************/ @@ -75,6 +75,8 @@ \sa QGraphicsScene, QGraphicsView, QGraphicsSceneIndex */ +#include <QtCore/qglobal.h> + #ifndef QT_NO_GRAPHICSVIEW #include <private/qgraphicsscene_p.h> @@ -542,6 +544,7 @@ void QGraphicsSceneBspTreeIndex::clear() d->indexedItems.clear(); d->unindexedItems.clear(); d->untransformableItems.clear(); + d->regenerateIndex = true; } /*! diff --git a/src/gui/graphicsview/qgraphicsscenebsptreeindex_p.h b/src/gui/graphicsview/qgraphicsscenebsptreeindex_p.h index 2e02458..2293a8e 100644 --- a/src/gui/graphicsview/qgraphicsscenebsptreeindex_p.h +++ b/src/gui/graphicsview/qgraphicsscenebsptreeindex_p.h @@ -1,9 +1,9 @@ /**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) +** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the QtGui module of the Qt Toolkit. +** This file is part of the QtCore module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage @@ -34,7 +34,7 @@ ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. +** contact the sales department at http://www.qtsoftware.com/contact. ** $QT_END_LICENSE$ ** ****************************************************************************/ @@ -53,11 +53,7 @@ #ifndef QGRAPHICSBSPTREEINDEX_H #define QGRAPHICSBSPTREEINDEX_H -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Gui) +#include <QtCore/qglobal.h> #if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW @@ -65,10 +61,11 @@ QT_MODULE(Gui) #include "qgraphicsitem_p.h" #include "qgraphicsscene_bsp_p.h" -#include <QtCore/qglobal.h> #include <QtCore/qrect.h> #include <QtCore/qlist.h> +QT_BEGIN_NAMESPACE + static const int QGRAPHICSSCENE_INDEXTIMER_TIMEOUT = 2000; class QGraphicsScene; @@ -204,10 +201,8 @@ static inline bool QRectF_intersects(const QRectF &s, const QRectF &r) return !(t1 >= b2 || t2 >= b1); } -#endif // QT_NO_GRAPHICSVIEW - QT_END_NAMESPACE -QT_END_HEADER +#endif // QT_NO_GRAPHICSVIEW #endif // QGRAPHICSBSPTREEINDEX_H diff --git a/src/gui/graphicsview/qgraphicssceneindex.cpp b/src/gui/graphicsview/qgraphicssceneindex.cpp index 01efde4..ab5ca85 100644 --- a/src/gui/graphicsview/qgraphicssceneindex.cpp +++ b/src/gui/graphicsview/qgraphicssceneindex.cpp @@ -34,7 +34,7 @@ ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. +** contact the sales department at http://www.qtsoftware.com/contact. ** $QT_END_LICENSE$ ** ****************************************************************************/ @@ -553,20 +553,9 @@ QList<QGraphicsItem *> QGraphicsSceneIndex::estimateTopLevelItems(const QRectF & } /*! - \fn virtual QList<QGraphicsItem *> - QGraphicsSceneIndex::estimateItems(const QRectF &rect, Qt::SortOrder - order, const QTransform &deviceTransform) const = 0 - - This pure virtual function return an estimation of items in the \a rect. - This method return a list sorted using \a order. - - \a deviceTransform is the transformation apply to the view. -*/ - -/*! - \fn virtual QList<QGraphicsItem *> - QGraphicsSceneIndex::items(Qt::SortOrder order = Qt::AscendingOrder) const - = 0; This pure virtual function all items in the index and sort them using + \fn QList<QGraphicsItem *> QGraphicsSceneIndex::items(Qt::SortOrder order = Qt::AscendingOrder) const + + This pure virtual function all items in the index and sort them using \a order. */ diff --git a/src/gui/graphicsview/qgraphicssceneindex_p.h b/src/gui/graphicsview/qgraphicssceneindex_p.h index 8cf0294..37dffb8 100644 --- a/src/gui/graphicsview/qgraphicssceneindex_p.h +++ b/src/gui/graphicsview/qgraphicssceneindex_p.h @@ -1,9 +1,9 @@ /**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) +** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the QtGui module of the Qt Toolkit. +** This file is part of the QtCore module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage @@ -34,7 +34,7 @@ ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. +** contact the sales department at http://www.qtsoftware.com/contact. ** $QT_END_LICENSE$ ** ****************************************************************************/ diff --git a/src/gui/graphicsview/qgraphicsscenelinearindex.cpp b/src/gui/graphicsview/qgraphicsscenelinearindex.cpp index 5e6ac30..52bbc79 100644 --- a/src/gui/graphicsview/qgraphicsscenelinearindex.cpp +++ b/src/gui/graphicsview/qgraphicsscenelinearindex.cpp @@ -1,11 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + /*! \class QGraphicsSceneLinearIndex \brief The QGraphicsSceneLinearIndex class provides an implementation of a linear indexing algorithm for discovering items in QGraphicsScene. \since 4.6 - \ingroup multimedia \ingroup graphicsview-api - \mainclass \internal QGraphicsSceneLinearIndex index is default linear implementation to discover items. @@ -30,32 +69,26 @@ /*! - \fn virtual QList<QGraphicsItem *> QGraphicsSceneLinearIndex::estimateItems(const QRectF &rect, Qt::SortOrder order) const; + \fn virtual QList<QGraphicsItem *> QGraphicsSceneLinearIndex::estimateItems(const QRectF &rect, Qt::SortOrder order) const Returns an estimation visible items that are either inside or intersect with the specified \a rect and return a list sorted using \a order. */ /*! - \fn QRectF QGraphicsSceneLinearIndex::indexedRect() const; - \reimp - Return the rect indexed by the the index. -*/ - -/*! - \fn void QGraphicsSceneLinearIndex::clear(); - \reimp + \fn void QGraphicsSceneLinearIndex::clear() + \internal Clear the all the BSP index. */ /*! - \fn virtual void QGraphicsSceneLinearIndex::addItem(QGraphicsItem *item); + \fn virtual void QGraphicsSceneLinearIndex::addItem(QGraphicsItem *item) Add the \a item into the index. */ /*! - \fn virtual void QGraphicsSceneLinearIndex::removeItem(QGraphicsItem *item); + \fn virtual void QGraphicsSceneLinearIndex::removeItem(QGraphicsItem *item) Add the \a item from the index. */ diff --git a/src/gui/graphicsview/qgraphicsscenelinearindex_p.h b/src/gui/graphicsview/qgraphicsscenelinearindex_p.h index 56dde3a..1f3d58b 100644 --- a/src/gui/graphicsview/qgraphicsscenelinearindex_p.h +++ b/src/gui/graphicsview/qgraphicsscenelinearindex_p.h @@ -1,9 +1,9 @@ /**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) +** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the QtGui module of the Qt Toolkit. +** This file is part of the QtCore module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage @@ -34,7 +34,7 @@ ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. +** contact the sales department at http://www.qtsoftware.com/contact. ** $QT_END_LICENSE$ ** ****************************************************************************/ @@ -53,13 +53,7 @@ // We mean it. // -#include <QtCore/qlist.h> - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Gui) +#include <QtCore/qglobal.h> #if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW @@ -68,6 +62,12 @@ QT_MODULE(Gui) #include <QtGui/qgraphicsitem.h> #include <private/qgraphicssceneindex_p.h> +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + class Q_AUTOTEST_EXPORT QGraphicsSceneLinearIndex : public QGraphicsSceneIndex { Q_OBJECT diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 1cea8db..53b044c 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -3129,7 +3129,7 @@ void QGraphicsView::mouseReleaseEvent(QMouseEvent *event) } } else #endif - if (d->dragMode == QGraphicsView::ScrollHandDrag) { + if (d->dragMode == QGraphicsView::ScrollHandDrag && event->button() == Qt::LeftButton) { #ifndef QT_NO_CURSOR // Restore the open hand cursor. ### There might be items // under the mouse that have a valid cursor at this time, so @@ -3552,6 +3552,8 @@ QTransform QGraphicsView::viewportTransform() const } /*! + \since 4.6 + Returns true if the view is transformed (i.e., a non-identity transform has been assigned, or the scrollbars are adjusted). diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index fa1ce29..7d7dde1 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -612,9 +612,6 @@ bool QImageData::checkForAlphaPixels() const \table \header \o Function \o Description \row - \o setAlphaChannel() - \o Sets the alpha channel of the image. - \row \o setDotsPerMeterX() \o Defines the aspect ratio by setting the number of pixels that fit horizontally in a physical meter. @@ -5269,7 +5266,7 @@ QPaintEngine *QImage::paintEngine() const /*! - \reimp + \internal Returns the size for the specified \a metric on the device. */ @@ -5587,7 +5584,7 @@ bool QImage::isDetached() const Note that the image will be converted to the Format_ARGB32_Premultiplied format if the function succeeds. - Use one of the composition mods in QPainter::CompositionMode instead. + Use one of the composition modes in QPainter::CompositionMode instead. \warning This function is expensive. @@ -5665,6 +5662,8 @@ void QImage::setAlphaChannel(const QImage &alphaChannel) /*! + \obsolete + Returns the alpha channel of the image as a new grayscale QImage in which each pixel's red, green, and blue values are given the alpha value of the original image. The color depth of the returned image is 8-bit. @@ -5744,7 +5743,7 @@ QImage QImage::alphaChannel() const Returns true if the image has a format that respects the alpha channel, otherwise returns false. - \sa alphaChannel(), {QImage#Image Information}{Image Information} + \sa {QImage#Image Information}{Image Information} */ bool QImage::hasAlphaChannel() const { diff --git a/src/gui/image/qpicture.cpp b/src/gui/image/qpicture.cpp index 874de81..ea1392b 100644 --- a/src/gui/image/qpicture.cpp +++ b/src/gui/image/qpicture.cpp @@ -954,6 +954,8 @@ bool QPicture::exec(QPainter *painter, QDataStream &s, int nrecords) } /*! + \internal + Internal implementation of the virtual QPaintDevice::metric() function. diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp index 61be832..3e5c9b7 100644 --- a/src/gui/image/qpixmap.cpp +++ b/src/gui/image/qpixmap.cpp @@ -380,6 +380,7 @@ QPixmap QPixmap::copy(const QRect &rect) const /*! \fn QPixmap::scroll(int dx, int dy, int x, int y, int width, int height, QRegion *exposed) + \since 4.6 This convenience function is equivalent to calling QPixmap::scroll(\a dx, \a dy, QRect(\a x, \a y, \a width, \a height), \a exposed). @@ -388,6 +389,8 @@ QPixmap QPixmap::copy(const QRect &rect) const */ /*! + \since 4.6 + Scrolls the area \a rect of this pixmap by (\a dx, \a dy). The exposed region is left unchanged. You can optionally pass a pointer to an empty QRegion to get the region that is \a exposed by the scroll operation. @@ -1569,24 +1572,24 @@ QPixmap QPixmap::transformed(const QMatrix &matrix, Qt::TransformationMode mode) designed and optimized for showing images on screen. QBitmap is only a convenience class that inherits QPixmap, ensuring a depth of 1. The isQBitmap() function returns true if a QPixmap object is - really a bitmap, otherwise returns false. Finally, the QPicture class is a - paint device that records and replays QPainter commands. + really a bitmap, otherwise returns false. Finally, the QPicture class + is a paint device that records and replays QPainter commands. A QPixmap can easily be displayed on the screen using QLabel or one of QAbstractButton's subclasses (such as QPushButton and QToolButton). QLabel has a pixmap property, whereas - QAbstractButton has an icon property. And because QPixmap is a - QPaintDevice subclass, QPainter can be used to draw directly onto - pixmaps. + QAbstractButton has an icon property. In addition to the ordinary constructors, a QPixmap can be constructed using the static grabWidget() and grabWindow() functions which creates a QPixmap and paints the given widget, or - window, in it. + window, into it. + + QPixmap objects can be passed around by value since the QPixmap + class uses implicit data sharing. For more information, see the \l + {Implicit Data Sharing} documentation. QPixmap objects can also be + streamed. - Note that the pixel data in a pixmap is internal and is managed by - the underlying window system. Pixels can only be accessed through - QPainter functions or by converting the QPixmap to a QImage. Depending on the system, QPixmap is stored using a RGB32 or a premultiplied alpha format. If the image has an alpha channel, and if the system allows, the preferred format is premultiplied alpha. @@ -1597,6 +1600,13 @@ QPixmap QPixmap::transformed(const QMatrix &matrix, Qt::TransformationMode mode) QPixmap are stored on the client side and don't use any GDI resources). + Note that the pixel data in a pixmap is internal and is managed by + the underlying window system. Because QPixmap is a QPaintDevice + subclass, QPainter can be used to draw directly onto pixmaps. + Pixels can only be accessed through QPainter functions or by + converting the QPixmap to a QImage. However, the fill() function + is available for initializing the entire pixmap with a given color. + There are functions to convert between QImage and QPixmap. Typically, the QImage class is used to load an image file, optionally manipulating the image data, before the QImage @@ -1611,11 +1621,6 @@ QPixmap QPixmap::transformed(const QMatrix &matrix, Qt::TransformationMode mode) there are several functions that enables transformation of the pixmap. - QPixmap objects can be passed around by value since the QPixmap - class uses implicit data sharing. For more information, see the \l - {Implicit Data Sharing} documentation. QPixmap objects can also be - streamed. - \tableofcontents \section1 Reading and Writing Image Files @@ -1672,12 +1677,15 @@ QPixmap QPixmap::transformed(const QMatrix &matrix, Qt::TransformationMode mode) The hasAlphaChannel() returns true if the pixmap has a format that respects the alpha channel, otherwise returns false, while the hasAlpha() function returns true if the pixmap has an alpha - channel \e or a mask (otherwise false). + channel \e or a mask (otherwise false). The mask() function returns + the mask as a QBitmap object, which can be set using setMask(). - The alphaChannel() function returns the alpha channel as a new - QPixmap object, while the mask() function returns the mask as a - QBitmap object. The alpha channel and mask can be set using the - setAlphaChannel() and setMask() functions, respectively. + The createHeuristicMask() function creates and returns a 1-bpp + heuristic mask (i.e. a QBitmap) for this pixmap. It works by + selecting a color from one of the corners and then chipping away + pixels of that color, starting at all the edges. The + createMaskFromColor() function creates and returns a mask (i.e. a + QBitmap) for the pixmap based on a given color. \row \o Low-level information @@ -1715,14 +1723,7 @@ QPixmap QPixmap::transformed(const QMatrix &matrix, Qt::TransformationMode mode) \section1 Pixmap Transformations QPixmap supports a number of functions for creating a new pixmap - that is a transformed version of the original: The - createHeuristicMask() function creates and returns a 1-bpp - heuristic mask (i.e. a QBitmap) for this pixmap. It works by - selecting a color from one of the corners and then chipping away - pixels of that color, starting at all the edges. The - createMaskFromColor() function creates and returns a mask (i.e. a - QBitmap) for the pixmap based on a given color. - + that is a transformed version of the original: The scaled(), scaledToWidth() and scaledToHeight() functions return scaled copies of the pixmap, while the copy() function @@ -1737,11 +1738,6 @@ QPixmap QPixmap::transformed(const QMatrix &matrix, Qt::TransformationMode mode) function returns the actual matrix used for transforming the pixmap. - There are also functions for changing attributes of a pixmap. - in-place: The fill() function fills the entire image with the - given color, the setMask() function sets a mask bitmap, and the - setAlphaChannel() function sets the pixmap's alpha channel. - \sa QBitmap, QImage, QImageReader, QImageWriter */ @@ -1760,7 +1756,7 @@ QPixmap QPixmap::transformed(const QMatrix &matrix, Qt::TransformationMode mode) Returns true if this pixmap has an alpha channel, \e or has a mask, otherwise returns false. - \sa hasAlphaChannel(), alphaChannel(), mask() + \sa hasAlphaChannel(), mask() */ bool QPixmap::hasAlpha() const { @@ -1771,7 +1767,7 @@ bool QPixmap::hasAlpha() const Returns true if the pixmap has a format that respects the alpha channel, otherwise returns false. - \sa alphaChannel(), hasAlpha() + \sa hasAlpha() */ bool QPixmap::hasAlphaChannel() const { @@ -1779,7 +1775,7 @@ bool QPixmap::hasAlphaChannel() const } /*! - \reimp + \internal */ int QPixmap::metric(PaintDeviceMetric metric) const { @@ -1788,6 +1784,7 @@ int QPixmap::metric(PaintDeviceMetric metric) const /*! \fn void QPixmap::setAlphaChannel(const QPixmap &alphaChannel) + \obsolete Sets the alpha channel of this pixmap to the given \a alphaChannel by converting the \a alphaChannel into 32 bit and using the @@ -1825,6 +1822,8 @@ void QPixmap::setAlphaChannel(const QPixmap &alphaChannel) } /*! + \obsolete + Returns the alpha channel of the pixmap as a new grayscale QPixmap in which each pixel's red, green, and blue values are given the alpha value of the original pixmap. The color depth of the returned pixmap is the system depth @@ -1843,7 +1842,9 @@ void QPixmap::setAlphaChannel(const QPixmap &alphaChannel) \image alphachannelimage.png The pixmap and channelImage QPixmaps \warning This is an expensive operation. The alpha channel of the - pixmap is extracted dynamically from the pixeldata. + pixmap is extracted dynamically from the pixeldata. Most usecases of this + function are covered by QPainter and compositionModes which will normally + execute faster. \sa setAlphaChannel(), {QPixmap#Pixmap Information}{Pixmap Information} @@ -1854,7 +1855,7 @@ QPixmap QPixmap::alphaChannel() const } /*! - \reimp + \internal */ QPaintEngine *QPixmap::paintEngine() const { @@ -1864,7 +1865,7 @@ QPaintEngine *QPixmap::paintEngine() const /*! \fn QBitmap QPixmap::mask() const - Extracts a bitmap mask from the pixmap's alphachannel. + Extracts a bitmap mask from the pixmap's alpha channel. \warning This is potentially an expensive operation. The mask of the pixmap is extracted dynamically from the pixeldata. diff --git a/src/gui/image/qpixmap_mac.cpp b/src/gui/image/qpixmap_mac.cpp index c281fe9..25ef8ba 100644 --- a/src/gui/image/qpixmap_mac.cpp +++ b/src/gui/image/qpixmap_mac.cpp @@ -1169,25 +1169,6 @@ IconRef qt_mac_create_iconref(const QPixmap &px) } #endif -QPixmap qt_mac_convert_iconref(const IconRef icon, int width, int height) -{ - QPixmap ret(width, height); - ret.fill(QColor(0, 0, 0, 0)); - - CGRect rect = CGRectMake(0, 0, width, height); - - CGContextRef ctx = qt_mac_cg_context(&ret); - CGAffineTransform old_xform = CGContextGetCTM(ctx); - CGContextConcatCTM(ctx, CGAffineTransformInvert(old_xform)); - CGContextConcatCTM(ctx, CGAffineTransformIdentity); - - ::RGBColor b; - b.blue = b.green = b.red = 255*255; - PlotIconRefInContext(ctx, &rect, kAlignNone, kTransformNone, &b, kPlotIconRefNormalFlags, icon); - CGContextRelease(ctx); - return ret; -} - /*! \internal */ QPaintEngine* QMacPixmapData::paintEngine() const { diff --git a/src/gui/image/qpixmapcache.cpp b/src/gui/image/qpixmapcache.cpp index 2ef42ee..ecdcd8c 100644 --- a/src/gui/image/qpixmapcache.cpp +++ b/src/gui/image/qpixmapcache.cpp @@ -64,25 +64,24 @@ QT_BEGIN_NAMESPACE access the global pixmap cache. It creates an internal QCache object for caching the pixmaps. - The cache associates a pixmap with a string as a key or with a QPixmapCache::Key. - The QPixmapCache::Key is faster than using strings as key. The string API is - very convenient for complex keys but the QPixmapCache::Key API will be very efficient - and convenient for a 1 object <-> 1 pixmap mapping (then you can store the key as - a member). - If two pixmaps are inserted into the cache using equal keys, then the - last pixmap will hide the first pixmap. The QHash and QCache classes do - exactly the same. + The cache associates a pixmap with a user-provided string as a key, + or with a QPixmapCache::Key that the cache generates. + Using QPixmapCache::Key for keys is faster than using strings. The string API is + very convenient for complex keys but the QPixmapCache::Key API will be very + efficient and convenient for a one-to-one object-to-pixmap mapping \mdash in + this case, you can store the keys as members of an object. + + If two pixmaps are inserted into the cache using equal keys then the + last pixmap will replace the first pixmap in the cache. This follows the + behavior of the QHash and QCache classes. The cache becomes full when the total size of all pixmaps in the cache exceeds cacheLimit(). The initial cache limit is - 2048 KB(2 MB) for Embedded, 10240 KB (10 - MB) for Desktops; it is changed with setCacheLimit(). - A pixmap takes roughly (\e{width} * \e{height} * \e{depth})/8 bytes of memory. - - The \e{Qt Quarterly} article - \l{http://doc.trolltech.com/qq/qq12-qpixmapcache.html}{Optimizing - with QPixmapCache} explains how to use QPixmapCache to speed up - applications by caching the results of painting. + 2048 KB (2 MB) on embedded platforms, 10240 KB (10 MB) on desktop + platforms; you can change this by calling setCacheLimit() with the + required value. + A pixmap takes roughly (\e{width} * \e{height} * \e{depth})/8 bytes of + memory. \sa QCache, QPixmap */ @@ -94,6 +93,17 @@ static int cache_limit = 10240; // 10 MB cache limit for desktop #endif /*! + \class QPixmapCache::Key + \brief The QPixmapCache::Key class can be used for efficient access + to the QPixmapCache. + \since 4.6 + + Use QPixmapCache::insert() to receive an instance of Key generated + by the pixmap cache. You can store the key in your own objects for + a very efficient one-to-one object-to-pixmap mapping. +*/ + +/*! Constructs an empty Key object. */ QPixmapCache::Key::Key() : d(0) @@ -112,7 +122,7 @@ QPixmapCache::Key::Key(const Key &other) } /*! - Destructor; called immediately before the object is deleted. + Destroys the key. */ QPixmapCache::Key::~Key() { @@ -123,7 +133,8 @@ QPixmapCache::Key::~Key() /*! \internal - Returns true if this key is the same as the given \a key. + Returns true if this key is the same as the given \a key; otherwise returns + false. */ bool QPixmapCache::Key::operator ==(const Key &key) const { @@ -407,7 +418,7 @@ QPixmapCache::KeyData* QPMCache::getKeyData(QPixmapCache::Key *key) Q_GLOBAL_STATIC(QPMCache, pm_cache) /*! - \obsolete + \obsolete \overload Returns the pixmap associated with the \a key in the cache, or @@ -440,7 +451,7 @@ bool QPixmapCache::find(const QString &key, QPixmap& pixmap) } /*! - Looks for a cached pixmap associated with the \a key in the cache. + Looks for a cached pixmap associated with the given \a key in the cache. If the pixmap is found, the function sets \a pixmap to that pixmap and returns true; otherwise it leaves \a pixmap alone and returns false. @@ -459,10 +470,10 @@ bool QPixmapCache::find(const QString &key, QPixmap* pixmap) } /*! - Looks for a cached pixmap associated with the \a key in the cache. + Looks for a cached pixmap associated with the given \a key in the cache. If the pixmap is found, the function sets \a pixmap to that pixmap and returns true; otherwise it leaves \a pixmap alone and returns false. If - the pixmap is not found, it means that the \a key is not valid anymore, + the pixmap is not found, it means that the \a key is no longer valid, so it will be released for the next insertion. \since 4.6 @@ -504,8 +515,8 @@ bool QPixmapCache::insert(const QString &key, const QPixmap &pixmap) } /*! - Inserts a copy of the pixmap \a pixmap into - the cache and return you the key. + Inserts a copy of the given \a pixmap into the cache and returns a key + that can be used to retrieve it. When a pixmap is inserted and the cache is about to exceed its limit, it removes pixmaps until there is enough room for the @@ -524,9 +535,9 @@ QPixmapCache::Key QPixmapCache::insert(const QPixmap &pixmap) } /*! - Replace the pixmap associated to the \a key into - the cache. It return true if the pixmap \a pixmap has been correctly - inserted into the cache false otherwise. + Replaces the pixmap associated with the given \a key with the \a pixmap + specified. Returns true if the \a pixmap has been correctly inserted into + the cache; otherwise returns false. \sa setCacheLimit(), insert() @@ -543,8 +554,8 @@ bool QPixmapCache::replace(const Key &key, const QPixmap &pixmap) /*! Returns the cache limit (in kilobytes). - The default cache limit is 2048 KB for Embedded, 10240 KB for - Desktops. + The default cache limit is 2048 KB on embedded platforms, 10240 KB on + desktop platforms. \sa setCacheLimit() */ @@ -557,8 +568,8 @@ int QPixmapCache::cacheLimit() /*! Sets the cache limit to \a n kilobytes. - The default setting is 2048 KB for Embedded, 10240 KB for - Desktops. + The default setting is 2048 KB on embedded platforms, 10240 KB on + desktop platforms. \sa cacheLimit() */ @@ -578,7 +589,7 @@ void QPixmapCache::remove(const QString &key) } /*! - Removes the pixmap associated with \a key from the cache and release + Removes the pixmap associated with \a key from the cache and releases the key for a future insertion. \since 4.6 diff --git a/src/gui/image/qpixmapfilter.cpp b/src/gui/image/qpixmapfilter.cpp index c5f3663..184bd65 100644 --- a/src/gui/image/qpixmapfilter.cpp +++ b/src/gui/image/qpixmapfilter.cpp @@ -293,8 +293,6 @@ int QPixmapConvolutionFilter::columns() const /*! - \reimp - \internal */ QRectF QPixmapConvolutionFilter::boundingRectFor(const QRectF &rect) const @@ -405,8 +403,6 @@ static void convolute( } /*! - \reimp - \internal */ void QPixmapConvolutionFilter::draw(QPainter *painter, const QPointF &p, const QPixmap &src, const QRectF& srcRect) const @@ -581,8 +577,6 @@ void QPixmapColorizeFilter::setColor(const QColor &color) } /*! - \reimp - \internal */ void QPixmapColorizeFilter::draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const @@ -805,8 +799,6 @@ void QPixmapDropShadowFilter::setOffset(const QPointF &offset) */ /*! - \reimp - \internal */ QRectF QPixmapDropShadowFilter::boundingRectFor(const QRectF &rect) const @@ -822,8 +814,6 @@ QRectF QPixmapDropShadowFilter::boundingRectFor(const QRectF &rect) const } /*! - \reimp - \internal */ void QPixmapDropShadowFilter::draw(QPainter *p, diff --git a/src/gui/itemviews/qdirmodel.cpp b/src/gui/itemviews/qdirmodel.cpp index c25149b..c5618b6 100644 --- a/src/gui/itemviews/qdirmodel.cpp +++ b/src/gui/itemviews/qdirmodel.cpp @@ -228,7 +228,10 @@ void QDirModelPrivate::invalidate() \note QDirModel requires an instance of a GUI application. - \sa nameFilters(), setFilter(), filter(), QListView, QTreeView, + \note The usage of QDirModel is not recommended anymore. The + QFileSystemModel class is a more performant alternative. + + \sa nameFilters(), setFilter(), filter(), QListView, QTreeView, QFileSystemModel {Dir View Example}, {Model Classes} */ diff --git a/src/gui/itemviews/qfileiconprovider.cpp b/src/gui/itemviews/qfileiconprovider.cpp index 1856f4d..dd4341b 100644 --- a/src/gui/itemviews/qfileiconprovider.cpp +++ b/src/gui/itemviews/qfileiconprovider.cpp @@ -45,15 +45,15 @@ #include <qstyle.h> #include <qapplication.h> #include <qdir.h> +#include <qpixmapcache.h> #if defined(Q_WS_WIN) #define _WIN32_IE 0x0500 #include <qt_windows.h> #include <commctrl.h> #include <objbase.h> #include <private/qpixmapdata_p.h> -#include <qpixmapcache.h> #elif defined(Q_WS_MAC) -#include <private/qt_mac_p.h> +#include <private/qt_cocoa_helpers_mac_p.h> #endif #include <private/qfunctions_p.h> @@ -314,6 +314,31 @@ QIcon QFileIconProviderPrivate::getWinIcon(const QFileInfo &fileInfo) const QIcon QFileIconProviderPrivate::getMacIcon(const QFileInfo &fi) const { QIcon retIcon; + QString fileExtension = fi.suffix().toUpper(); + fileExtension.prepend(QLatin1String(".")); + + const QString keyBase = QLatin1String("qt_") + fileExtension; + + QPixmap pixmap; + if (fi.isFile() && !fi.isExecutable() && !fi.isSymLink()) { + QPixmapCache::find(keyBase + QLatin1String("16"), pixmap); + } + + if (!pixmap.isNull()) { + retIcon.addPixmap(pixmap); + if (QPixmapCache::find(keyBase + QLatin1String("32"), pixmap)) { + retIcon.addPixmap(pixmap); + if (QPixmapCache::find(keyBase + QLatin1String("64"), pixmap)) { + retIcon.addPixmap(pixmap); + if (QPixmapCache::find(keyBase + QLatin1String("128"), pixmap)) { + retIcon.addPixmap(pixmap); + return retIcon; + } + } + } + } + + FSRef macRef; OSStatus status = FSPathMakeRef(reinterpret_cast<const UInt8*>(fi.canonicalFilePath().toUtf8().constData()), &macRef, 0); @@ -326,12 +351,23 @@ QIcon QFileIconProviderPrivate::getMacIcon(const QFileInfo &fi) const return retIcon; IconRef iconRef; SInt16 iconLabel; - status = GetIconRefFromFileInfo(&macRef, macName.length, macName.unicode, kIconServicesCatalogInfoMask, &info, kIconServicesNormalUsageFlag, &iconRef, &iconLabel); + status = GetIconRefFromFileInfo(&macRef, macName.length, macName.unicode, + kIconServicesCatalogInfoMask, &info, kIconServicesNormalUsageFlag, + &iconRef, &iconLabel); if (status != noErr) return retIcon; - extern void qt_mac_constructQIconFromIconRef(const IconRef, const IconRef, QIcon*, QStyle::StandardPixmap = QStyle::SP_CustomBase); // qmacstyle_mac.cpp qt_mac_constructQIconFromIconRef(iconRef, 0, &retIcon); ReleaseIconRef(iconRef); + + pixmap = retIcon.pixmap(16); + QPixmapCache::insert(keyBase + QLatin1String("16"), pixmap); + pixmap = retIcon.pixmap(32); + QPixmapCache::insert(keyBase + QLatin1String("32"), pixmap); + pixmap = retIcon.pixmap(64); + QPixmapCache::insert(keyBase + QLatin1String("64"), pixmap); + pixmap = retIcon.pixmap(128); + QPixmapCache::insert(keyBase + QLatin1String("128"), pixmap); + return retIcon; } #endif diff --git a/src/gui/itemviews/qitemdelegate.cpp b/src/gui/itemviews/qitemdelegate.cpp index 2dd5540..336ca79 100644 --- a/src/gui/itemviews/qitemdelegate.cpp +++ b/src/gui/itemviews/qitemdelegate.cpp @@ -861,6 +861,8 @@ void QItemDelegate::drawBackground(QPainter *painter, /*! \internal + + Code duplicated in QCommonStylePrivate::viewItemLayout */ void QItemDelegate::doLayout(const QStyleOptionViewItem &option, @@ -882,8 +884,10 @@ void QItemDelegate::doLayout(const QStyleOptionViewItem &option, int w, h; textRect->adjust(-textMargin, 0, textMargin, 0); // add width padding - if (textRect->height() == 0 && !hasPixmap) + if (textRect->height() == 0 && (!hasPixmap || !hint)) { + //if there is no text, we still want to have a decent height for the item sizeHint and the editor size textRect->setHeight(option.fontMetrics.height()); + } QSize pm(0, 0); if (hasPixmap) { @@ -1219,15 +1223,12 @@ bool QItemDelegate::eventFilter(QObject *object, QEvent *event) if (editor->parentWidget()) editor->parentWidget()->setFocus(); return true; - } else if (event->type() == QEvent::FocusOut || event->type() == QEvent::Hide) { + } else if (event->type() == QEvent::FocusOut || (event->type() == QEvent::Hide && editor->isWindow())) { //the Hide event will take care of he editors that are in fact complete dialogs if (!editor->isActiveWindow() || (QApplication::focusWidget() != editor)) { - QWidget *w = QApplication::focusWidget(); - while (w) { // don't worry about focus changes internally in the editor - if (w == editor) - return false; - w = w->parentWidget(); - } + if (editor->isAncestorOf(QApplication::focusWidget())) + return false; // don't worry about focus changes internally in the editor + #ifndef QT_NO_DRAGANDDROP // The window may lose focus during an drag operation. // i.e when dragging involves the taskbar on Windows. diff --git a/src/gui/itemviews/qlistview.cpp b/src/gui/itemviews/qlistview.cpp index 40f28d4..148d204 100644 --- a/src/gui/itemviews/qlistview.cpp +++ b/src/gui/itemviews/qlistview.cpp @@ -1563,7 +1563,10 @@ void QListView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFl } // middle rectangle if (top.bottom() < bottom.top()) { - middle.setTop(top.bottom() + 1); + if (gridSize().isValid() && !gridSize().isNull()) + middle.setTop(top.top() + gridSize().height()); + else + middle.setTop(top.bottom() + 1); middle.setLeft(qMin(top.left(), bottom.left())); middle.setBottom(bottom.top() - 1); middle.setRight(qMax(top.right(), bottom.right())); @@ -1590,7 +1593,10 @@ void QListView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFl // only set middle if the middle.setTop(0); middle.setBottom(ch); - middle.setLeft(left.right() + 1); + if (gridSize().isValid() && !gridSize().isNull()) + middle.setLeft(left.left() + gridSize().width()); + else + middle.setLeft(left.right() + 1); middle.setRight(right.left() - 1); } else if (left.bottom() < right.top()) { left.setBottom(right.top() - 1); diff --git a/src/gui/itemviews/qsortfilterproxymodel.cpp b/src/gui/itemviews/qsortfilterproxymodel.cpp index 30a8c96..fdc09ca 100644 --- a/src/gui/itemviews/qsortfilterproxymodel.cpp +++ b/src/gui/itemviews/qsortfilterproxymodel.cpp @@ -146,6 +146,7 @@ public: const QModelIndex &source_parent) const; QModelIndex proxy_to_source(const QModelIndex &proxyIndex) const; QModelIndex source_to_proxy(const QModelIndex &sourceIndex) const; + bool can_create_mapping(const QModelIndex &source_parent) const; void remove_from_mapping(const QModelIndex &source_parent); @@ -354,6 +355,25 @@ QModelIndex QSortFilterProxyModelPrivate::source_to_proxy(const QModelIndex &sou return create_index(proxy_row, proxy_column, it); } +bool QSortFilterProxyModelPrivate::can_create_mapping(const QModelIndex &source_parent) const +{ + if (source_parent.isValid()) { + QModelIndex source_grand_parent = source_parent.parent(); + IndexMap::const_iterator it = source_index_mapping.constFind(source_grand_parent); + if (it == source_index_mapping.constEnd()) { + // Don't care, since we don't have mapping for the grand parent + return false; + } + Mapping *gm = it.value(); + if (gm->proxy_rows.at(source_parent.row()) == -1 || + gm->proxy_columns.at(source_parent.column()) == -1) { + // Don't care, since parent is filtered + return false; + } + } + return true; +} + /*! \internal @@ -659,20 +679,8 @@ void QSortFilterProxyModelPrivate::source_items_inserted( return; IndexMap::const_iterator it = source_index_mapping.constFind(source_parent); if (it == source_index_mapping.constEnd()) { - if (source_parent.isValid()) { - QModelIndex source_grand_parent = source_parent.parent(); - it = source_index_mapping.constFind(source_grand_parent); - if (it == source_index_mapping.constEnd()) { - // Don't care, since we don't have mapping for the grand parent - return; - } - Mapping *gm = it.value(); - if (gm->proxy_rows.at(source_parent.row()) == -1 || - gm->proxy_columns.at(source_parent.column()) == -1) { - // Don't care, since parent is filtered - return; - } - } + if (!can_create_mapping(source_parent)) + return; it = create_mapping(source_parent); Mapping *m = it.value(); QModelIndex proxy_parent = q->mapFromSource(source_parent); @@ -1186,7 +1194,8 @@ void QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeInserted( Q_UNUSED(end); //Force the creation of a mapping now, even if its empty. //We need it because the proxy can be acessed at the moment it emits rowsAboutToBeInserted in insert_source_items - create_mapping(source_parent); + if (can_create_mapping(source_parent)) + create_mapping(source_parent); } void QSortFilterProxyModelPrivate::_q_sourceRowsInserted( @@ -1217,7 +1226,8 @@ void QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeInserted( Q_UNUSED(end); //Force the creation of a mapping now, even if its empty. //We need it because the proxy can be acessed at the moment it emits columnsAboutToBeInserted in insert_source_items - create_mapping(source_parent); + if (can_create_mapping(source_parent)) + create_mapping(source_parent); } void QSortFilterProxyModelPrivate::_q_sourceColumnsInserted( diff --git a/src/gui/itemviews/qstyleditemdelegate.cpp b/src/gui/itemviews/qstyleditemdelegate.cpp index edca724..bd8fdac 100644 --- a/src/gui/itemviews/qstyleditemdelegate.cpp +++ b/src/gui/itemviews/qstyleditemdelegate.cpp @@ -671,15 +671,12 @@ bool QStyledItemDelegate::eventFilter(QObject *object, QEvent *event) if (editor->parentWidget()) editor->parentWidget()->setFocus(); return true; - } else if (event->type() == QEvent::FocusOut || event->type() == QEvent::Hide) { + } else if (event->type() == QEvent::FocusOut || (event->type() == QEvent::Hide && editor->isWindow())) { //the Hide event will take care of he editors that are in fact complete dialogs if (!editor->isActiveWindow() || (QApplication::focusWidget() != editor)) { - QWidget *w = QApplication::focusWidget(); - while (w) { // don't worry about focus changes internally in the editor - if (w == editor) - return false; - w = w->parentWidget(); - } + if (editor->isAncestorOf(QApplication::focusWidget())) + return false; // don't worry about focus changes internally in the editor + #ifndef QT_NO_DRAGANDDROP // The window may lose focus during an drag operation. // i.e when dragging involves the taskbar on Windows. diff --git a/src/gui/itemviews/qtreeview.cpp b/src/gui/itemviews/qtreeview.cpp index 7084e6d..7536d72 100644 --- a/src/gui/itemviews/qtreeview.cpp +++ b/src/gui/itemviews/qtreeview.cpp @@ -1095,18 +1095,22 @@ void QTreeView::scrollTo(const QModelIndex &index, ScrollHint hint) } else if (hint == PositionAtTop || (hint == EnsureVisible && item < top)) { verticalScrollBar()->setValue(item); } else { // PositionAtBottom or PositionAtCenter - int itemLocation = item; + const int currentItemHeight = d->itemHeight(item); int y = (hint == PositionAtCenter - ? area.height() / 2 + //we center on the current item with a preference to the top item (ie. -1) + ? area.height() / 2 + currentItemHeight - 1 + //otherwise we simply take the whole space : area.height()); - while (y > 0 && item > 0) - y -= d->itemHeight(item--); - // end up half over the top of the area - if (y < 0 && item < itemLocation) - ++item; - // end up half over the bottom of the area - if (item >= 0 && item < itemLocation) - ++item; + if (y > currentItemHeight) { + while (item >= 0) { + y -= d->itemHeight(item); + if (y < 0) { //there is no more space left + item++; + break; + } + item--; + } + } verticalScrollBar()->setValue(item); } } else { // ScrollPerPixel @@ -2849,7 +2853,7 @@ int QTreeView::rowHeight(const QModelIndex &index) const } /*! - \reimp + \internal */ void QTreeView::horizontalScrollbarAction(int action) { diff --git a/src/gui/kernel/qaction.cpp b/src/gui/kernel/qaction.cpp index 4ee17f4..e7cb5c2 100644 --- a/src/gui/kernel/qaction.cpp +++ b/src/gui/kernel/qaction.cpp @@ -81,7 +81,7 @@ static QString qt_strippedText(QString s) QActionPrivate::QActionPrivate() : group(0), enabled(1), forceDisabled(0), visible(1), forceInvisible(0), checkable(0), checked(0), separator(0), fontSet(false), - menuRole(QAction::TextHeuristicRole), iconVisibleInMenu(-1) + menuRole(QAction::TextHeuristicRole), priority(QAction::NormalPriority), iconVisibleInMenu(-1) { #ifdef QT3_SUPPORT static int qt_static_action_id = -1; @@ -909,6 +909,52 @@ QString QAction::whatsThis() const return d->whatsthis; } +/*! + \enum QAction::Priority + \since 4.6 + + This enum defines priorities for actions in user interface. + + \value LowPriority The action should not be prioritized in + the user interface. + + \value NormalPriority + + \value HighPriority The action should be prioritized in + the user interface. + + \sa priority +*/ + + +/*! + \property QAction::priority + \since 4.6 + + \brief the actions's priority in the user interface. + + This property can be set to indicate how the action should be prioritized + in the user interface. + + For instance, when toolbars have the Qt::ToolButtonTextBesideIcon + mode set, then actions with LowPriority will not show the text + labels. +*/ +void QAction::setPriority(Priority priority) +{ + Q_D(QAction); + if (d->priority == priority) + return; + + d->priority = priority; + d->sendDataChanged(); +} + +QAction::Priority QAction::priority() const +{ + Q_D(const QAction); + return d->priority; +} /*! \property QAction::checkable diff --git a/src/gui/kernel/qaction.h b/src/gui/kernel/qaction.h index 3ac30ed..cb681c4 100644 --- a/src/gui/kernel/qaction.h +++ b/src/gui/kernel/qaction.h @@ -67,6 +67,7 @@ class Q_GUI_EXPORT QAction : public QObject Q_DECLARE_PRIVATE(QAction) Q_ENUMS(MenuRole) + Q_ENUMS(Priority) Q_PROPERTY(bool checkable READ isCheckable WRITE setCheckable NOTIFY changed) Q_PROPERTY(bool checked READ isChecked WRITE setChecked DESIGNABLE isCheckable NOTIFY toggled) Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY changed) @@ -85,10 +86,14 @@ class Q_GUI_EXPORT QAction : public QObject Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY changed) Q_PROPERTY(MenuRole menuRole READ menuRole WRITE setMenuRole NOTIFY changed) Q_PROPERTY(bool iconVisibleInMenu READ isIconVisibleInMenu WRITE setIconVisibleInMenu NOTIFY changed) + Q_PROPERTY(Priority priority READ priority WRITE setPriority) public: enum MenuRole { NoRole, TextHeuristicRole, ApplicationSpecificRole, AboutQtRole, AboutRole, PreferencesRole, QuitRole }; + enum Priority { LowPriority = 0, + NormalPriority = 128, + HighPriority = 256}; explicit QAction(QObject* parent); QAction(const QString &text, QObject* parent); QAction(const QIcon &icon, const QString &text, QObject* parent); @@ -123,6 +128,9 @@ public: void setWhatsThis(const QString &what); QString whatsThis() const; + void setPriority(Priority priority); + Priority priority() const; + #ifndef QT_NO_MENU QMenu *menu() const; void setMenu(QMenu *menu); diff --git a/src/gui/kernel/qaction_p.h b/src/gui/kernel/qaction_p.h index bae9bbf..4745ed1 100644 --- a/src/gui/kernel/qaction_p.h +++ b/src/gui/kernel/qaction_p.h @@ -102,6 +102,7 @@ public: uint separator : 1; uint fontSet : 1; QAction::MenuRole menuRole; + QAction::Priority priority; int iconVisibleInMenu : 3; // Only has values -1, 0, and 1 QList<QWidget *> widgets; #ifndef QT_NO_GRAPHICSVIEW diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index b168188..3453408 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -819,6 +819,12 @@ QApplication::QApplication(Display *dpy, int &argc, char **argv, #endif // Q_WS_X11 extern void qInitDrawhelperAsm(); +extern int qRegisterGuiVariant(); +extern int qUnregisterGuiVariant(); +#ifndef QT_NO_STATEMACHINE +extern int qRegisterGuiStateMachine(); +extern int qUnregisterGuiStateMachine(); +#endif /*! \fn void QApplicationPrivate::initialize() @@ -832,11 +838,9 @@ void QApplicationPrivate::initialize() if (qt_appType != QApplication::Tty) (void) QApplication::style(); // trigger creation of application style // trigger registering of QVariant's GUI types - extern int qRegisterGuiVariant(); qRegisterGuiVariant(); #ifndef QT_NO_STATEMACHINE // trigger registering of QStateMachine's GUI types - extern int qRegisterGuiStateMachine(); qRegisterGuiStateMachine(); #endif @@ -1060,11 +1064,9 @@ QApplication::~QApplication() #ifndef QT_NO_STATEMACHINE // trigger unregistering of QStateMachine's GUI types - extern int qUnregisterGuiStateMachine(); qUnregisterGuiStateMachine(); #endif // trigger unregistering of QVariant's GUI types - extern int qUnregisterGuiVariant(); qUnregisterGuiVariant(); } diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index 90eaba0..595f220 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -192,101 +192,57 @@ extern "C" { #endif #if defined(Q_WS_WIN) -typedef BOOL (WINAPI *qt_RegisterTouchWindowPtr)(HWND, ULONG); -typedef BOOL (WINAPI *qt_GetTouchInputInfoPtr)(HANDLE, UINT, PVOID, int); -typedef BOOL (WINAPI *qt_CloseTouchInputHandlePtr)(HANDLE); +typedef BOOL (WINAPI *PtrRegisterTouchWindow)(HWND, ULONG); +typedef BOOL (WINAPI *PtrGetTouchInputInfo)(HANDLE, UINT, PVOID, int); +typedef BOOL (WINAPI *PtrCloseTouchInputHandle)(HANDLE); + +typedef BOOL (WINAPI *PtrGetGestureInfo)(HANDLE, PVOID); +typedef BOOL (WINAPI *PtrGetGestureExtraArgs)(HANDLE, UINT, PBYTE); +typedef BOOL (WINAPI *PtrCloseGestureInfoHandle)(HANDLE); +typedef BOOL (WINAPI *PtrSetGestureConfig)(HWND, DWORD, UINT, PVOID, UINT); +typedef BOOL (WINAPI *PtrGetGestureConfig)(HWND, DWORD, DWORD, PUINT, PVOID, UINT); + +typedef BOOL (WINAPI *PtrBeginPanningFeedback)(HWND); +typedef BOOL (WINAPI *PtrUpdatePanningFeedback)(HWND, LONG, LONG, BOOL); +typedef BOOL (WINAPI *PtrEndPanningFeedback)(HWND, BOOL); #ifndef WM_GESTURE +# define WM_GESTURE 0x0119 + +# define GID_BEGIN 1 +# define GID_END 2 +# define GID_ZOOM 3 +# define GID_PAN 4 +# define GID_ROTATE 5 +# define GID_TWOFINGERTAP 6 +# define GID_ROLLOVER 7 -#define WM_GESTURE 0x0119 -#define WM_GESTURE_NOTIFY 0x011A - -DECLARE_HANDLE(HGESTUREINFO); - -#define GF_BEGIN 0x00000001 -#define GF_INERTIA 0x00000002 -#define GF_END 0x00000004 - -/* - * Gesture IDs - */ -#define GID_BEGIN 1 -#define GID_END 2 -#define GID_ZOOM 3 -#define GID_PAN 4 -#define GID_ROTATE 5 -#define GID_TWOFINGERTAP 6 -#define GID_ROLLOVER 7 - -typedef struct tagGESTUREINFO { - UINT cbSize; // size, in bytes, of this structure (including variable length Args field) - DWORD dwFlags; // see GF_* flags - DWORD dwID; // gesture ID, see GID_* defines - HWND hwndTarget; // handle to window targeted by this gesture - POINTS ptsLocation; // current location of this gesture - DWORD dwInstanceID; // internally used - DWORD dwSequenceID; // internally used - ULONGLONG ullArguments; // arguments for gestures whose arguments fit in 8 BYTES - UINT cbExtraArgs; // size, in bytes, of extra arguments, if any, that accompany this gesture -} GESTUREINFO, *PGESTUREINFO; -typedef GESTUREINFO const * PCGESTUREINFO; - -typedef struct tagGESTURENOTIFYSTRUCT { - UINT cbSize; // size, in bytes, of this structure - DWORD dwFlags; // unused - HWND hwndTarget; // handle to window targeted by the gesture - POINTS ptsLocation; // starting location - DWORD dwInstanceID; // internally used -} GESTURENOTIFYSTRUCT, *PGESTURENOTIFYSTRUCT; - -/* - * Gesture argument helpers - * - Angle should be a double in the range of -2pi to +2pi - * - Argument should be an unsigned 16-bit value - */ -#define GID_ROTATE_ANGLE_TO_ARGUMENT(_arg_) ((USHORT)((((_arg_) + 2.0 * 3.14159265) / (4.0 * 3.14159265)) * 65535.0)) -#define GID_ROTATE_ANGLE_FROM_ARGUMENT(_arg_) ((((double)(_arg_) / 65535.0) * 4.0 * 3.14159265) - 2.0 * 3.14159265) - -typedef struct tagGESTURECONFIG { - DWORD dwID; // gesture ID - DWORD dwWant; // settings related to gesture ID that are to be turned on - DWORD dwBlock; // settings related to gesture ID that are to be turned off -} GESTURECONFIG, *PGESTURECONFIG; - -#define GC_ALLGESTURES 0x00000001 -#define GC_ZOOM 0x00000001 -#define GC_PAN 0x00000001 -#define GC_PAN_WITH_SINGLE_FINGER_VERTICALLY 0x00000002 -#define GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY 0x00000004 -#define GC_PAN_WITH_GUTTER 0x00000008 -#define GC_PAN_WITH_INERTIA 0x00000010 -#define GC_ROTATE 0x00000001 -#define GC_TWOFINGERTAP 0x00000001 -#define GC_ROLLOVER 0x00000001 -#define GESTURECONFIGMAXCOUNT 256 // Maximum number of gestures that can be included - // in a single call to SetGestureConfig / GetGestureConfig - - - -#define GCF_INCLUDE_ANCESTORS 0x00000001 // If specified, GetGestureConfig returns consolidated configuration - // for the specified window and it's parent window chain - -typedef BOOL (*PtrGetGestureInfo)(HGESTUREINFO hGestureInfo, PGESTUREINFO pGestureInfo); -typedef BOOL (*PtrGetGestureExtraArgs)(HGESTUREINFO hGestureInfo, UINT cbExtraArgs, PBYTE pExtraArgs); -typedef BOOL (*PtrCloseGestureInfoHandle)(HGESTUREINFO hGestureInfo); -typedef BOOL (*PtrSetGestureConfig)(HWND hwnd, DWORD dwReserved, UINT cIDs, - PGESTURECONFIG pGestureConfig, - UINT cbSize); -typedef BOOL (*PtrGetGestureConfig)(HWND hwnd, DWORD dwReserved, - DWORD dwFlags, PUINT pcIDs, - PGESTURECONFIG pGestureConfig, - UINT cbSize); - -typedef BOOL (*PtrBeginPanningFeedback)(HWND hwnd); -typedef BOOL (*PtrUpdatePanningFeedback)(HWND hwnd, LONG, LONG, BOOL); -typedef BOOL (*PtrEndPanningFeedback)(HWND hwnd, BOOL); +typedef struct tagGESTUREINFO +{ + UINT cbSize; + DWORD dwFlags; + DWORD dwID; + HWND hwndTarget; + POINTS ptsLocation; + DWORD dwInstanceID; + DWORD dwSequenceID; + ULONGLONG ullArguments; + UINT cbExtraArgs; +} GESTUREINFO; + +# define GC_PAN 0x00000001 +# define GC_PAN_WITH_SINGLE_FINGER_VERTICALLY 0x00000002 +# define GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY 0x00000004 + +typedef struct tagGESTURECONFIG +{ + DWORD dwID; + DWORD dwWant; + DWORD dwBlock; +} GESTURECONFIG; #endif // WM_GESTURE + #endif // Q_WS_WIN class QPanGesture; @@ -558,9 +514,9 @@ public: const QList<QTouchEvent::TouchPoint> &touchPoints); #if defined(Q_WS_WIN) - static qt_RegisterTouchWindowPtr RegisterTouchWindow; - static qt_GetTouchInputInfoPtr GetTouchInputInfo; - static qt_CloseTouchInputHandlePtr CloseTouchInputHandle; + static PtrRegisterTouchWindow RegisterTouchWindow; + static PtrGetTouchInputInfo GetTouchInputInfo; + static PtrCloseTouchInputHandle CloseTouchInputHandle; QHash<DWORD, int> touchInputIDToTouchPointID; QList<QTouchEvent::TouchPoint> appAllTouchPoints; diff --git a/src/gui/kernel/qapplication_qws.cpp b/src/gui/kernel/qapplication_qws.cpp index f568438..347afc8 100644 --- a/src/gui/kernel/qapplication_qws.cpp +++ b/src/gui/kernel/qapplication_qws.cpp @@ -661,10 +661,14 @@ void QWSDisplay::Data::sendSynchronousCommand(QWSCommand & cmd) int QWSDisplay::Data::takeId() { - if (unused_identifiers.count() == 10) + int unusedIdCount = unused_identifiers.count(); + if (unusedIdCount == 10) create(15); - if (unused_identifiers.count() == 0) + if (unusedIdCount == 0) { + create(1); // Make sure we have an incoming id to wait for, just in case we're recursive waitForCreation(); + } + return unused_identifiers.takeFirst(); } diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index 164a228..d5c820c 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -275,6 +275,8 @@ extern HRGN qt_tryCreateRegion(QRegion::RegionType type, int left, int top, int #define GET_XBUTTON_WPARAM(wParam) (HIWORD(wParam)) #define XBUTTON1 0x0001 #define XBUTTON2 0x0002 +#endif +#ifndef MK_XBUTTON1 #define MK_XBUTTON1 0x0020 #define MK_XBUTTON2 0x0040 #endif @@ -807,9 +809,10 @@ void qt_init(QApplicationPrivate *priv, int) ptrUpdateLayeredWindowIndirect = qt_updateLayeredWindowIndirect; // Notify Vista and Windows 7 that we support highter DPI settings - if (ptrSetProcessDPIAware = (PtrSetProcessDPIAware) - QLibrary::resolve(QLatin1String("user32"), "SetProcessDPIAware")) - ptrSetProcessDPIAware(); + ptrSetProcessDPIAware = (PtrSetProcessDPIAware) + QLibrary::resolve(QLatin1String("user32"), "SetProcessDPIAware"); + if (ptrSetProcessDPIAware) + ptrSetProcessDPIAware(); #endif priv->lastGestureId = 0; @@ -1006,6 +1009,8 @@ const QString qt_reg_winclass(QWidget *w) // register window class #ifndef QT_NO_DEBUG if (!atom) qErrnoWarning("QApplication::regClass: Registering window class failed."); +#else + Q_UNUSED(atom); #endif winclassNames()->insert(cname, 1); @@ -1351,13 +1356,13 @@ static int inputcharset = CP_ACP; static bool qt_is_translatable_mouse_event(UINT message) { - return (message >= WM_MOUSEFIRST && message <= WM_MOUSELAST || - message >= WM_XBUTTONDOWN && message <= WM_XBUTTONDBLCLK) + return (((message >= WM_MOUSEFIRST && message <= WM_MOUSELAST) || + (message >= WM_XBUTTONDOWN && message <= WM_XBUTTONDBLCLK)) && message != WM_MOUSEWHEEL - && message != WM_MOUSEHWHEEL + && message != WM_MOUSEHWHEEL) #ifndef Q_WS_WINCE - || message >= WM_NCMOUSEMOVE && message <= WM_NCMBUTTONDBLCLK + || (message >= WM_NCMOUSEMOVE && message <= WM_NCMBUTTONDBLCLK) #endif ; } @@ -2601,7 +2606,7 @@ bool qt_try_modal(QWidget *widget, MSG *msg, int& ret) bool block_event = false; #ifndef Q_WS_WINCE - if (type != WM_NCHITTEST) + if (type != WM_NCHITTEST) { #endif if ((type >= WM_MOUSEFIRST && type <= WM_MOUSELAST) || type == WM_MOUSEWHEEL || type == WM_MOUSEHWHEEL || @@ -2631,17 +2636,18 @@ bool qt_try_modal(QWidget *widget, MSG *msg, int& ret) block_event = true; } #ifndef Q_WS_WINCE - else if (type == WM_MOUSEACTIVATE || type == WM_NCLBUTTONDOWN){ - if (!top->isActiveWindow()) { - top->activateWindow(); - } else { - QApplication::beep(); - } - block_event = true; - ret = MA_NOACTIVATEANDEAT; - } else if (type == WM_SYSCOMMAND) { - if (!(msg->wParam == SC_RESTORE && widget->isMinimized())) + else if (type == WM_MOUSEACTIVATE || type == WM_NCLBUTTONDOWN){ + if (!top->isActiveWindow()) { + top->activateWindow(); + } else { + QApplication::beep(); + } block_event = true; + ret = MA_NOACTIVATEANDEAT; + } else if (type == WM_SYSCOMMAND) { + if (!(msg->wParam == SC_RESTORE && widget->isMinimized())) + block_event = true; + } } #endif @@ -2843,7 +2849,7 @@ void qt_win_eatMouseMove() // remove all those messages (usually 1) and post the last one with a // reset button state - MSG msg = {0, 0, 0, 0, 0, 0, 0}; + MSG msg = {0, 0, 0, 0, 0, {0, 0} }; while (PeekMessage(&msg, 0, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE)) ; if (msg.message == WM_MOUSEMOVE) @@ -3721,7 +3727,7 @@ bool QETWidget::translateGestureEvent(const MSG &msg) gi.dwSequenceID = 0; QApplicationPrivate *qAppPriv = getQApplicationPrivateInternal(); - BOOL bResult = qAppPriv->GetGestureInfo((HGESTUREINFO)msg.lParam, &gi); + BOOL bResult = qAppPriv->GetGestureInfo((HANDLE)msg.lParam, &gi); const QPoint widgetPos = QPoint(gi.ptsLocation.x, gi.ptsLocation.y); QWidget *alienWidget = !internalWinId() ? this : childAt(widgetPos); @@ -3759,7 +3765,7 @@ bool QETWidget::translateGestureEvent(const MSG &msg) if (dwErr > 0) qWarning() << "translateGestureEvent: error = " << dwErr; } - qAppPriv->CloseGestureInfoHandle((HGESTUREINFO)msg.lParam); + qAppPriv->CloseGestureInfoHandle((HANDLE)msg.lParam); return true; } @@ -3945,16 +3951,17 @@ void QSessionManager::cancel() #endif //QT_NO_SESSIONMANAGER -qt_RegisterTouchWindowPtr QApplicationPrivate::RegisterTouchWindow = 0; -qt_GetTouchInputInfoPtr QApplicationPrivate::GetTouchInputInfo = 0; -qt_CloseTouchInputHandlePtr QApplicationPrivate::CloseTouchInputHandle = 0; +PtrRegisterTouchWindow QApplicationPrivate::RegisterTouchWindow = 0; +PtrGetTouchInputInfo QApplicationPrivate::GetTouchInputInfo = 0; +PtrCloseTouchInputHandle QApplicationPrivate::CloseTouchInputHandle = 0; void QApplicationPrivate::initializeMultitouch_sys() { QLibrary library(QLatin1String("user32")); - RegisterTouchWindow = reinterpret_cast<qt_RegisterTouchWindowPtr>(library.resolve("RegisterTouchWindow")); - GetTouchInputInfo = reinterpret_cast<qt_GetTouchInputInfoPtr>(library.resolve("GetTouchInputInfo")); - CloseTouchInputHandle = reinterpret_cast<qt_CloseTouchInputHandlePtr>(library.resolve("CloseTouchInputHandle")); + // MinGW (g++ 3.4.5) accepts only C casts. + RegisterTouchWindow = (PtrRegisterTouchWindow)(library.resolve("RegisterTouchWindow")); + GetTouchInputInfo = (PtrGetTouchInputInfo)(library.resolve("GetTouchInputInfo")); + CloseTouchInputHandle = (PtrCloseTouchInputHandle)(library.resolve("CloseTouchInputHandle")); touchInputIDToTouchPointID.clear(); } diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp index 5ef6b2e..4016563 100644 --- a/src/gui/kernel/qapplication_x11.cpp +++ b/src/gui/kernel/qapplication_x11.cpp @@ -117,7 +117,9 @@ extern "C" { #define XK_MISCELLANY #include <X11/keysymdef.h> +#if !defined(QT_NO_XINPUT) #include <X11/extensions/XI.h> +#endif #include <stdlib.h> #include <string.h> @@ -655,11 +657,13 @@ static int qt_x_errhandler(Display *dpy, XErrorEvent *err) break; default: +#if !defined(QT_NO_XINPUT) if (err->request_code == X11->xinput_major && err->error_code == (X11->xinput_errorbase + XI_BadDevice) && err->minor_code == 3 /* X_OpenDevice */) { return 0; } +#endif break; } @@ -1392,6 +1396,18 @@ static void qt_set_x11_resources(const char* font = 0, const char* fg = 0, color = kdeColor(QLatin1String("Colors:Button/ForegroundNormal"), theKdeSettings); if (color.isValid()) pal.setColor(QPalette::ButtonText, color); + + color = kdeColor(QLatin1String("linkColor"), theKdeSettings); + if (!color.isValid()) + color = kdeColor(QLatin1String("Colors:View/ForegroundLink"), theKdeSettings); + if (color.isValid()) + pal.setColor(QPalette::Link, color); + + color = kdeColor(QLatin1String("visitedLinkColor"), theKdeSettings); + if (!color.isValid()) + color = kdeColor(QLatin1String("Colors:View/ForegroundVisited"), theKdeSettings); + if (color.isValid()) + pal.setColor(QPalette::LinkVisited, color); } if (highlight.isValid() && highlightText.isValid()) { @@ -3230,48 +3246,43 @@ int QApplication::x11ProcessEvent(XEvent* event) #ifdef ALIEN_DEBUG //qDebug() << "QApplication::x11ProcessEvent:" << event->type; #endif - Time time = 0, userTime = 0; switch (event->type) { case ButtonPress: pressed_window = event->xbutton.window; - userTime = event->xbutton.time; + X11->userTime = event->xbutton.time; // fallthrough intended case ButtonRelease: - time = event->xbutton.time; + X11->time = event->xbutton.time; break; case MotionNotify: - time = event->xmotion.time; + X11->time = event->xmotion.time; break; case XKeyPress: - userTime = event->xkey.time; + X11->userTime = event->xkey.time; // fallthrough intended case XKeyRelease: - time = event->xkey.time; + X11->time = event->xkey.time; break; case PropertyNotify: - time = event->xproperty.time; + X11->time = event->xproperty.time; break; case EnterNotify: case LeaveNotify: - time = event->xcrossing.time; + X11->time = event->xcrossing.time; break; case SelectionClear: - time = event->xselectionclear.time; + X11->time = event->xselectionclear.time; break; default: -#ifndef QT_NO_XFIXES - if (X11->use_xfixes && event->type == (X11->xfixes_eventbase + XFixesSelectionNotify)) { - XFixesSelectionNotifyEvent *req = - reinterpret_cast<XFixesSelectionNotifyEvent *>(event); - time = req->selection_timestamp; - } -#endif break; } - if (time > X11->time) - X11->time = time; - if (userTime > X11->userTime) - X11->userTime = userTime; +#ifndef QT_NO_XFIXES + if (X11->use_xfixes && event->type == (X11->xfixes_eventbase + XFixesSelectionNotify)) { + XFixesSelectionNotifyEvent *req = + reinterpret_cast<XFixesSelectionNotifyEvent *>(event); + X11->time = req->selection_timestamp; + } +#endif QETWidget *widget = (QETWidget*)QWidget::find((WId)event->xany.window); @@ -3437,19 +3448,10 @@ int QApplication::x11ProcessEvent(XEvent* event) QSize oldSize(w->size()); w->data->crect.setWidth(DisplayWidth(X11->display, scr)); w->data->crect.setHeight(DisplayHeight(X11->display, scr)); - QVarLengthArray<QRect> oldSizes(desktop->numScreens()); - for (int i = 0; i < desktop->numScreens(); ++i) - oldSizes[i] = desktop->screenGeometry(i); QResizeEvent e(w->size(), oldSize); QApplication::sendEvent(w, &e); - for (int i = 0; i < qMin(oldSizes.count(), desktop->numScreens()); ++i) { - if (oldSizes[i] != desktop->screenGeometry(i)) - emit desktop->resized(i); - } - for (int i = oldSizes.count(); i < desktop->numScreens(); ++i) - emit desktop->resized(i); // added - for (int i = desktop->numScreens(); i < oldSizes.count(); ++i) - emit desktop->resized(i); // removed + if (w != desktop) + QApplication::sendEvent(desktop, &e); } #endif // QT_NO_XRANDR diff --git a/src/gui/kernel/qcocoaview_mac.mm b/src/gui/kernel/qcocoaview_mac.mm index 52685ca..3e5bfb6 100644 --- a/src/gui/kernel/qcocoaview_mac.mm +++ b/src/gui/kernel/qcocoaview_mac.mm @@ -550,15 +550,7 @@ extern "C" { qwidget->objectName().local8Bit().data()); #endif QPainter p(qwidget); - QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea *>(qwidget->parent()); - QPoint scrollAreaOffset; - if (scrollArea && scrollArea->viewport() == qwidget) { - QAbstractScrollAreaPrivate *priv - = static_cast<QAbstractScrollAreaPrivate *>(qt_widget_private(scrollArea)); - scrollAreaOffset = priv->contentsOffset(); - p.translate(-scrollAreaOffset); - } - qwidgetprivate->paintBackground(&p, qrgn, scrollAreaOffset, + qwidgetprivate->paintBackground(&p, qrgn, qwidget->isWindow() ? QWidgetPrivate::DrawAsRoot : 0); p.end(); } diff --git a/src/gui/kernel/qcursor_win.cpp b/src/gui/kernel/qcursor_win.cpp index db00835..26e395c 100644 --- a/src/gui/kernel/qcursor_win.cpp +++ b/src/gui/kernel/qcursor_win.cpp @@ -476,7 +476,11 @@ void QCursorData::update() qWarning("QCursor::update: Invalid cursor shape %d", cshape); return; } +#ifdef Q_WS_WINCE + hcurs = LoadCursor(0, sh); +#else hcurs = (HCURSOR)LoadImage(0, sh, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED); +#endif } QT_END_NAMESPACE diff --git a/src/gui/kernel/qdesktopwidget.h b/src/gui/kernel/qdesktopwidget.h index 470f10a..a21ae9d 100644 --- a/src/gui/kernel/qdesktopwidget.h +++ b/src/gui/kernel/qdesktopwidget.h @@ -56,6 +56,9 @@ class QDesktopWidgetPrivate; class Q_GUI_EXPORT QDesktopWidget : public QWidget { Q_OBJECT + Q_PROPERTY(bool virtualDesktop READ isVirtualDesktop) + Q_PROPERTY(int screenCount READ screenCount NOTIFY screenCountChanged) + Q_PROPERTY(int primaryScreen READ primaryScreen) public: QDesktopWidget(); ~QDesktopWidget(); @@ -63,6 +66,7 @@ public: bool isVirtualDesktop() const; int numScreens() const; + int screenCount() const; int primaryScreen() const; int screenNumber(const QWidget *widget = 0) const; @@ -85,6 +89,7 @@ public: Q_SIGNALS: void resized(int); void workAreaResized(int); + void screenCountChanged(int); protected: void resizeEvent(QResizeEvent *e); @@ -97,6 +102,9 @@ private: friend class QApplicationPrivate; }; +inline int QDesktopWidget::screenCount() const +{ return numScreens(); } + QT_END_NAMESPACE QT_END_HEADER diff --git a/src/gui/kernel/qdesktopwidget_mac.mm b/src/gui/kernel/qdesktopwidget_mac.mm index 2489fe4..705387d 100644 --- a/src/gui/kernel/qdesktopwidget_mac.mm +++ b/src/gui/kernel/qdesktopwidget_mac.mm @@ -97,15 +97,13 @@ QT_USE_NAMESPACE Q_GLOBAL_STATIC(QDesktopWidgetImplementation, qdesktopWidgetImplementation) QDesktopWidgetImplementation::QDesktopWidgetImplementation() - : appScreen(0), displays(0) + : appScreen(0) { onResize(); } QDesktopWidgetImplementation::~QDesktopWidgetImplementation() { - if (displays) - [displays release]; } QDesktopWidgetImplementation *QDesktopWidgetImplementation::instance() @@ -118,13 +116,7 @@ QRect QDesktopWidgetImplementation::availableRect(int screenIndex) const if (screenIndex < 0 || screenIndex >= screenCount) screenIndex = appScreen; - NSRect r = [[displays objectAtIndex:screenIndex] visibleFrame]; - NSRect primaryRect = [[displays objectAtIndex:0] frame]; - - const int flippedY = - r.origin.y + // account for position offset and - primaryRect.size.height - r.size.height; // height difference. - return QRectF(r.origin.x, flippedY, - r.size.width, r.size.height).toRect(); + return availableRects[screenIndex].toRect(); } QRect QDesktopWidgetImplementation::screenRect(int screenIndex) const @@ -132,22 +124,28 @@ QRect QDesktopWidgetImplementation::screenRect(int screenIndex) const if (screenIndex < 0 || screenIndex >= screenCount) screenIndex = appScreen; - NSRect r = [[displays objectAtIndex:screenIndex] frame]; - NSRect primaryRect = [[displays objectAtIndex:0] frame]; - - const int flippedY = - r.origin.y + // account for position offset and - primaryRect.size.height - r.size.height; // height difference. - return QRectF(r.origin.x, flippedY, - r.size.width, r.size.height).toRect(); + return screenRects[screenIndex].toRect(); } void QDesktopWidgetImplementation::onResize() { - if (displays) - [displays release]; - - displays = [[NSScreen screens] retain]; - screenCount = [displays count]; + QMacCocoaAutoReleasePool pool; + NSArray *displays = [NSScreen screens]; + screenCount = [displays count]; + + screenRects.clear(); + availableRects.clear(); + NSRect primaryRect = [[displays objectAtIndex:0] frame]; + for (int i = 0; i<screenCount; i++) { + NSRect r = [[displays objectAtIndex:i] frame]; + const int flippedY = - r.origin.y + // account for position offset and + primaryRect.size.height - r.size.height; // height difference. + screenRects.append(QRectF(r.origin.x, flippedY, + r.size.width, r.size.height)); + r = [[displays objectAtIndex:i] visibleFrame]; + availableRects.append(QRectF(r.origin.x, flippedY, + r.size.width, r.size.height)); + } } @@ -195,7 +193,7 @@ const QRect QDesktopWidget::screenGeometry(int screen) const int QDesktopWidget::screenNumber(const QWidget *widget) const { - QDesktopWidgetImplementation *d = qdesktopWidgetImplementation(); + QDesktopWidgetImplementation *d = qdesktopWidgetImplementation(); if (!widget) return d->appScreen; QRect frame = widget->frameGeometry(); @@ -216,7 +214,7 @@ int QDesktopWidget::screenNumber(const QWidget *widget) const int QDesktopWidget::screenNumber(const QPoint &point) const { - QDesktopWidgetImplementation *d = qdesktopWidgetImplementation(); + QDesktopWidgetImplementation *d = qdesktopWidgetImplementation(); int closestScreen = -1; int shortestDistance = INT_MAX; for (int i = 0; i < d->screenCount; ++i) { @@ -232,13 +230,25 @@ int QDesktopWidget::screenNumber(const QPoint &point) const void QDesktopWidget::resizeEvent(QResizeEvent *) { - QDesktopWidgetImplementation *d = qdesktopWidgetImplementation(); + QDesktopWidgetImplementation *d = qdesktopWidgetImplementation(); + + const int oldScreenCount = d->screenCount; + const QVector<QRectF> oldRects(d->screenRects); + const QVector<QRectF> oldWorks(d->availableRects); d->onResize(); - for (int i = 0; i < d->screenCount; ++i) { - emit resized(i); + for (int i = 0; i < qMin(oldScreenCount, d->screenCount); ++i) { + if (oldRects.at(i) != d->screenRects.at(i)) + emit resized(i); + } + for (int i = 0; i < qMin(oldScreenCount, d->screenCount); ++i) { + if (oldWorks.at(i) != d->availableRects.at(i)) + emit workAreaResized(i); } + + if (oldScreenCount != d->screenCount) + emit screenCountChanged(d->screenCount); } QT_END_NAMESPACE diff --git a/src/gui/kernel/qdesktopwidget_mac_p.h b/src/gui/kernel/qdesktopwidget_mac_p.h index 0fdc455..e9d5d9f 100644 --- a/src/gui/kernel/qdesktopwidget_mac_p.h +++ b/src/gui/kernel/qdesktopwidget_mac_p.h @@ -64,7 +64,8 @@ public: int appScreen; int screenCount; - NSArray *displays; + QVector<QRectF> availableRects; + QVector<QRectF> screenRects; QRect availableRect(int screenIndex) const; QRect screenRect(int screenIndex) const; diff --git a/src/gui/kernel/qdesktopwidget_win.cpp b/src/gui/kernel/qdesktopwidget_win.cpp index fb176b7..a89e08f 100644 --- a/src/gui/kernel/qdesktopwidget_win.cpp +++ b/src/gui/kernel/qdesktopwidget_win.cpp @@ -354,10 +354,8 @@ int QDesktopWidget::screenNumber(const QPoint &point) const void QDesktopWidget::resizeEvent(QResizeEvent *) { Q_D(QDesktopWidget); - QVector<QRect> oldrects; - oldrects = *d->rects; - QVector<QRect> oldworkrects; - oldworkrects = *d->workrects; + const QVector<QRect> oldrects(*d->rects); + const QVector<QRect> oldworkrects(*d->workrects); int oldscreencount = d->screenCount; QDesktopWidgetPrivate::cleanup(); @@ -368,18 +366,22 @@ void QDesktopWidget::resizeEvent(QResizeEvent *) #endif for (int i = 0; i < qMin(oldscreencount, d->screenCount); ++i) { - QRect oldrect = oldrects[i]; - QRect newrect = d->rects->at(i); + const QRect oldrect = oldrects[i]; + const QRect newrect = d->rects->at(i); if (oldrect != newrect) emit resized(i); } for (int j = 0; j < qMin(oldscreencount, d->screenCount); ++j) { - QRect oldrect = oldworkrects[j]; - QRect newrect = d->workrects->at(j); + const QRect oldrect = oldworkrects[j]; + const QRect newrect = d->workrects->at(j); if (oldrect != newrect) emit workAreaResized(j); } + + if (oldscreencount != d->screenCount) { + emit screenCountChanged(d->screenCount); + } } #ifdef Q_CC_MSVC diff --git a/src/gui/kernel/qdesktopwidget_x11.cpp b/src/gui/kernel/qdesktopwidget_x11.cpp index 59d3239..1555fc0 100644 --- a/src/gui/kernel/qdesktopwidget_x11.cpp +++ b/src/gui/kernel/qdesktopwidget_x11.cpp @@ -372,7 +372,32 @@ int QDesktopWidget::screenNumber(const QPoint &point) const void QDesktopWidget::resizeEvent(QResizeEvent *event) { Q_D(QDesktopWidget); + int oldScreenCount = d->screenCount; + QVector<QRect> oldRects(oldScreenCount); + QVector<QRect> oldWorks(oldScreenCount); + for (int i = 0; i < oldScreenCount; ++i) { + oldRects[i] = d->rects[i]; + oldWorks[i] = d->workareas[i]; + } + d->init(); + + for (int i = 0; i < qMin(oldScreenCount, d->screenCount); ++i) { + if (oldRects.at(i) != d->rects[i]) + emit resized(i); + } + + // ### workareas are just reset by init, not filled with new values + // ### so this will not work correctly + for (int j = 0; j < qMin(oldScreenCount, d->screenCount); ++j) { + if (oldWorks.at(j) != d->workareas[j]) + emit workAreaResized(j); + } + + if (oldScreenCount != d->screenCount) { + emit screenCountChanged(d->screenCount); + } + qt_desktopwidget_workarea_dirty = true; QWidget::resizeEvent(event); } diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index 21b96eb..a035acf 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -120,7 +120,7 @@ QInputEvent::~QInputEvent() will not be propagated further up the parent widget chain. The state of the keyboard modifier keys can be found by calling the - \l{QInputEvent::modifiers()}{modifiers()} function, inhertied from + \l{QInputEvent::modifiers()}{modifiers()} function, inherited from QInputEvent. The functions pos(), x(), and y() give the cursor position @@ -3570,21 +3570,23 @@ QMenubarUpdatedEvent::QMenubarUpdatedEvent(QMenuBar * const menuBar) #endif /*! \class QTouchEvent - \brief The QTouchEvent class contains parameters that describe a touch event -. + \brief The QTouchEvent class contains parameters that describe a touch event. \since 4.6 \ingroup events Touch events occur when pressing, releasing, or moving one or more touch points on a touch device (such as a touch-screen or - track-pad), and if the widget has the Qt::WA_AcceptTouchEvents - attribute. + track-pad). To receive touch events, widgets have to have the + Qt::WA_AcceptTouchEvents attribute set and graphics items need to have + the \l{QGraphicsItem::setAcceptTouchEvents()}{acceptTouchEvents} + attribute set to true. All touch events are of type QEvent::TouchBegin, QEvent::TouchUpdate, or QEvent::TouchEnd. The touchPoints() function returns a list of all touch points contained in the event. - Information about each touch point can be retreived using the - QTouchEvent::TouchPoint class. + Information about each touch point can be retrieved using the + QTouchEvent::TouchPoint class. The Qt::TouchPointState enum + describes the different states that a touch point may have. Similar to QMouseEvent, Qt automatically grabs each touch point on the first press inside a widget; the widget will receive all @@ -3602,10 +3604,11 @@ QMenubarUpdatedEvent::QMenubarUpdatedEvent(QMenuBar * const menuBar) then mouse events are simulated from the state of the first touch point. - The Qt::TouchPointState enum describes the different states that a - touch point may have. + Reimplement QWidget::event() for widgets and QGraphicsItem::sceneEvent() + for items in a graphics view to receive touch events. - QTouchEvent::TouchPoint Qt::TouchPointState Qt::WA_AcceptTouchEvents + \sa QTouchEvent::TouchPoint, Qt::TouchPointState, Qt::WA_AcceptTouchEvents, + QGraphicsItem::acceptTouchEvents() */ /*! \enum Qt::TouchPointState @@ -3623,13 +3626,7 @@ QMenubarUpdatedEvent::QMenubarUpdatedEvent(QMenuBar * const menuBar) \omitvalue TouchPointPrimary */ -/*! \class QTouchEvent::TouchPoint - \brief The QTouchEvent::TouchPoint class provide information about a touch point in a QTouchEvent. - \since 4.6 -*/ - /*! \enum QTouchEvent::DeviceType - \since 4.6 This enum represents the type of device that generated a QTouchEvent. @@ -3708,6 +3705,11 @@ QTouchEvent::~QTouchEvent() Sets the list of touch points for this event. */ +/*! \class QTouchEvent::TouchPoint + \brief The QTouchEvent::TouchPoint class provides information about a touch point in a QTouchEvent. + \since 4.6 +*/ + /*! \internal Constructs a QTouchEvent::TouchPoint for use in a QTouchEvent. @@ -3767,7 +3769,9 @@ bool QTouchEvent::TouchPoint::isPrimary() const /*! Returns the position of this touch point, relative to the widget - or item that received the event. + or QGraphicsItem that received the event. + + \sa startPos(), lastPos(), screenPos(), scenePos(), normalizedPos() */ QPointF QTouchEvent::TouchPoint::pos() const { @@ -3776,6 +3780,13 @@ QPointF QTouchEvent::TouchPoint::pos() const /*! Returns the scene position of this touch point. + + The scene position is the position in QGraphicsScene coordinates + if the QTouchEvent is handled by a QGraphicsItem::touchEvent() + reimplementation, and identical to the screen position for + widgets. + + \sa startScenePos(), lastScenePos(), pos() */ QPointF QTouchEvent::TouchPoint::scenePos() const { @@ -3784,6 +3795,8 @@ QPointF QTouchEvent::TouchPoint::scenePos() const /*! Returns the screen position of this touch point. + + \sa startScreenPos(), lastScreenPos(), pos() */ QPointF QTouchEvent::TouchPoint::screenPos() const { @@ -3791,8 +3804,12 @@ QPointF QTouchEvent::TouchPoint::screenPos() const } /*! - Returns the position of this touch point. The coordinates are normalized to size of the touch - device, i.e. (0,0) is the top-left corner and (1,1) is the bottom-right corner. + Returns the normalized position of this touch point. + + The coordinates are normalized to the size of the touch device, + i.e. (0,0) is the top-left corner and (1,1) is the bottom-right corner. + + \sa startNormalizedPos(), lastNormalizedPos(), pos() */ QPointF QTouchEvent::TouchPoint::normalizedPos() const { @@ -3801,7 +3818,9 @@ QPointF QTouchEvent::TouchPoint::normalizedPos() const /*! Returns the starting position of this touch point, relative to the - widget that received the event. + widget or QGraphicsItem that received the event. + + \sa pos(), lastPos() */ QPointF QTouchEvent::TouchPoint::startPos() const { @@ -3810,6 +3829,13 @@ QPointF QTouchEvent::TouchPoint::startPos() const /*! Returns the starting scene position of this touch point. + + The scene position is the position in QGraphicsScene coordinates + if the QTouchEvent is handled by a QGraphicsItem::touchEvent() + reimplementation, and identical to the screen position for + widgets. + + \sa scenePos(), lastScenePos() */ QPointF QTouchEvent::TouchPoint::startScenePos() const { @@ -3818,6 +3844,8 @@ QPointF QTouchEvent::TouchPoint::startScenePos() const /*! Returns the starting screen position of this touch point. + + \sa screenPos(), lastScreenPos() */ QPointF QTouchEvent::TouchPoint::startScreenPos() const { @@ -3825,8 +3853,12 @@ QPointF QTouchEvent::TouchPoint::startScreenPos() const } /*! - Returns the starting position of this touch point. The coordinates are normalized to size of - the touch device, i.e. (0,0) is the top-left corner and (1,1) is the bottom-right corner. + Returns the normalized starting position of this touch point. + + The coordinates are normalized to the size of the touch device, + i.e. (0,0) is the top-left corner and (1,1) is the bottom-right corner. + + \sa normalizedPos(), lastNormalizedPos() */ QPointF QTouchEvent::TouchPoint::startNormalizedPos() const { @@ -3835,7 +3867,9 @@ QPointF QTouchEvent::TouchPoint::startNormalizedPos() const /*! Returns the position of this touch point from the previous touch - event, relative to the widget that received the event. + event, relative to the widget or QGraphicsItem that received the event. + + \sa pos(), startPos() */ QPointF QTouchEvent::TouchPoint::lastPos() const { @@ -3845,6 +3879,13 @@ QPointF QTouchEvent::TouchPoint::lastPos() const /*! Returns the scene position of this touch point from the previous touch event. + + The scene position is the position in QGraphicsScene coordinates + if the QTouchEvent is handled by a QGraphicsItem::touchEvent() + reimplementation, and identical to the screen position for + widgets. + + \sa scenePos(), startScenePos() */ QPointF QTouchEvent::TouchPoint::lastScenePos() const { @@ -3854,6 +3895,8 @@ QPointF QTouchEvent::TouchPoint::lastScenePos() const /*! Returns the screen position of this touch point from the previous touch event. + + \sa screenPos(), startScreenPos() */ QPointF QTouchEvent::TouchPoint::lastScreenPos() const { @@ -3861,9 +3904,13 @@ QPointF QTouchEvent::TouchPoint::lastScreenPos() const } /*! - Returns the position of this touch point from the previous touch event. The coordinates are - normalized to size of the touch device, i.e. (0,0) is the top-left corner and (1,1) is the - bottom-right corner. + Returns the normalized position of this touch point from the + previous touch event. + + The coordinates are normalized to the size of the touch device, + i.e. (0,0) is the top-left corner and (1,1) is the bottom-right corner. + + \sa normalizedPos(), startNormalizedPos() */ QPointF QTouchEvent::TouchPoint::lastNormalizedPos() const { @@ -3871,8 +3918,11 @@ QPointF QTouchEvent::TouchPoint::lastNormalizedPos() const } /*! - Returns the rect for this touch point. The rect is centered around the point returned by pos(). - Note this function returns an empty rect if the device does not report touch point sizes. + Returns the rect for this touch point, relative to the widget + or QGraphicsItem that received the event. The rect is centered + around the point returned by pos(). + + \note This function returns an empty rect if the device does not report touch point sizes. */ QRectF QTouchEvent::TouchPoint::rect() const { @@ -3881,6 +3931,10 @@ QRectF QTouchEvent::TouchPoint::rect() const /*! Returns the rect for this touch point in scene coordinates. + + \note This function returns an empty rect if the device does not report touch point sizes. + + \sa scenePos(), rect() */ QRectF QTouchEvent::TouchPoint::sceneRect() const { @@ -3889,6 +3943,10 @@ QRectF QTouchEvent::TouchPoint::sceneRect() const /*! Returns the rect for this touch point in screen coordinates. + + \note This function returns an empty rect if the device does not report touch point sizes. + + \sa screenPos(), rect() */ QRectF QTouchEvent::TouchPoint::screenRect() const { diff --git a/src/gui/kernel/qeventdispatcher_mac.mm b/src/gui/kernel/qeventdispatcher_mac.mm index 99a1fc1..cde0c47 100644 --- a/src/gui/kernel/qeventdispatcher_mac.mm +++ b/src/gui/kernel/qeventdispatcher_mac.mm @@ -264,12 +264,16 @@ void qt_mac_socket_callback(CFSocketRef s, CFSocketCallBackType callbackType, CF int nativeSocket = CFSocketGetNative(s); MacSocketInfo *socketInfo = eventDispatcher->macSockets.value(nativeSocket); QEvent notifierEvent(QEvent::SockAct); + + // There is a race condition that happen where we disable the notifier and + // the kernel still has a notification to pass on. We then get this + // notification after we've successfully disabled the CFSocket, but our Qt + // notifier is now gone. The upshot is we have to check the notifier + // everytime. if (callbackType == kCFSocketReadCallBack) { - Q_ASSERT(socketInfo->readNotifier); - QApplication::sendEvent(socketInfo->readNotifier, ¬ifierEvent); + if (socketInfo->readNotifier) + QApplication::sendEvent(socketInfo->readNotifier, ¬ifierEvent); } else if (callbackType == kCFSocketWriteCallBack) { - // ### Bug in Apple socket notifiers seems to send write even - // ### after the notifier has been disabled, need to investigate further. if (socketInfo->writeNotifier) QApplication::sendEvent(socketInfo->writeNotifier, ¬ifierEvent); } diff --git a/src/gui/kernel/qgesture.h b/src/gui/kernel/qgesture.h index cc46916..1cd9cae 100644 --- a/src/gui/kernel/qgesture.h +++ b/src/gui/kernel/qgesture.h @@ -42,12 +42,12 @@ #ifndef QGESTURE_H #define QGESTURE_H -#include "qobject.h" -#include "qlist.h" -#include "qdatetime.h" -#include "qpoint.h" -#include "qrect.h" -#include "qmetatype.h" +#include <QtCore/qobject.h> +#include <QtCore/qlist.h> +#include <QtCore/qdatetime.h> +#include <QtCore/qpoint.h> +#include <QtCore/qrect.h> +#include <QtCore/qmetatype.h> QT_BEGIN_HEADER diff --git a/src/gui/kernel/qguivariant.cpp b/src/gui/kernel/qguivariant.cpp index 01df47d..ab69cdf 100644 --- a/src/gui/kernel/qguivariant.cpp +++ b/src/gui/kernel/qguivariant.cpp @@ -60,6 +60,11 @@ #include "qregion.h" #include "qsizepolicy.h" #include "qtextformat.h" +#include "qmatrix4x4.h" +#include "qvector2d.h" +#include "qvector3d.h" +#include "qvector4d.h" +#include "qquaternion.h" #include "private/qvariant_p.h" @@ -148,6 +153,31 @@ static void construct(QVariant::Private *x, const void *copy) v_construct<QColor>(x, &color); break; } +#ifndef QT_NO_MATRIX4X4 + case QVariant::Matrix4x4: + v_construct<QMatrix4x4>(x, copy); + break; +#endif +#ifndef QT_NO_VECTOR2D + case QVariant::Vector2D: + v_construct<QVector2D>(x, copy); + break; +#endif +#ifndef QT_NO_VECTOR3D + case QVariant::Vector3D: + v_construct<QVector3D>(x, copy); + break; +#endif +#ifndef QT_NO_VECTOR4D + case QVariant::Vector4D: + v_construct<QVector4D>(x, copy); + break; +#endif +#ifndef QT_NO_QUATERNION + case QVariant::Quaternion: + v_construct<QQuaternion>(x, copy); + break; +#endif default: qcoreVariantHandler()->construct(x, copy); return; @@ -221,6 +251,31 @@ static void clear(QVariant::Private *d) case QVariant::Pen: v_clear<QPen>(d); break; +#ifndef QT_NO_MATRIX4X4 + case QVariant::Matrix4x4: + v_clear<QMatrix4x4>(d); + break; +#endif +#ifndef QT_NO_VECTOR2D + case QVariant::Vector2D: + v_clear<QVector2D>(d); + break; +#endif +#ifndef QT_NO_VECTOR3D + case QVariant::Vector3D: + v_clear<QVector3D>(d); + break; +#endif +#ifndef QT_NO_VECTOR4D + case QVariant::Vector4D: + v_clear<QVector4D>(d); + break; +#endif +#ifndef QT_NO_QUATERNION + case QVariant::Quaternion: + v_clear<QVector4D>(d); + break; +#endif default: qcoreVariantHandler()->clear(d); return; @@ -266,7 +321,26 @@ static bool isNull(const QVariant::Private *d) case QVariant::KeySequence: #endif case QVariant::Pen: +#ifndef QT_NO_MATRIX4X4 + case QVariant::Matrix4x4: +#endif break; +#ifndef QT_NO_VECTOR2D + case QVariant::Vector2D: + return v_cast<QVector2D>(d)->isNull(); +#endif +#ifndef QT_NO_VECTOR3D + case QVariant::Vector3D: + return v_cast<QVector3D>(d)->isNull(); +#endif +#ifndef QT_NO_VECTOR4D + case QVariant::Vector4D: + return v_cast<QVector4D>(d)->isNull(); +#endif +#ifndef QT_NO_QUATERNION + case QVariant::Quaternion: + return v_cast<QQuaternion>(d)->isNull(); +#endif default: return qcoreVariantHandler()->isNull(d); } @@ -326,6 +400,26 @@ static bool compare(const QVariant::Private *a, const QVariant::Private *b) #endif case QVariant::Pen: return *v_cast<QPen>(a) == *v_cast<QPen>(b); +#ifndef QT_NO_MATRIX4X4 + case QVariant::Matrix4x4: + return *v_cast<QMatrix4x4>(a) == *v_cast<QMatrix4x4>(b); +#endif +#ifndef QT_NO_VECTOR2D + case QVariant::Vector2D: + return *v_cast<QVector2D>(a) == *v_cast<QVector2D>(b); +#endif +#ifndef QT_NO_VECTOR3D + case QVariant::Vector3D: + return *v_cast<QVector3D>(a) == *v_cast<QVector3D>(b); +#endif +#ifndef QT_NO_VECTOR4D + case QVariant::Vector4D: + return *v_cast<QVector4D>(a) == *v_cast<QVector4D>(b); +#endif +#ifndef QT_NO_QUATERNION + case QVariant::Quaternion: + return *v_cast<QQuaternion>(a) == *v_cast<QQuaternion>(b); +#endif default: break; } @@ -513,6 +607,31 @@ static void streamDebug(QDebug dbg, const QVariant &v) case QVariant::Pen: dbg.nospace() << qvariant_cast<QPen>(v); break; +#ifndef QT_NO_MATRIX4X4 + case QVariant::Matrix4x4: + dbg.nospace() << qvariant_cast<QMatrix4x4>(v); + break; +#endif +#ifndef QT_NO_VECTOR2D + case QVariant::Vector2D: + dbg.nospace() << qvariant_cast<QVector2D>(v); + break; +#endif +#ifndef QT_NO_VECTOR3D + case QVariant::Vector3D: + dbg.nospace() << qvariant_cast<QVector3D>(v); + break; +#endif +#ifndef QT_NO_VECTOR4D + case QVariant::Vector4D: + dbg.nospace() << qvariant_cast<QVector4D>(v); + break; +#endif +#ifndef QT_NO_QUATERNION + case QVariant::Quaternion: + dbg.nospace() << qvariant_cast<QQuaternion>(v); + break; +#endif default: qcoreVariantHandler()->debugStream(dbg, v); break; @@ -596,6 +715,21 @@ Q_DECL_METATYPE_HELPER(QTextLength) Q_DECL_METATYPE_HELPER(QTextFormat) Q_DECL_METATYPE_HELPER(QMatrix) Q_DECL_METATYPE_HELPER(QTransform) +#ifndef QT_NO_MATRIX4X4 +Q_DECL_METATYPE_HELPER(QMatrix4x4) +#endif +#ifndef QT_NO_VECTOR2D +Q_DECL_METATYPE_HELPER(QVector2D) +#endif +#ifndef QT_NO_VECTOR3D +Q_DECL_METATYPE_HELPER(QVector3D) +#endif +#ifndef QT_NO_VECTOR4D +Q_DECL_METATYPE_HELPER(QVector4D) +#endif +#ifndef QT_NO_QUATERNION +Q_DECL_METATYPE_HELPER(QQuaternion) +#endif #ifdef QT_NO_DATASTREAM # define Q_IMPL_METATYPE_HELPER(TYPE) \ @@ -645,7 +779,32 @@ static const QMetaTypeGuiHelper qVariantGuiHelper[] = { Q_IMPL_METATYPE_HELPER(QTextLength), Q_IMPL_METATYPE_HELPER(QTextFormat), Q_IMPL_METATYPE_HELPER(QMatrix), - Q_IMPL_METATYPE_HELPER(QTransform) + Q_IMPL_METATYPE_HELPER(QTransform), +#ifndef QT_NO_MATRIX4X4 + Q_IMPL_METATYPE_HELPER(QMatrix4x4), +#else + {0, 0, 0, 0}, +#endif +#ifndef QT_NO_VECTOR2D + Q_IMPL_METATYPE_HELPER(QVector2D), +#else + {0, 0, 0, 0}, +#endif +#ifndef QT_NO_VECTOR3D + Q_IMPL_METATYPE_HELPER(QVector3D), +#else + {0, 0, 0, 0}, +#endif +#ifndef QT_NO_VECTOR4D + Q_IMPL_METATYPE_HELPER(QVector4D), +#else + {0, 0, 0, 0}, +#endif +#ifndef QT_NO_QUATERNION + Q_IMPL_METATYPE_HELPER(QQuaternion) +#else + {0, 0, 0, 0} +#endif }; static const QVariant::Handler *qt_guivariant_last_handler = 0; diff --git a/src/gui/kernel/qkeymapper_win.cpp b/src/gui/kernel/qkeymapper_win.cpp index b13e622..0998631 100644 --- a/src/gui/kernel/qkeymapper_win.cpp +++ b/src/gui/kernel/qkeymapper_win.cpp @@ -851,8 +851,8 @@ bool QKeyMapperPrivate::translateKeyEvent(QWidget *widget, const MSG &msg, bool } } else if (msgType == WM_KEYUP) { if (dirStatus == VK_LSHIFT - && (msg.wParam == VK_SHIFT && GetKeyState(VK_LCONTROL) - || msg.wParam == VK_CONTROL && GetKeyState(VK_LSHIFT))) { + && ((msg.wParam == VK_SHIFT && GetKeyState(VK_LCONTROL)) + || (msg.wParam == VK_CONTROL && GetKeyState(VK_LSHIFT)))) { k0 = q->sendKeyEvent(widget, grab, QEvent::KeyPress, Qt::Key_Direction_L, 0, QString(), false, 0, scancode, msg.wParam, nModifiers); @@ -861,8 +861,8 @@ bool QKeyMapperPrivate::translateKeyEvent(QWidget *widget, const MSG &msg, bool scancode, msg.wParam, nModifiers); dirStatus = 0; } else if (dirStatus == VK_RSHIFT - && (msg.wParam == VK_SHIFT && GetKeyState(VK_RCONTROL) - || msg.wParam == VK_CONTROL && GetKeyState(VK_RSHIFT))) { + && ( (msg.wParam == VK_SHIFT && GetKeyState(VK_RCONTROL)) + || (msg.wParam == VK_CONTROL && GetKeyState(VK_RSHIFT)))) { k0 = q->sendKeyEvent(widget, grab, QEvent::KeyPress, Qt::Key_Direction_R, 0, QString(), false, 0, scancode, msg.wParam, nModifiers); diff --git a/src/gui/kernel/qmime_win.cpp b/src/gui/kernel/qmime_win.cpp index c7559d8..acd7cfc 100644 --- a/src/gui/kernel/qmime_win.cpp +++ b/src/gui/kernel/qmime_win.cpp @@ -170,7 +170,7 @@ static QByteArray getData(int cf, IDataObject *pDataObj) if (pDataObj->GetData(&formatetc, &s) == S_OK) { char szBuffer[4096]; ULONG actualRead = 0; - LARGE_INTEGER pos = {0, 0}; + LARGE_INTEGER pos = {{0, 0}}; //Move to front (can fail depending on the data model implemented) HRESULT hr = s.pstm->Seek(pos, STREAM_SEEK_SET, NULL); while(SUCCEEDED(hr)){ diff --git a/src/gui/kernel/qstandardgestures.h b/src/gui/kernel/qstandardgestures.h index db96ef6..2234702 100644 --- a/src/gui/kernel/qstandardgestures.h +++ b/src/gui/kernel/qstandardgestures.h @@ -42,11 +42,10 @@ #ifndef QSTANDARDGESTURES_H #define QSTANDARDGESTURES_H -#include "qevent.h" -#include "qbasictimer.h" -#include "qdebug.h" +#include <QtGui/qevent.h> +#include <QtCore/qbasictimer.h> -#include "qgesture.h" +#include <QtGui/qgesture.h> QT_BEGIN_HEADER diff --git a/src/gui/kernel/qt_cocoa_helpers_mac.mm b/src/gui/kernel/qt_cocoa_helpers_mac.mm index a98a7f8..223e36b 100644 --- a/src/gui/kernel/qt_cocoa_helpers_mac.mm +++ b/src/gui/kernel/qt_cocoa_helpers_mac.mm @@ -77,6 +77,7 @@ #include <qwidget.h> #include <qdesktopwidget.h> #include <qevent.h> +#include <qpixmapcache.h> #include <private/qevent_p.h> #include <private/qt_cocoa_helpers_mac_p.h> #include <private/qt_mac_p.h> @@ -1147,4 +1148,49 @@ QString qt_mac_get_pasteboardString() } } +QPixmap qt_mac_convert_iconref(const IconRef icon, int width, int height) +{ + QPixmap ret(width, height); + ret.fill(QColor(0, 0, 0, 0)); + + CGRect rect = CGRectMake(0, 0, width, height); + + CGContextRef ctx = qt_mac_cg_context(&ret); + CGAffineTransform old_xform = CGContextGetCTM(ctx); + CGContextConcatCTM(ctx, CGAffineTransformInvert(old_xform)); + CGContextConcatCTM(ctx, CGAffineTransformIdentity); + + ::RGBColor b; + b.blue = b.green = b.red = 255*255; + PlotIconRefInContext(ctx, &rect, kAlignNone, kTransformNone, &b, kPlotIconRefNormalFlags, icon); + CGContextRelease(ctx); + return ret; +} + +void qt_mac_constructQIconFromIconRef(const IconRef icon, const IconRef overlayIcon, QIcon *retIcon, QStyle::StandardPixmap standardIcon) +{ + int size = 16; + while (size <= 128) { + + const QString cacheKey = QLatin1String("qt_mac_constructQIconFromIconRef") + QString::number(standardIcon) + QString::number(size); + QPixmap mainIcon; + if (standardIcon >= QStyle::SP_CustomBase) { + mainIcon = qt_mac_convert_iconref(icon, size, size); + } else if (QPixmapCache::find(cacheKey, mainIcon) == false) { + mainIcon = qt_mac_convert_iconref(icon, size, size); + QPixmapCache::insert(cacheKey, mainIcon); + } + + if (overlayIcon) { + int littleSize = size / 2; + QPixmap overlayPix = qt_mac_convert_iconref(overlayIcon, littleSize, littleSize); + QPainter painter(&mainIcon); + painter.drawPixmap(size - littleSize, size - littleSize, overlayPix); + } + + retIcon->addPixmap(mainIcon); + size += size; // 16 -> 32 -> 64 -> 128 + } +} + QT_END_NAMESPACE diff --git a/src/gui/kernel/qt_cocoa_helpers_mac_p.h b/src/gui/kernel/qt_cocoa_helpers_mac_p.h index 5f6204f..af3b4cb 100644 --- a/src/gui/kernel/qt_cocoa_helpers_mac_p.h +++ b/src/gui/kernel/qt_cocoa_helpers_mac_p.h @@ -105,6 +105,8 @@ #include <qpoint.h> #include "private/qt_mac_p.h" +struct HIContentBorderMetrics; + #ifdef Q_WS_MAC32 typedef struct _NSPoint NSPoint; // Just redefine here so I don't have to pull in all of Cocoa. #else @@ -122,7 +124,6 @@ bool macWindowToolbarIsVisible( void * /*OSWindowRef*/ window ); void macWindowSetHasShadow( void * /*OSWindowRef*/ window, bool hasShadow ); void macWindowFlush(void * /*OSWindowRef*/ window); void macSendToolbarChangeEvent(QWidget *widget); -struct HIContentBorderMetrics; void qt_mac_updateContentBorderMetricts(void * /*OSWindowRef */window, const ::HIContentBorderMetrics &metrics); void * /*NSImage */qt_mac_create_nsimage(const QPixmap &pm); void qt_mac_update_mouseTracking(QWidget *widget); @@ -143,6 +144,9 @@ struct ::TabletProximityRec; void qt_dispatchTabletProximityEvent(const ::TabletProximityRec &proxRec); Qt::KeyboardModifiers qt_cocoaModifiers2QtModifiers(ulong modifierFlags); Qt::KeyboardModifiers qt_cocoaDragOperation2QtModifiers(uint dragOperations); +QPixmap qt_mac_convert_iconref(const IconRef icon, int width, int height); +void qt_mac_constructQIconFromIconRef(const IconRef icon, const IconRef overlayIcon, QIcon *retIcon, + QStyle::StandardPixmap standardIcon = QStyle::SP_CustomBase); inline int flipYCoordinate(int y) { return QApplication::desktop()->screenGeometry(0).height() - y; diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index 474bd5d..9ee877e 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -1972,10 +1972,9 @@ void QPixmap::fill( const QWidget *widget, const QPoint &off ) QPainter p(this); p.translate(-off); widget->d_func()->paintBackground(&p, QRect(off, size())); - } -static inline void fillRegion(QPainter *painter, const QRegion &rgn, const QPoint &offset, const QBrush &brush) +static inline void fillRegion(QPainter *painter, const QRegion &rgn, const QBrush &brush) { Q_ASSERT(painter); @@ -1984,26 +1983,39 @@ static inline void fillRegion(QPainter *painter, const QRegion &rgn, const QPoin // Optimize pattern filling on mac by using HITheme directly // when filling with the standard widget background. // Defined in qmacstyle_mac.cpp - extern void qt_mac_fill_background(QPainter *painter, const QRegion &rgn, const QPoint &offset, const QBrush &brush); - qt_mac_fill_background(painter, rgn, offset, brush); + extern void qt_mac_fill_background(QPainter *painter, const QRegion &rgn, const QBrush &brush); + qt_mac_fill_background(painter, rgn, brush); #else - const QRegion translated = rgn.translated(offset); - const QRect rect(translated.boundingRect()); - painter->setClipRegion(translated); + const QRect rect(rgn.boundingRect()); + painter->setClipRegion(rgn); painter->drawTiledPixmap(rect, brush.texture(), rect.topLeft()); #endif } else { const QVector<QRect> &rects = rgn.rects(); for (int i = 0; i < rects.size(); ++i) - painter->fillRect(rects.at(i).translated(offset), brush); + painter->fillRect(rects.at(i), brush); } } - -void QWidgetPrivate::paintBackground(QPainter *painter, const QRegion &rgn, const QPoint &offset, int flags) const +void QWidgetPrivate::paintBackground(QPainter *painter, const QRegion &rgn, int flags) const { Q_Q(const QWidget); +#ifndef QT_NO_SCROLLAREA + bool resetBrushOrigin = false; + QPointF oldBrushOrigin; + //If we are painting the viewport of a scrollarea, we must apply an offset to the brush in case we are drawing a texture + QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea *>(parent); + if (scrollArea && scrollArea->viewport() == q) { + QObjectData *scrollPrivate = static_cast<QWidget *>(scrollArea)->d_ptr; + QAbstractScrollAreaPrivate *priv = static_cast<QAbstractScrollAreaPrivate *>(scrollPrivate); + oldBrushOrigin = painter->brushOrigin(); + resetBrushOrigin = true; + painter->setBrushOrigin(-priv->contentsOffset()); + + } +#endif // QT_NO_SCROLLAREA + const QBrush autoFillBrush = q->palette().brush(q->backgroundRole()); if ((flags & DrawAsRoot) && !(q->autoFillBackground() && autoFillBrush.isOpaque())) { @@ -2012,18 +2024,24 @@ void QWidgetPrivate::paintBackground(QPainter *painter, const QRegion &rgn, cons if (!(flags & DontSetCompositionMode) && painter->paintEngine()->hasFeature(QPaintEngine::PorterDuff)) painter->setCompositionMode(QPainter::CompositionMode_Source); //copy alpha straight in #endif - fillRegion(painter, rgn, offset, bg); + fillRegion(painter, rgn, bg); } if (q->autoFillBackground()) - fillRegion(painter, rgn, offset, autoFillBrush); + fillRegion(painter, rgn, autoFillBrush); + if (q->testAttribute(Qt::WA_StyledBackground)) { - painter->setClipRegion(rgn.translated(offset)); + painter->setClipRegion(rgn); QStyleOption opt; opt.initFrom(q); q->style()->drawPrimitive(QStyle::PE_Widget, &opt, painter, q); } + +#ifndef QT_NO_SCROLLAREA + if (resetBrushOrigin) + painter->setBrushOrigin(oldBrushOrigin); +#endif // QT_NO_SCROLLAREA } /* @@ -5004,19 +5022,7 @@ void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QP && !q->testAttribute(Qt::WA_OpaquePaintEvent) && !q->testAttribute(Qt::WA_NoSystemBackground)) { QPainter p(q); - QPoint scrollAreaOffset; - -#ifndef QT_NO_SCROLLAREA - QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea *>(parent); - if (scrollArea && scrollArea->viewport() == q) { - QObjectData *scrollPrivate = static_cast<QWidget *>(scrollArea)->d_ptr; - QAbstractScrollAreaPrivate *priv = static_cast<QAbstractScrollAreaPrivate *>(scrollPrivate); - scrollAreaOffset = priv->contentsOffset(); - p.translate(-scrollAreaOffset); - } -#endif // QT_NO_SCROLLAREA - - paintBackground(&p, toBePainted, scrollAreaOffset, (asRoot || onScreen) ? flags | DrawAsRoot : 0); + paintBackground(&p, toBePainted, (asRoot || onScreen) ? flags | DrawAsRoot : 0); } if (!sharedPainter) diff --git a/src/gui/kernel/qwidget_mac.mm b/src/gui/kernel/qwidget_mac.mm index 5577224..1717fbd 100644 --- a/src/gui/kernel/qwidget_mac.mm +++ b/src/gui/kernel/qwidget_mac.mm @@ -1198,22 +1198,13 @@ OSStatus QWidgetPrivate::qt_widget_event(EventHandlerCallRef er, EventRef event, p.setClipping(false); if(was_unclipped) widget->setAttribute(Qt::WA_PaintUnclipped); - - QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea *>(widget->parent()); - QPoint scrollAreaOffset; - if (scrollArea && scrollArea->viewport() == widget) { - QAbstractScrollAreaPrivate *priv = static_cast<QAbstractScrollAreaPrivate *>(static_cast<QWidget *>(scrollArea)->d_ptr); - scrollAreaOffset = priv->contentsOffset(); - p.translate(-scrollAreaOffset); - } - - widget->d_func()->paintBackground(&p, qrgn, scrollAreaOffset, widget->isWindow() ? DrawAsRoot : 0); + widget->d_func()->paintBackground(&p, qrgn, widget->isWindow() ? DrawAsRoot : 0); if (widget->testAttribute(Qt::WA_TintedBackground)) { QColor tint = widget->palette().window().color(); tint.setAlphaF(.6); const QVector<QRect> &rects = qrgn.rects(); for (int i = 0; i < rects.size(); ++i) - p.fillRect(rects.at(i).translated(scrollAreaOffset), tint); + p.fillRect(rects.at(i), tint); } p.end(); if (!redirectionOffset.isNull()) diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h index 626950e..998181e 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -295,7 +295,7 @@ public: void setUpdatesEnabled_helper(bool ); - void paintBackground(QPainter *, const QRegion &, const QPoint & = QPoint(), int flags = DrawAsRoot) const; + void paintBackground(QPainter *, const QRegion &, int flags = DrawAsRoot) const; bool isAboutToShow() const; QRegion prepareToRender(const QRegion ®ion, QWidget::RenderFlags renderFlags); void render_helper(QPainter *painter, const QPoint &targetOffset, const QRegion &sourceRegion, diff --git a/src/gui/kernel/qwidget_win.cpp b/src/gui/kernel/qwidget_win.cpp index dcf541c..46fa3be 100644 --- a/src/gui/kernel/qwidget_win.cpp +++ b/src/gui/kernel/qwidget_win.cpp @@ -264,7 +264,7 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO HINSTANCE appinst = qWinAppInst(); HWND parentw, destroyw = 0; - WId id; + WId id = 0; QString windowClassName = qt_reg_winclass(q); diff --git a/src/gui/math3d/qmatrix4x4.cpp b/src/gui/math3d/qmatrix4x4.cpp index 88f58c8..b4c54a0 100644 --- a/src/gui/math3d/qmatrix4x4.cpp +++ b/src/gui/math3d/qmatrix4x4.cpp @@ -1794,6 +1794,51 @@ QDebug operator<<(QDebug dbg, const QMatrix4x4 &m) #endif -#endif +#ifndef QT_NO_DATASTREAM + +/*! + \fn QDataStream &operator<<(QDataStream &stream, const QMatrix4x4 &matrix) + \relates QMatrix4x4 + + Writes the given \a matrix to the given \a stream and returns a + reference to the stream. + + \sa {Format of the QDataStream Operators} +*/ + +QDataStream &operator<<(QDataStream &stream, const QMatrix4x4 &matrix) +{ + for (int row = 0; row < 4; ++row) + for (int col = 0; col < 4; ++col) + stream << double(matrix(row, col)); + return stream; +} + +/*! + \fn QDataStream &operator>>(QDataStream &stream, QMatrix4x4 &matrix) + \relates QMatrix4x4 + + Reads a 4x4 matrix from the given \a stream into the given \a matrix + and returns a reference to the stream. + + \sa {Format of the QDataStream Operators} +*/ + +QDataStream &operator>>(QDataStream &stream, QMatrix4x4 &matrix) +{ + double x; + for (int row = 0; row < 4; ++row) { + for (int col = 0; col < 4; ++col) { + stream >> x; + matrix(row, col) = float(x); + } + } + matrix.inferSpecialType(); + return stream; +} + +#endif // QT_NO_DATASTREAM + +#endif // QT_NO_MATRIX4X4 QT_END_NAMESPACE diff --git a/src/gui/math3d/qmatrix4x4.h b/src/gui/math3d/qmatrix4x4.h index d63de70..f7246bb 100644 --- a/src/gui/math3d/qmatrix4x4.h +++ b/src/gui/math3d/qmatrix4x4.h @@ -960,6 +960,11 @@ inline float *QMatrix4x4::data() Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QMatrix4x4 &m); #endif +#ifndef QT_NO_DATASTREAM +Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QMatrix4x4 &); +Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QMatrix4x4 &); +#endif + template <int N, int M> QMatrix4x4 qGenericMatrixToMatrix4x4(const QGenericMatrix<N, M, qreal, float>& matrix) { @@ -989,10 +994,6 @@ QGenericMatrix<N, M, qreal, float> qGenericMatrixFromMatrix4x4(const QMatrix4x4& QT_END_NAMESPACE -#ifndef QT_NO_MATRIX4X4 -Q_DECLARE_METATYPE(QMatrix4x4) -#endif - QT_END_HEADER #endif diff --git a/src/gui/math3d/qquaternion.cpp b/src/gui/math3d/qquaternion.cpp index d9d4160..841a4c0 100644 --- a/src/gui/math3d/qquaternion.cpp +++ b/src/gui/math3d/qquaternion.cpp @@ -571,6 +571,51 @@ QDebug operator<<(QDebug dbg, const QQuaternion &q) #endif +#ifndef QT_NO_DATASTREAM + +/*! + \fn QDataStream &operator<<(QDataStream &stream, const QQuaternion &quaternion) + \relates QQuaternion + + Writes the given \a quaternion to the given \a stream and returns a + reference to the stream. + + \sa {Format of the QDataStream Operators} +*/ + +QDataStream &operator<<(QDataStream &stream, const QQuaternion &quaternion) +{ + stream << double(quaternion.scalar()) << double(quaternion.x()) + << double(quaternion.y()) << double(quaternion.z()); + return stream; +} + +/*! + \fn QDataStream &operator>>(QDataStream &stream, QQuaternion &quaternion) + \relates QQuaternion + + Reads a quaternion from the given \a stream into the given \a quaternion + and returns a reference to the stream. + + \sa {Format of the QDataStream Operators} +*/ + +QDataStream &operator>>(QDataStream &stream, QQuaternion &quaternion) +{ + double scalar, x, y, z; + stream >> scalar; + stream >> x; + stream >> y; + stream >> z; + quaternion.setScalar(qreal(scalar)); + quaternion.setX(qreal(x)); + quaternion.setY(qreal(y)); + quaternion.setZ(qreal(z)); + return stream; +} + +#endif // QT_NO_DATASTREAM + #endif QT_END_NAMESPACE diff --git a/src/gui/math3d/qquaternion.h b/src/gui/math3d/qquaternion.h index 6b24a04..55c871d 100644 --- a/src/gui/math3d/qquaternion.h +++ b/src/gui/math3d/qquaternion.h @@ -324,14 +324,15 @@ inline QVector4D QQuaternion::toVector4D() const Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QQuaternion &q); #endif +#ifndef QT_NO_DATASTREAM +Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QQuaternion &); +Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QQuaternion &); #endif -QT_END_NAMESPACE - -#ifndef QT_NO_QUATERNION -Q_DECLARE_METATYPE(QQuaternion) #endif +QT_END_NAMESPACE + QT_END_HEADER #endif diff --git a/src/gui/math3d/qvector2d.cpp b/src/gui/math3d/qvector2d.cpp index b492aa8..28f6b7a 100644 --- a/src/gui/math3d/qvector2d.cpp +++ b/src/gui/math3d/qvector2d.cpp @@ -410,6 +410,46 @@ QDebug operator<<(QDebug dbg, const QVector2D &vector) #endif -#endif +#ifndef QT_NO_DATASTREAM + +/*! + \fn QDataStream &operator<<(QDataStream &stream, const QVector2D &vector) + \relates QVector2D + + Writes the given \a vector to the given \a stream and returns a + reference to the stream. + + \sa {Format of the QDataStream Operators} +*/ + +QDataStream &operator<<(QDataStream &stream, const QVector2D &vector) +{ + stream << double(vector.x()) << double(vector.y()); + return stream; +} + +/*! + \fn QDataStream &operator>>(QDataStream &stream, QVector2D &vector) + \relates QVector2D + + Reads a 2D vector from the given \a stream into the given \a vector + and returns a reference to the stream. + + \sa {Format of the QDataStream Operators} +*/ + +QDataStream &operator>>(QDataStream &stream, QVector2D &vector) +{ + double x, y; + stream >> x; + stream >> y; + vector.setX(qreal(x)); + vector.setY(qreal(y)); + return stream; +} + +#endif // QT_NO_DATASTREAM + +#endif // QT_NO_VECTOR2D QT_END_NAMESPACE diff --git a/src/gui/math3d/qvector2d.h b/src/gui/math3d/qvector2d.h index bb62afe..d473c2f 100644 --- a/src/gui/math3d/qvector2d.h +++ b/src/gui/math3d/qvector2d.h @@ -243,14 +243,15 @@ inline QPointF QVector2D::toPointF() const Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QVector2D &vector); #endif +#ifndef QT_NO_DATASTREAM +Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QVector2D &); +Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QVector2D &); #endif -QT_END_NAMESPACE - -#ifndef QT_NO_VECTOR2D -Q_DECLARE_METATYPE(QVector2D) #endif +QT_END_NAMESPACE + QT_END_HEADER #endif diff --git a/src/gui/math3d/qvector3d.cpp b/src/gui/math3d/qvector3d.cpp index 95550cd..881f47c 100644 --- a/src/gui/math3d/qvector3d.cpp +++ b/src/gui/math3d/qvector3d.cpp @@ -558,6 +558,49 @@ QDebug operator<<(QDebug dbg, const QVector3D &vector) #endif -#endif +#ifndef QT_NO_DATASTREAM + +/*! + \fn QDataStream &operator<<(QDataStream &stream, const QVector3D &vector) + \relates QVector3D + + Writes the given \a vector to the given \a stream and returns a + reference to the stream. + + \sa {Format of the QDataStream Operators} +*/ + +QDataStream &operator<<(QDataStream &stream, const QVector3D &vector) +{ + stream << double(vector.x()) << double(vector.y()) + << double(vector.z()); + return stream; +} + +/*! + \fn QDataStream &operator>>(QDataStream &stream, QVector3D &vector) + \relates QVector3D + + Reads a 3D vector from the given \a stream into the given \a vector + and returns a reference to the stream. + + \sa {Format of the QDataStream Operators} +*/ + +QDataStream &operator>>(QDataStream &stream, QVector3D &vector) +{ + double x, y, z; + stream >> x; + stream >> y; + stream >> z; + vector.setX(qreal(x)); + vector.setY(qreal(y)); + vector.setZ(qreal(z)); + return stream; +} + +#endif // QT_NO_DATASTREAM + +#endif // QT_NO_VECTOR3D QT_END_NAMESPACE diff --git a/src/gui/math3d/qvector3d.h b/src/gui/math3d/qvector3d.h index 873b388..7494dcf 100644 --- a/src/gui/math3d/qvector3d.h +++ b/src/gui/math3d/qvector3d.h @@ -271,14 +271,15 @@ inline QPointF QVector3D::toPointF() const Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QVector3D &vector); #endif +#ifndef QT_NO_DATASTREAM +Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QVector3D &); +Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QVector3D &); #endif -QT_END_NAMESPACE - -#ifndef QT_NO_VECTOR3D -Q_DECLARE_METATYPE(QVector3D) #endif +QT_END_NAMESPACE + QT_END_HEADER #endif diff --git a/src/gui/math3d/qvector4d.cpp b/src/gui/math3d/qvector4d.cpp index 1f7d921..1a84db6 100644 --- a/src/gui/math3d/qvector4d.cpp +++ b/src/gui/math3d/qvector4d.cpp @@ -509,6 +509,51 @@ QDebug operator<<(QDebug dbg, const QVector4D &vector) #endif -#endif +#ifndef QT_NO_DATASTREAM + +/*! + \fn QDataStream &operator<<(QDataStream &stream, const QVector4D &vector) + \relates QVector4D + + Writes the given \a vector to the given \a stream and returns a + reference to the stream. + + \sa {Format of the QDataStream Operators} +*/ + +QDataStream &operator<<(QDataStream &stream, const QVector4D &vector) +{ + stream << double(vector.x()) << double(vector.y()) + << double(vector.z()) << double(vector.w()); + return stream; +} + +/*! + \fn QDataStream &operator>>(QDataStream &stream, QVector4D &vector) + \relates QVector4D + + Reads a 4D vector from the given \a stream into the given \a vector + and returns a reference to the stream. + + \sa {Format of the QDataStream Operators} +*/ + +QDataStream &operator>>(QDataStream &stream, QVector4D &vector) +{ + double x, y, z, w; + stream >> x; + stream >> y; + stream >> z; + stream >> w; + vector.setX(qreal(x)); + vector.setY(qreal(y)); + vector.setZ(qreal(z)); + vector.setW(qreal(w)); + return stream; +} + +#endif // QT_NO_DATASTREAM + +#endif // QT_NO_VECTOR4D QT_END_NAMESPACE diff --git a/src/gui/math3d/qvector4d.h b/src/gui/math3d/qvector4d.h index dcfd87a..cd61496 100644 --- a/src/gui/math3d/qvector4d.h +++ b/src/gui/math3d/qvector4d.h @@ -276,14 +276,15 @@ inline QPointF QVector4D::toPointF() const Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QVector4D &vector); #endif +#ifndef QT_NO_DATASTREAM +Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QVector4D &); +Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QVector4D &); #endif -QT_END_NAMESPACE - -#ifndef QT_NO_VECTOR4D -Q_DECLARE_METATYPE(QVector4D) #endif +QT_END_NAMESPACE + QT_END_HEADER #endif diff --git a/src/gui/painting/qdrawutil.cpp b/src/gui/painting/qdrawutil.cpp index bcea571..062c3a9 100644 --- a/src/gui/painting/qdrawutil.cpp +++ b/src/gui/painting/qdrawutil.cpp @@ -1008,8 +1008,7 @@ void qDrawItem(QPainter *p, Qt::GUIStyle gs, ; #ifndef QT_NO_IMAGE_HEURISTIC_MASK } else { // color pixmap, no mask - QString k; - k.sprintf("$qt-drawitem-%llx", pm.cacheKey()); + QString k = QString::fromLatin1("$qt-drawitem-%1").arg(pm.cacheKey()); if (!QPixmapCache::find(k, pm)) { pm = pm.createHeuristicMask(); pm.setMask((QBitmap&)pm); diff --git a/src/gui/painting/qdrawutil.h b/src/gui/painting/qdrawutil.h index 8f6797c..ce07c1f 100644 --- a/src/gui/painting/qdrawutil.h +++ b/src/gui/painting/qdrawutil.h @@ -133,7 +133,7 @@ Q_GUI_EXPORT QT3_SUPPORT void qDrawArrow(QPainter *p, Qt::ArrowType type, Qt::GU const QPalette &pal, bool enabled); #endif -struct Q_GUI_EXPORT QMargins +struct QMargins { inline QMargins(int margin = 0) : top(margin), @@ -151,7 +151,7 @@ struct Q_GUI_EXPORT QMargins int right; }; -struct Q_GUI_EXPORT QTileRules +struct QTileRules { inline QTileRules(Qt::TileRule horizontalRule, Qt::TileRule verticalRule = Qt::Stretch) : horizontal(horizontalRule), vertical(verticalRule) {} @@ -168,8 +168,7 @@ Q_GUI_EXPORT void qDrawBorderPixmap(QPainter *painter, const QRect &sourceRect, const QMargins &sourceMargins, const QTileRules &rules = QTileRules()); - -Q_GUI_EXPORT inline void qDrawBorderPixmap(QPainter *painter, +inline void qDrawBorderPixmap(QPainter *painter, const QRect &target, const QMargins &margins, const QPixmap &pixmap) diff --git a/src/gui/painting/qgraphicssystemfactory.cpp b/src/gui/painting/qgraphicssystemfactory.cpp index b618d8b..ddc66f3 100644 --- a/src/gui/painting/qgraphicssystemfactory.cpp +++ b/src/gui/painting/qgraphicssystemfactory.cpp @@ -64,6 +64,10 @@ QGraphicsSystem *QGraphicsSystemFactory::create(const QString& key) if (system.isEmpty()) { system = QLatin1String("opengl"); } +#elif defined (QT_GRAPHICSSYSTEM_OPENVG) + if (system.isEmpty()) { + system = QLatin1String("openvg"); + } #elif defined (QT_GRAPHICSSYSTEM_RASTER) && !defined(Q_WS_WIN) if (system.isEmpty()) { system = QLatin1String("raster"); diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 4c35004..e9ff752 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -110,10 +110,6 @@ extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // #define qt_swap_int(x, y) { int tmp = (x); (x) = (y); (y) = tmp; } #define qt_swap_qreal(x, y) { qreal tmp = (x); (x) = (y); (y) = tmp; } -#ifdef Q_WS_WIN -static bool qt_enable_16bit_colors = false; -#endif - // #define QT_DEBUG_DRAW #ifdef QT_DEBUG_DRAW void dumpClip(int width, int height, QClipData *clip); @@ -4661,104 +4657,6 @@ static int qt_intersect_spans(QT_FT_Span *spans, int numSpans, return n; } -/* - \internal - Clip spans to \a{clip}-region. - Returns number of unclipped spans -*/ -static int qt_intersect_spans(QT_FT_Span *spans, int numSpans, - int *currSpan, - QT_FT_Span *outSpans, int maxOut, - const QRegion &clip) -{ - const QVector<QRect> rects = clip.rects(); - const int numRects = rects.size(); - - int r = 0; - short miny, minx, maxx, maxy; - { - const QRect &rect = rects[0]; - miny = rect.top(); - minx = rect.left(); - maxx = rect.right(); - maxy = rect.bottom(); - } - - // TODO: better mapping of currY and startRect - - int n = 0; - int i = *currSpan; - int currY = spans[i].y; - while (i < numSpans) { - - if (spans[i].y != currY && r != 0) { - currY = spans[i].y; - r = 0; - const QRect &rect = rects[r]; - miny = rect.top(); - minx = rect.left(); - maxx = rect.right(); - maxy = rect.bottom(); - } - - if (spans[i].y < miny) { - ++i; - continue; - } - - if (spans[i].y > maxy || spans[i].x > maxx) { - if (++r >= numRects) { - ++i; - continue; - } - - const QRect &rect = rects[r]; - miny = rect.top(); - minx = rect.left(); - maxx = rect.right(); - maxy = rect.bottom(); - continue; - } - - if (spans[i].x + spans[i].len <= minx) { - ++i; - continue; - } - - outSpans[n].y = spans[i].y; - outSpans[n].coverage = spans[i].coverage; - - if (spans[i].x < minx) { - const ushort cutaway = minx - spans[i].x; - outSpans[n].len = qMin(spans[i].len - cutaway, maxx - minx + 1); - outSpans[n].x = minx; - if (outSpans[n].len == spans[i].len - cutaway) { - ++i; - } else { - // span wider than current rect - spans[i].len -= outSpans[n].len + cutaway; - spans[i].x = maxx + 1; - } - } else { // span starts inside current rect - outSpans[n].x = spans[i].x; - outSpans[n].len = qMin(spans[i].len, - ushort(maxx - spans[i].x + 1)); - if (outSpans[n].len == spans[i].len) { - ++i; - } else { - // span wider than current rect - spans[i].len -= outSpans[n].len; - spans[i].x = maxx + 1; - } - } - - if (++n >= maxOut) - break; - } - - *currSpan = i; - return n; -} static void qt_span_fill_clipRect(int count, const QSpan *spans, void *userData) diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp index 178d519..6735ee6 100644 --- a/src/gui/painting/qpdf.cpp +++ b/src/gui/painting/qpdf.cpp @@ -968,8 +968,7 @@ QPdfBaseEngine::QPdfBaseEngine(QPdfBaseEnginePrivate &dd, PaintEngineFeatures f) void QPdfBaseEngine::drawPoints (const QPointF *points, int pointCount) { - Q_D(QPdfBaseEngine); - if (!points || !d->hasPen) + if (!points) return; QPainterPath p; @@ -999,6 +998,12 @@ void QPdfBaseEngine::drawRects (const QRectF *rects, int rectCount) return; Q_D(QPdfBaseEngine); + if (d->useAlphaEngine) { + QAlphaPaintEngine::drawRects(rects, rectCount); + if (!continueCall()) + return; + } + if (d->clipEnabled && d->allClipped) return; if (!d->hasPen && !d->hasBrush) diff --git a/src/gui/painting/qprinter.cpp b/src/gui/painting/qprinter.cpp index 8823b18..411b74d 100644 --- a/src/gui/painting/qprinter.cpp +++ b/src/gui/painting/qprinter.cpp @@ -793,7 +793,8 @@ QPrinter::OutputFormat QPrinter::outputFormat() const -/*! \reimp */ +/*! \internal +*/ int QPrinter::devType() const { return QInternal::Printer; diff --git a/src/gui/painting/qregion_win.cpp b/src/gui/painting/qregion_win.cpp index 873439e..249b1a6 100644 --- a/src/gui/painting/qregion_win.cpp +++ b/src/gui/painting/qregion_win.cpp @@ -59,7 +59,7 @@ HRGN qt_tryCreateRegion(QRegion::RegionType type, int left, int top, int right, { const int tries = 10; for (int i = 0; i < tries; ++i) { - HRGN region; + HRGN region = 0; switch (type) { case QRegion::Rectangle: region = CreateRectRgn(left, top, right, bottom); diff --git a/src/gui/painting/qwindowsurface_qws.cpp b/src/gui/painting/qwindowsurface_qws.cpp index 639bc92..d5a5c20 100644 --- a/src/gui/painting/qwindowsurface_qws.cpp +++ b/src/gui/painting/qwindowsurface_qws.cpp @@ -421,7 +421,8 @@ QWSWindowSurface::QWSWindowSurface(QWidget *widget) QWSWindowSurface::~QWSWindowSurface() { #ifdef Q_BACKINGSTORE_SUBSURFACES - winIdToSurfaceMap()->remove(winId()); + if (d_ptr->winId) + winIdToSurfaceMap()->remove(d_ptr->winId); #endif delete d_ptr; diff --git a/src/gui/styles/gtksymbols.cpp b/src/gui/styles/gtksymbols.cpp index f553d27..c2c7876 100644 --- a/src/gui/styles/gtksymbols.cpp +++ b/src/gui/styles/gtksymbols.cpp @@ -68,6 +68,7 @@ #include <QtGui/QStatusBar> #include <QtGui/QMenuBar> #include <QtGui/QToolBar> +#include <QtGui/QToolButton> #include <QtGui/QX11Info> #include <X11/Xlib.h> @@ -166,6 +167,7 @@ Ptr_gtk_file_filter_set_name QGtk::gtk_file_filter_set_name = 0; Ptr_gtk_file_filter_add_pattern QGtk::gtk_file_filter_add_pattern = 0; Ptr_gtk_file_chooser_add_filter QGtk::gtk_file_chooser_add_filter = 0; Ptr_gtk_file_chooser_set_filter QGtk::gtk_file_chooser_set_filter = 0; +Ptr_gtk_file_chooser_get_filter QGtk::gtk_file_chooser_get_filter = 0; Ptr_gtk_file_chooser_dialog_new QGtk::gtk_file_chooser_dialog_new = 0; Ptr_gtk_file_chooser_set_current_folder QGtk::gtk_file_chooser_set_current_folder = 0; Ptr_gtk_file_chooser_get_filename QGtk::gtk_file_chooser_get_filename = 0; @@ -220,6 +222,7 @@ static void resolveGtk() QGtk::gtk_file_filter_add_pattern = (Ptr_gtk_file_filter_add_pattern)libgtk.resolve("gtk_file_filter_add_pattern"); QGtk::gtk_file_chooser_add_filter = (Ptr_gtk_file_chooser_add_filter)libgtk.resolve("gtk_file_chooser_add_filter"); QGtk::gtk_file_chooser_set_filter = (Ptr_gtk_file_chooser_set_filter)libgtk.resolve("gtk_file_chooser_set_filter"); + QGtk::gtk_file_chooser_get_filter = (Ptr_gtk_file_chooser_get_filter)libgtk.resolve("gtk_file_chooser_get_filter"); QGtk::gtk_file_chooser_dialog_new = (Ptr_gtk_file_chooser_dialog_new)libgtk.resolve("gtk_file_chooser_dialog_new"); QGtk::gtk_file_chooser_set_current_folder = (Ptr_gtk_file_chooser_set_current_folder)libgtk.resolve("gtk_file_chooser_set_current_folder"); QGtk::gtk_file_chooser_get_filename = (Ptr_gtk_file_chooser_get_filename)libgtk.resolve("gtk_file_chooser_get_filename"); @@ -633,6 +636,20 @@ GtkStyle* QGtk::gtkStyle(const QString &path) return 0; } +static void update_toolbar_style(GtkWidget *gtkToolBar, GParamSpec *pspec, gpointer user_data) +{ + GtkToolbarStyle toolbar_style = GTK_TOOLBAR_ICONS; + g_object_get(gtkToolBar, "toolbar-style", &toolbar_style, NULL); + QWidgetList widgets = QApplication::allWidgets(); + for (int i = 0; i < widgets.size(); ++i) { + QWidget *widget = widgets.at(i); + if (qobject_cast<QToolButton*>(widget)) { + QEvent event(QEvent::StyleChange); + QApplication::sendEvent(widget, &event); + } + } +} + void QGtk::initGtkWidgets() { // From gtkmain.c @@ -679,6 +696,7 @@ void QGtk::initGtkWidgets() add_widget(QGtk::gtk_spin_button_new((GtkAdjustment*) (QGtk::gtk_adjustment_new(1, 0, 1, 0, 0, 0)), 0.1, 3)); GtkWidget *toolbar = QGtk::gtk_toolbar_new(); + g_signal_connect (toolbar, "notify::toolbar-style", G_CALLBACK (update_toolbar_style), toolbar); QGtk::gtk_toolbar_insert((GtkToolbar*)toolbar, QGtk::gtk_separator_tool_item_new(), -1); add_widget(toolbar); init_gtk_treeview(); @@ -720,7 +738,8 @@ extern QStringList qt_make_filter_list(const QString &filter); static void setupGtkFileChooser(GtkWidget* gtkFileChooser, QWidget *parent, const QString &dir, const QString &filter, QString *selectedFilter, - QFileDialog::Options options, bool isSaveDialog = false) + QFileDialog::Options options, bool isSaveDialog = false, + QMap<GtkFileFilter *, QString> *filterMap = 0) { g_object_set(gtkFileChooser, "do-overwrite-confirmation", gboolean(!(options & QFileDialog::DontConfirmOverwrite)), NULL); g_object_set(gtkFileChooser, "local_only", gboolean(true), NULL); @@ -735,6 +754,8 @@ static void setupGtkFileChooser(GtkWidget* gtkFileChooser, QWidget *parent, foreach (const QString &fileExtension, extensions) { QGtk::gtk_file_filter_add_pattern (gtkFilter, qPrintable(fileExtension)); } + if (filterMap) + filterMap->insert(gtkFilter, rawfilter); QGtk::gtk_file_chooser_add_filter((GtkFileChooser*)gtkFileChooser, gtkFilter); if (selectedFilter && (rawfilter == *selectedFilter)) QGtk::gtk_file_chooser_set_filter((GtkFileChooser*)gtkFileChooser, gtkFilter); @@ -771,7 +792,7 @@ static void setupGtkFileChooser(GtkWidget* gtkFileChooser, QWidget *parent, QString QGtk::openFilename(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options) { - + QMap<GtkFileFilter *, QString> filterMap; GtkWidget *gtkFileChooser = QGtk::gtk_file_chooser_dialog_new (qPrintable(caption), NULL, GTK_FILE_CHOOSER_ACTION_OPEN, @@ -779,7 +800,7 @@ QString QGtk::openFilename(QWidget *parent, const QString &caption, const QStrin GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); - setupGtkFileChooser(gtkFileChooser, parent, dir, filter, selectedFilter, options); + setupGtkFileChooser(gtkFileChooser, parent, dir, filter, selectedFilter, options, false, &filterMap); QWidget modal_widget; modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true); @@ -791,6 +812,10 @@ QString QGtk::openFilename(QWidget *parent, const QString &caption, const QStrin char *gtk_filename = QGtk::gtk_file_chooser_get_filename ((GtkFileChooser*)gtkFileChooser); filename = QString::fromUtf8(gtk_filename); g_free (gtk_filename); + if (selectedFilter) { + GtkFileFilter *gtkFilter = QGtk::gtk_file_chooser_get_filter ((GtkFileChooser*)gtkFileChooser); + *selectedFilter = filterMap.value(gtkFilter); + } } QApplicationPrivate::leaveModal(&modal_widget); @@ -801,6 +826,7 @@ QString QGtk::openFilename(QWidget *parent, const QString &caption, const QStrin QString QGtk::openDirectory(QWidget *parent, const QString &caption, const QString &dir, QFileDialog::Options options) { + QMap<GtkFileFilter *, QString> filterMap; GtkWidget *gtkFileChooser = QGtk::gtk_file_chooser_dialog_new (qPrintable(caption), NULL, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, @@ -830,6 +856,7 @@ QStringList QGtk::openFilenames(QWidget *parent, const QString &caption, const Q QString *selectedFilter, QFileDialog::Options options) { QStringList filenames; + QMap<GtkFileFilter *, QString> filterMap; GtkWidget *gtkFileChooser = QGtk::gtk_file_chooser_dialog_new (qPrintable(caption), NULL, GTK_FILE_CHOOSER_ACTION_OPEN, @@ -837,7 +864,7 @@ QStringList QGtk::openFilenames(QWidget *parent, const QString &caption, const Q GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); - setupGtkFileChooser(gtkFileChooser, parent, dir, filter, selectedFilter, options); + setupGtkFileChooser(gtkFileChooser, parent, dir, filter, selectedFilter, options, false, &filterMap); g_object_set(gtkFileChooser, "select-multiple", gboolean(true), NULL); QWidget modal_widget; @@ -850,6 +877,10 @@ QStringList QGtk::openFilenames(QWidget *parent, const QString &caption, const Q for (GSList *iterator = gtk_file_names ; iterator; iterator = iterator->next) filenames << QString::fromUtf8((const char*)iterator->data); g_slist_free(gtk_file_names); + if (selectedFilter) { + GtkFileFilter *gtkFilter = QGtk::gtk_file_chooser_get_filter ((GtkFileChooser*)gtkFileChooser); + *selectedFilter = filterMap.value(gtkFilter); + } } QApplicationPrivate::leaveModal(&modal_widget); @@ -860,13 +891,14 @@ QStringList QGtk::openFilenames(QWidget *parent, const QString &caption, const Q QString QGtk::saveFilename(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options) { + QMap<GtkFileFilter *, QString> filterMap; GtkWidget *gtkFileChooser = QGtk::gtk_file_chooser_dialog_new (qPrintable(caption), NULL, GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); - setupGtkFileChooser(gtkFileChooser, parent, dir, filter, selectedFilter, options, true); + setupGtkFileChooser(gtkFileChooser, parent, dir, filter, selectedFilter, options, true, &filterMap); QWidget modal_widget; modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true); @@ -878,6 +910,10 @@ QString QGtk::saveFilename(QWidget *parent, const QString &caption, const QStrin char *gtk_filename = QGtk::gtk_file_chooser_get_filename ((GtkFileChooser*)gtkFileChooser); filename = QString::fromUtf8(gtk_filename); g_free (gtk_filename); + if (selectedFilter) { + GtkFileFilter *gtkFilter = QGtk::gtk_file_chooser_get_filter ((GtkFileChooser*)gtkFileChooser); + *selectedFilter = filterMap.value(gtkFilter); + } } QApplicationPrivate::leaveModal(&modal_widget); diff --git a/src/gui/styles/gtksymbols_p.h b/src/gui/styles/gtksymbols_p.h index b0195d2..18c6dc5 100644 --- a/src/gui/styles/gtksymbols_p.h +++ b/src/gui/styles/gtksymbols_p.h @@ -162,6 +162,7 @@ typedef void (*Ptr_gtk_file_filter_set_name)(GtkFileFilter *, const gchar *); typedef void (*Ptr_gtk_file_filter_add_pattern)(GtkFileFilter *filter, const gchar *pattern); typedef void (*Ptr_gtk_file_chooser_add_filter)(GtkFileChooser *chooser, GtkFileFilter *filter); typedef void (*Ptr_gtk_file_chooser_set_filter)(GtkFileChooser *chooser, GtkFileFilter *filter); +typedef GtkFileFilter* (*Ptr_gtk_file_chooser_get_filter)(GtkFileChooser *chooser); typedef gchar* (*Ptr_gtk_file_chooser_get_filename)(GtkFileChooser *chooser); typedef GSList* (*Ptr_gtk_file_chooser_get_filenames)(GtkFileChooser *chooser); typedef GtkWidget* (*Ptr_gtk_file_chooser_dialog_new)(const gchar *title, @@ -302,6 +303,7 @@ public: static Ptr_gtk_file_filter_add_pattern gtk_file_filter_add_pattern; static Ptr_gtk_file_chooser_add_filter gtk_file_chooser_add_filter; static Ptr_gtk_file_chooser_set_filter gtk_file_chooser_set_filter; + static Ptr_gtk_file_chooser_get_filter gtk_file_chooser_get_filter; static Ptr_gtk_file_chooser_dialog_new gtk_file_chooser_dialog_new; static Ptr_gtk_file_chooser_set_current_folder gtk_file_chooser_set_current_folder; static Ptr_gtk_file_chooser_get_filename gtk_file_chooser_get_filename; diff --git a/src/gui/styles/qcleanlooksstyle.cpp b/src/gui/styles/qcleanlooksstyle.cpp index 01f19c6..8f88781 100644 --- a/src/gui/styles/qcleanlooksstyle.cpp +++ b/src/gui/styles/qcleanlooksstyle.cpp @@ -1745,10 +1745,9 @@ void QCleanlooksStyle::drawControl(ControlElement element, const QStyleOption *o int maxWidth = rect.width() - 4; int minWidth = 4; - qint64 progress = (qint64)qMax(bar->progress, bar->minimum); // workaround for bug in QProgressBar - double vc6_workaround = ((progress - qint64(bar->minimum)) / qMax(double(1.0), double(qint64(bar->maximum) - qint64(bar->minimum))) * maxWidth); - int progressBarWidth = (int(vc6_workaround) > minWidth ) ? int(vc6_workaround) : minWidth; - int width = indeterminate ? maxWidth : progressBarWidth; + qreal progress = qMax(bar->progress, bar->minimum); // workaround for bug in QProgressBar + int progressBarWidth = (progress - bar->minimum) * qreal(maxWidth) / qMax(qreal(1.0), qreal(bar->maximum) - bar->minimum); + int width = indeterminate ? maxWidth : qMax(minWidth, progressBarWidth); bool reverse = (!vertical && (bar->direction == Qt::RightToLeft)) || vertical; if (inverted) diff --git a/src/gui/styles/qcommonstyle.cpp b/src/gui/styles/qcommonstyle.cpp index 7b8b75e..308a0b8 100644 --- a/src/gui/styles/qcommonstyle.cpp +++ b/src/gui/styles/qcommonstyle.cpp @@ -84,6 +84,8 @@ #ifdef Q_WS_X11 # include <private/qt_x11_p.h> +#elif defined(Q_WS_MAC) +# include <private/qt_cocoa_helpers_mac_p.h> #endif QT_BEGIN_NAMESPACE @@ -840,6 +842,11 @@ static void drawArrow(const QStyle *style, const QStyleOptionToolButton *toolbut #ifdef Q_WS_X11 // These functions are used to parse the X11 freedesktop icon spec +static int kdeVersion() +{ + static int kdeVersion = qgetenv("KDE_SESSION_VERSION").toInt(); + return kdeVersion; +} void QCommonStylePrivate::lookupIconTheme() const { @@ -858,8 +865,7 @@ void QCommonStylePrivate::lookupIconTheme() const QFileInfo fileInfo(QLatin1String("/usr/share/icons/default.kde")); QDir dir(fileInfo.canonicalFilePath()); - int kdeVersion = qgetenv("KDE_SESSION_VERSION").toInt(); - QString kdeDefault = kdeVersion >= 4 ? QString::fromLatin1("oxygen") : QString::fromLatin1("crystalsvg"); + QString kdeDefault = kdeVersion() >= 4 ? QString::fromLatin1("oxygen") : QString::fromLatin1("crystalsvg"); QString defaultTheme = fileInfo.exists() ? dir.dirName() : kdeDefault; QSettings settings(QApplicationPrivate::kdeHome() + QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat); @@ -997,6 +1003,29 @@ QIcon QCommonStylePrivate::createIcon(const QString &name) const icon.addPixmap(findIcon(32, name)); return icon; } +/*!internal + +Checks if you are running KDE and looks up the toolbar +from the KDE configuration file + +*/ +int QCommonStylePrivate::lookupToolButtonStyle() const +{ + int result = Qt::ToolButtonIconOnly; + if (kdeVersion() >= 4) { + QSettings settings(QApplicationPrivate::kdeHome() + + QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat); + settings.beginGroup(QLatin1String("Toolbar style")); + QString toolbarStyle = settings.value(QLatin1String("ToolButtonStyle"), QLatin1String("TextBesideIcon")).toString(); + if (toolbarStyle == QLatin1String("TextBesideIcon")) + result = Qt::ToolButtonTextBesideIcon; + else if (toolbarStyle == QLatin1String("TextOnly")) + result = Qt::ToolButtonTextOnly; + else if (toolbarStyle == QLatin1String("TextUnderIcon")) + result = Qt::ToolButtonTextUnderIcon; + } + return result; +} #endif //Q_WS_X11 @@ -1155,8 +1184,14 @@ void QCommonStylePrivate::viewItemDrawText(QPainter *p, const QStyleOptionViewIt } } -/* Set sizehint to false to layout the elements inside opt->rect. Set sizehint to true to ignore - opt->rect and return rectangles in infinite space */ +/*! \internal + compute the position for the different component of an item (pixmap, text, checkbox) + + Set sizehint to false to layout the elements inside opt->rect. Set sizehint to true to ignore + opt->rect and return rectangles in infinite space + + Code duplicated in QItemDelegate::doLayout +*/ void QCommonStylePrivate::viewItemLayout(const QStyleOptionViewItemV4 *opt, QRect *checkRect, QRect *pixmapRect, QRect *textRect, bool sizehint) const { @@ -1177,8 +1212,10 @@ void QCommonStylePrivate::viewItemLayout(const QStyleOptionViewItemV4 *opt, QRe int y = opt->rect.top(); int w, h; - if (textRect->height() == 0 && !hasPixmap) + if (textRect->height() == 0 && (!hasPixmap || !sizehint)) { + //if there is no text, we still want to have a decent height for the item sizeHint and the editor size textRect->setHeight(opt->fontMetrics.height()); + } QSize pm(0, 0); if (hasPixmap) { @@ -4841,7 +4878,14 @@ int QCommonStyle::pixelMetric(PixelMetric m, const QStyleOption *opt, const QWid ret = int(QStyleHelper::dpiScaled(13.)); break; case PM_MessageBoxIconSize: - ret = int(QStyleHelper::dpiScaled(32.)); +#ifdef Q_WS_MAC + if (QApplication::desktopSettingsAware()) { + ret = 64; // No DPI scaling, it's handled elsewhere. + } else +#endif + { + ret = int(QStyleHelper::dpiScaled(32.)); + } break; case PM_TextCursorWidth: ret = 1; @@ -5290,6 +5334,16 @@ int QCommonStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget case SH_DockWidget_ButtonsHaveFrame: ret = true; break; + case SH_ToolButtonStyle: + ret = Qt::ToolButtonIconOnly; +#ifdef Q_WS_X11 + { + Q_D(const QCommonStyle); + static int buttonStyle = d->lookupToolButtonStyle(); + return buttonStyle; + } +#endif + break; default: ret = 0; break; @@ -5729,9 +5783,9 @@ QIcon QCommonStyle::standardIconImplementation(StandardPixmap standardIcon, cons const QWidget *widget) const { QIcon icon; -#ifdef Q_WS_X11 - Q_D(const QCommonStyle); if (QApplication::desktopSettingsAware()) { +#ifdef Q_WS_X11 + Q_D(const QCommonStyle); d->lookupIconTheme(); QPixmap pixmap; switch (standardIcon) { @@ -5750,6 +5804,7 @@ QIcon QCommonStyle::standardIconImplementation(StandardPixmap standardIcon, cons case SP_MessageBoxWarning: { icon = d->createIcon(QLatin1String("dialog-warning.png")); + icon = d->createIcon(QLatin1String("dialog-warning.png")); if (icon.isNull()) icon = d->createIcon(QLatin1String("messagebox_warning.png")); break; @@ -5975,8 +6030,101 @@ QIcon QCommonStyle::standardIconImplementation(StandardPixmap standardIcon, cons } if (!icon.isNull()) return icon; +#elif defined(Q_WS_MAC) + OSType iconType = 0; + switch (standardIcon) { + case QStyle::SP_MessageBoxQuestion: + case QStyle::SP_MessageBoxInformation: + case QStyle::SP_MessageBoxWarning: + case QStyle::SP_MessageBoxCritical: + iconType = kGenericApplicationIcon; + break; + case SP_DesktopIcon: + iconType = kDesktopIcon; + break; + case SP_TrashIcon: + iconType = kTrashIcon; + break; + case SP_ComputerIcon: + iconType = kComputerIcon; + break; + case SP_DriveFDIcon: + iconType = kGenericFloppyIcon; + break; + case SP_DriveHDIcon: + iconType = kGenericHardDiskIcon; + break; + case SP_DriveCDIcon: + case SP_DriveDVDIcon: + iconType = kGenericCDROMIcon; + break; + case SP_DriveNetIcon: + iconType = kGenericNetworkIcon; + break; + case SP_DirOpenIcon: + iconType = kOpenFolderIcon; + break; + case SP_DirClosedIcon: + case SP_DirLinkIcon: + iconType = kGenericFolderIcon; + break; + case SP_FileLinkIcon: + case SP_FileIcon: + iconType = kGenericDocumentIcon; + break; + case SP_DirIcon: { + // A rather special case + QIcon closeIcon = QStyle::standardIcon(SP_DirClosedIcon, option, widget); + QIcon openIcon = QStyle::standardIcon(SP_DirOpenIcon, option, widget); + closeIcon.addPixmap(openIcon.pixmap(16, 16), QIcon::Normal, QIcon::On); + closeIcon.addPixmap(openIcon.pixmap(32, 32), QIcon::Normal, QIcon::On); + closeIcon.addPixmap(openIcon.pixmap(64, 64), QIcon::Normal, QIcon::On); + closeIcon.addPixmap(openIcon.pixmap(128, 128), QIcon::Normal, QIcon::On); + return closeIcon; } -#endif//Q_WS_X11 + case SP_TitleBarNormalButton: + case SP_TitleBarCloseButton: { + QIcon titleBarIcon; + if (standardIcon == SP_TitleBarCloseButton) { + titleBarIcon.addFile(QLatin1String(":/trolltech/styles/macstyle/images/closedock-16.png")); + titleBarIcon.addFile(QLatin1String(":/trolltech/styles/macstyle/images/closedock-down-16.png"), QSize(16, 16), QIcon::Normal, QIcon::On); + } else { + titleBarIcon.addFile(QLatin1String(":/trolltech/styles/macstyle/images/dockdock-16.png")); + titleBarIcon.addFile(QLatin1String(":/trolltech/styles/macstyle/images/dockdock-down-16.png"), QSize(16, 16), QIcon::Normal, QIcon::On); + } + return titleBarIcon; + } + default: + break; + } + if (iconType != 0) { + QIcon retIcon; + IconRef icon; + IconRef overlayIcon = 0; + if (iconType != kGenericApplicationIcon) { + GetIconRef(kOnSystemDisk, kSystemIconsCreator, iconType, &icon); + } else { + FSRef fsRef; + ProcessSerialNumber psn = { 0, kCurrentProcess }; + GetProcessBundleLocation(&psn, &fsRef); + GetIconRefFromFileInfo(&fsRef, 0, 0, 0, 0, kIconServicesNormalUsageFlag, &icon, 0); + if (standardIcon == SP_MessageBoxCritical) { + overlayIcon = icon; + GetIconRef(kOnSystemDisk, kSystemIconsCreator, kAlertCautionIcon, &icon); + } + } + if (icon) { + qt_mac_constructQIconFromIconRef(icon, overlayIcon, &retIcon, standardIcon); + ReleaseIconRef(icon); + } + if (overlayIcon) + ReleaseIconRef(overlayIcon); + return retIcon; + } + +#endif //Q_WS_X11 || Q_WS_MAC + } + switch (standardIcon) { #ifndef QT_NO_IMAGEFORMAT_PNG diff --git a/src/gui/styles/qcommonstyle_p.h b/src/gui/styles/qcommonstyle_p.h index 27ebc05..f2af5b2 100644 --- a/src/gui/styles/qcommonstyle_p.h +++ b/src/gui/styles/qcommonstyle_p.h @@ -126,6 +126,7 @@ public: //icon detection on X11 #ifdef Q_WS_X11 void lookupIconTheme() const; + int lookupToolButtonStyle() const; QIcon createIcon(const QString &) const; QPixmap findIcon(int size, const QString &) const; QPixmap findIconHelper(int size, const QString &, const QString &, QStringList &visited) const; diff --git a/src/gui/styles/qgtkstyle.cpp b/src/gui/styles/qgtkstyle.cpp index 67586ac..660b4c3 100644 --- a/src/gui/styles/qgtkstyle.cpp +++ b/src/gui/styles/qgtkstyle.cpp @@ -70,6 +70,7 @@ #include <qpixmapcache.h> #undef signals // Collides with GTK stymbols #include "qgtkpainter_p.h" +#include "qstylehelper_p.h" #include <private/qcleanlooksstyle_p.h> @@ -208,17 +209,6 @@ static GdkColor fromQColor(const QColor &color) return retval; } -// Note this is different from uniqueName as used in QGtkPainter -static QString uniqueName(const QString &key, const QStyleOption *option, const QSize &size) -{ - QString tmp; - const QStyleOptionComplex *complexOption = qstyleoption_cast<const QStyleOptionComplex *>(option); - tmp.sprintf("%s-%d-%d-%d-%lld-%dx%d", key.toLatin1().constData(), uint(option->state), - option->direction, complexOption ? uint(complexOption->activeSubControls) : uint(0), - option->palette.cacheKey(), size.width(), size.height()); - return tmp; -} - /*! \class QGtkStyle \brief The QGtkStyle class provides a widget style rendered by GTK+ @@ -609,6 +599,26 @@ int QGtkStyle::styleHint(StyleHint hint, const QStyleOption *option, const QWidg break; + case SH_ToolButtonStyle: + { + if (QGtk::isKDE4Session()) + return QCleanlooksStyle::styleHint(hint, option, widget, returnData); + GtkWidget *gtkToolbar = QGtk::gtkWidget(QLS("GtkToolbar")); + GtkToolbarStyle toolbar_style = GTK_TOOLBAR_ICONS; + g_object_get(gtkToolbar, "toolbar-style", &toolbar_style, NULL); + switch (toolbar_style) { + case GTK_TOOLBAR_TEXT: + return Qt::ToolButtonTextOnly; + case GTK_TOOLBAR_BOTH: + return Qt::ToolButtonTextUnderIcon; + case GTK_TOOLBAR_BOTH_HORIZ: + return Qt::ToolButtonTextBesideIcon; + case GTK_TOOLBAR_ICONS: + default: + return Qt::ToolButtonIconOnly; + } + } + break; case SH_SpinControls_DisableOnBounds: return int(true); @@ -2065,8 +2075,8 @@ void QGtkStyle::drawControl(ControlElement element, } if (vertical) rect = QRect(rect.left(), rect.top(), rect.height(), rect.width()); // flip width and height - const int progressIndicatorPos = static_cast<int>((bar->progress - qint64(bar->minimum)) / - qMax(double(1.0), double(qint64(bar->maximum) - qint64(bar->minimum))) * rect.width()); + const int progressIndicatorPos = (bar->progress - qreal(bar->minimum)) * rect.width() / + qMax(qreal(1.0), qreal(bar->maximum) - bar->minimum); if (progressIndicatorPos >= 0 && progressIndicatorPos <= rect.width()) leftRect = QRect(rect.left(), rect.top(), progressIndicatorPos, rect.height()); if (vertical) diff --git a/src/gui/styles/qmacstyle_mac.mm b/src/gui/styles/qmacstyle_mac.mm index c08009b..2f93034 100644 --- a/src/gui/styles/qmacstyle_mac.mm +++ b/src/gui/styles/qmacstyle_mac.mm @@ -558,7 +558,6 @@ QT_END_INCLUDE_NAMESPACE External functions *****************************************************************************/ extern CGContextRef qt_mac_cg_context(const QPaintDevice *); //qpaintdevice_mac.cpp -extern QPixmap qt_mac_convert_iconref(const IconRef, int, int); //qpixmap_mac.cpp extern QRegion qt_mac_convert_mac_region(HIShapeRef); //qregion_mac.cpp void qt_mac_dispose_rgn(RgnHandle r); //qregion_mac.cpp extern QPaintDevice *qt_mac_safe_pdev; //qapplication_mac.cpp @@ -1871,24 +1870,23 @@ QPixmap QMacStylePrivate::generateBackgroundPattern() const Fills the given \a rect with the pattern stored in \a brush. As an optimization, HIThemeSetFill us used directly if we are filling with the standard background. */ -void qt_mac_fill_background(QPainter *painter, const QRegion &rgn, const QPoint &offset, const QBrush &brush) +void qt_mac_fill_background(QPainter *painter, const QRegion &rgn, const QBrush &brush) { QPoint dummy; const QPaintDevice *target = painter->device(); const QPaintDevice *redirected = QPainter::redirected(target, &dummy); const bool usePainter = redirected && redirected != target; - const QRegion translated = rgn.translated(offset); if (!usePainter && qt_mac_backgroundPattern && qt_mac_backgroundPattern->cacheKey() == brush.texture().cacheKey()) { - painter->setClipRegion(translated); + painter->setClipRegion(rgn); CGContextRef cg = qt_mac_cg_context(target); CGContextSaveGState(cg); HIThemeSetFill(kThemeBrushDialogBackgroundActive, 0, cg, kHIThemeOrientationInverted); - const QVector<QRect> &rects = translated.rects(); + const QVector<QRect> &rects = rgn.rects(); for (int i = 0; i < rects.size(); ++i) { const QRect rect(rects.at(i)); // Anchor the pattern to the top so it stays put when the window is resized. @@ -1899,8 +1897,8 @@ void qt_mac_fill_background(QPainter *painter, const QRegion &rgn, const QPoint CGContextRestoreGState(cg); } else { - const QRect rect(translated.boundingRect()); - painter->setClipRegion(translated); + const QRect rect(rgn.boundingRect()); + painter->setClipRegion(rgn); painter->drawTiledPixmap(rect, brush.texture(), rect.topLeft()); } } @@ -2304,9 +2302,6 @@ int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QW case PM_ToolBarItemSpacing: ret = 4; break; - case PM_MessageBoxIconSize: - ret = 64; - break; case PM_SplitterWidth: ret = qMax(7, QApplication::globalStrut().width()); break; @@ -3362,6 +3357,9 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter } proxy()->drawItemPixmap(p, pr, Qt::AlignCenter, pixmap); break; } + default: + Q_ASSERT(false); + break; } if (needText) { @@ -5856,76 +5854,12 @@ bool QMacStyle::event(QEvent *e) return false; } -void qt_mac_constructQIconFromIconRef(const IconRef icon, const IconRef overlayIcon, QIcon *retIcon, QStyle::StandardPixmap standardIcon = QStyle::SP_CustomBase) -{ - int size = 16; - while (size <= 128) { - - const QString cacheKey = QLatin1String("qt_mac_constructQIconFromIconRef") + QString::number(standardIcon) + QString::number(size); - QPixmap mainIcon; - if (standardIcon >= QStyle::SP_CustomBase) { - mainIcon = qt_mac_convert_iconref(icon, size, size); - } else if (QPixmapCache::find(cacheKey, mainIcon) == false) { - mainIcon = qt_mac_convert_iconref(icon, size, size); - QPixmapCache::insert(cacheKey, mainIcon); - } - - if (overlayIcon) { - int littleSize = size / 2; - QPixmap overlayPix = qt_mac_convert_iconref(overlayIcon, littleSize, littleSize); - QPainter painter(&mainIcon); - painter.drawPixmap(size - littleSize, size - littleSize, overlayPix); - } - - retIcon->addPixmap(mainIcon); - size += size; // 16 -> 32 -> 64 -> 128 - } -} - QIcon QMacStyle::standardIconImplementation(StandardPixmap standardIcon, const QStyleOption *opt, const QWidget *widget) const { - OSType iconType = 0; switch (standardIcon) { - case QStyle::SP_MessageBoxQuestion: - case QStyle::SP_MessageBoxInformation: - case QStyle::SP_MessageBoxWarning: - case QStyle::SP_MessageBoxCritical: - iconType = kGenericApplicationIcon; - break; - case SP_DesktopIcon: - iconType = kDesktopIcon; - break; - case SP_TrashIcon: - iconType = kTrashIcon; - break; - case SP_ComputerIcon: - iconType = kComputerIcon; - break; - case SP_DriveFDIcon: - iconType = kGenericFloppyIcon; - break; - case SP_DriveHDIcon: - iconType = kGenericHardDiskIcon; - break; - case SP_DriveCDIcon: - case SP_DriveDVDIcon: - iconType = kGenericCDROMIcon; - break; - case SP_DriveNetIcon: - iconType = kGenericNetworkIcon; - break; - case SP_DirOpenIcon: - iconType = kOpenFolderIcon; - break; - case SP_DirClosedIcon: - case SP_DirLinkIcon: - iconType = kGenericFolderIcon; - break; - case SP_FileLinkIcon: - case SP_FileIcon: - iconType = kGenericDocumentIcon; - break; + default: + return QWindowsStyle::standardIconImplementation(standardIcon, opt, widget); case SP_ToolBarHorizontalExtensionButton: case SP_ToolBarVerticalExtensionButton: { QPixmap pixmap(qt_mac_toolbar_ext); @@ -5939,58 +5873,8 @@ QIcon QMacStyle::standardIconImplementation(StandardPixmap standardIcon, const Q return pix2; } return pixmap; - } - break; - case SP_DirIcon: { - // A rather special case - QIcon closeIcon = QStyle::standardIcon(SP_DirClosedIcon, opt, widget); - QIcon openIcon = QStyle::standardIcon(SP_DirOpenIcon, opt, widget); - closeIcon.addPixmap(openIcon.pixmap(16, 16), QIcon::Normal, QIcon::On); - closeIcon.addPixmap(openIcon.pixmap(32, 32), QIcon::Normal, QIcon::On); - closeIcon.addPixmap(openIcon.pixmap(64, 64), QIcon::Normal, QIcon::On); - closeIcon.addPixmap(openIcon.pixmap(128, 128), QIcon::Normal, QIcon::On); - return closeIcon; - } - case SP_TitleBarNormalButton: - case SP_TitleBarCloseButton: { - QIcon titleBarIcon; - if (standardIcon == SP_TitleBarCloseButton) { - titleBarIcon.addFile(QLatin1String(":/trolltech/styles/macstyle/images/closedock-16.png")); - titleBarIcon.addFile(QLatin1String(":/trolltech/styles/macstyle/images/closedock-down-16.png"), QSize(16, 16), QIcon::Normal, QIcon::On); - } else { - titleBarIcon.addFile(QLatin1String(":/trolltech/styles/macstyle/images/dockdock-16.png")); - titleBarIcon.addFile(QLatin1String(":/trolltech/styles/macstyle/images/dockdock-down-16.png"), QSize(16, 16), QIcon::Normal, QIcon::On); - } - return titleBarIcon; - } - default: - break; } - if (iconType != 0) { - QIcon retIcon; - IconRef icon; - IconRef overlayIcon = 0; - if (iconType != kGenericApplicationIcon) { - GetIconRef(kOnSystemDisk, kSystemIconsCreator, iconType, &icon); - } else { - FSRef fsRef; - ProcessSerialNumber psn = { 0, kCurrentProcess }; - GetProcessBundleLocation(&psn, &fsRef); - GetIconRefFromFileInfo(&fsRef, 0, 0, 0, 0, kIconServicesNormalUsageFlag, &icon, 0); - if (standardIcon == SP_MessageBoxCritical) { - overlayIcon = icon; - GetIconRef(kOnSystemDisk, kSystemIconsCreator, kAlertCautionIcon, &icon); - } - } - if (icon) { - qt_mac_constructQIconFromIconRef(icon, overlayIcon, &retIcon, standardIcon); - ReleaseIconRef(icon); - } - if (overlayIcon) - ReleaseIconRef(overlayIcon); - return retIcon; } - return QWindowsStyle::standardIconImplementation(standardIcon, opt, widget); } int QMacStyle::layoutSpacingImplementation(QSizePolicy::ControlType control1, diff --git a/src/gui/styles/qplastiquestyle.cpp b/src/gui/styles/qplastiquestyle.cpp index 12aa679..80c9881 100644 --- a/src/gui/styles/qplastiquestyle.cpp +++ b/src/gui/styles/qplastiquestyle.cpp @@ -730,16 +730,6 @@ static QColor mergedColors(const QColor &colorA, const QColor &colorB, int facto return tmp; } -static QString uniqueName(const QString &key, const QStyleOption *option, const QSize &size) -{ - QString tmp; - const QStyleOptionComplex *complexOption = qstyleoption_cast<const QStyleOptionComplex *>(option); - tmp.sprintf("%s-%d-%d-%d-%lld-%dx%d", key.toLatin1().constData(), uint(option->state), - option->direction, complexOption ? uint(complexOption->activeSubControls) : uint(0), - option->palette.cacheKey(), size.width(), size.height()); - return tmp; -} - static void qt_plastique_draw_gradient(QPainter *painter, const QRect &rect, const QColor &gradientStart, const QColor &gradientStop) { @@ -1512,7 +1502,7 @@ void QPlastiqueStyle::drawPrimitive(PrimitiveElement element, const QStyleOption rect.adjust(2, 0, -2, 0); } #endif - QString pixmapName = uniqueName(QLatin1String("toolbarhandle"), option, rect.size()); + QString pixmapName = QStyleHelper::uniqueName(QLatin1String("toolbarhandle"), option, rect.size()); if (!QPixmapCache::find(pixmapName, cache)) { cache = QPixmap(rect.size()); cache.fill(Qt::transparent); @@ -2581,8 +2571,7 @@ void QPlastiqueStyle::drawControl(ControlElement element, const QStyleOption *op painter->setTransform(m, true); } - double vc6_workaround = ((bar->progress - qint64(bar->minimum)) / qMax(double(1.0), double(qint64(bar->maximum) - qint64(bar->minimum))) * rect.width()); - int progressIndicatorPos = int(vc6_workaround); + int progressIndicatorPos = (bar->progress - qreal(bar->minimum)) / qMax(qreal(1.0), qreal(bar->maximum) - bar->minimum) * rect.width(); bool flip = (!vertical && (((bar->direction == Qt::RightToLeft) && !inverted) || ((bar->direction == Qt::LeftToRight) && inverted))) || (vertical && ((!inverted && !bottomToTop) || (inverted && bottomToTop))); @@ -2777,7 +2766,7 @@ void QPlastiqueStyle::drawControl(ControlElement element, const QStyleOption *op // contents painter->setPen(QPen()); - QString progressBarName = uniqueName(QLatin1String("progressBarContents"), + QString progressBarName = QStyleHelper::uniqueName(QLatin1String("progressBarContents"), option, rect.size()); QPixmap cache; if (!QPixmapCache::find(progressBarName, cache) && rect.height() > 7) { @@ -2837,7 +2826,7 @@ void QPlastiqueStyle::drawControl(ControlElement element, const QStyleOption *op // Draws the header in tables. if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) { QPixmap cache; - QString pixmapName = uniqueName(QLatin1String("headersection"), option, option->rect.size()); + QString pixmapName = QStyleHelper::uniqueName(QLatin1String("headersection"), option, option->rect.size()); pixmapName += QString::number(- int(header->position)); pixmapName += QString::number(- int(header->orientation)); @@ -3084,7 +3073,7 @@ void QPlastiqueStyle::drawControl(ControlElement element, const QStyleOption *op // Draws a menu bar item; File, Edit, Help etc.. if ((option->state & State_Selected)) { QPixmap cache; - QString pixmapName = uniqueName(QLatin1String("menubaritem"), option, option->rect.size()); + QString pixmapName = QStyleHelper::uniqueName(QLatin1String("menubaritem"), option, option->rect.size()); if (!QPixmapCache::find(pixmapName, cache)) { cache = QPixmap(option->rect.size()); cache.fill(Qt::white); @@ -3447,7 +3436,7 @@ void QPlastiqueStyle::drawControl(ControlElement element, const QStyleOption *op bool reverse = scrollBar->direction == Qt::RightToLeft; bool sunken = scrollBar->state & State_Sunken; - QString addLinePixmapName = uniqueName(QLatin1String("scrollbar_addline"), option, option->rect.size()); + QString addLinePixmapName = QStyleHelper::uniqueName(QLatin1String("scrollbar_addline"), option, option->rect.size()); QPixmap cache; if (!QPixmapCache::find(addLinePixmapName, cache)) { cache = QPixmap(option->rect.size()); @@ -3519,7 +3508,7 @@ void QPlastiqueStyle::drawControl(ControlElement element, const QStyleOption *op bool sunken = scrollBar->state & State_Sunken; bool horizontal = scrollBar->orientation == Qt::Horizontal; - QString groovePixmapName = uniqueName(QLatin1String("scrollbar_groove"), option, option->rect.size()); + QString groovePixmapName = QStyleHelper::uniqueName(QLatin1String("scrollbar_groove"), option, option->rect.size()); if (sunken) groovePixmapName += QLatin1String("-sunken"); if (element == CE_ScrollBarAddPage) @@ -3578,7 +3567,7 @@ void QPlastiqueStyle::drawControl(ControlElement element, const QStyleOption *op button2.setRect(scrollBarSubLine.left(), scrollBarSubLine.bottom() - (scrollBarExtent - 1), scrollBarSubLine.width(), scrollBarExtent); } - QString subLinePixmapName = uniqueName(QLatin1String("scrollbar_subline"), option, button1.size()); + QString subLinePixmapName = QStyleHelper::uniqueName(QLatin1String("scrollbar_subline"), option, button1.size()); QPixmap cache; if (!QPixmapCache::find(subLinePixmapName, cache)) { cache = QPixmap(button1.size()); @@ -3653,7 +3642,7 @@ void QPlastiqueStyle::drawControl(ControlElement element, const QStyleOption *op // The slider if (option->rect.isValid()) { - QString sliderPixmapName = uniqueName(QLatin1String("scrollbar_slider"), option, option->rect.size()); + QString sliderPixmapName = QStyleHelper::uniqueName(QLatin1String("scrollbar_slider"), option, option->rect.size()); if (horizontal) sliderPixmapName += QLatin1String("-horizontal"); @@ -3873,7 +3862,7 @@ void QPlastiqueStyle::drawComplexControl(ComplexControl control, const QStyleOpt } if ((option->subControls & SC_SliderHandle) && handle.isValid()) { - QString handlePixmapName = uniqueName(QLatin1String("slider_handle"), option, handle.size()); + QString handlePixmapName = QStyleHelper::uniqueName(QLatin1String("slider_handle"), option, handle.size()); if (ticksAbove && !ticksBelow) handlePixmapName += QLatin1String("-flipped"); if ((option->activeSubControls & SC_SliderHandle) && (option->state & State_Sunken)) diff --git a/src/gui/styles/qstyle.cpp b/src/gui/styles/qstyle.cpp index 797886c..a5ab80e 100644 --- a/src/gui/styles/qstyle.cpp +++ b/src/gui/styles/qstyle.cpp @@ -526,8 +526,9 @@ void QStyle::drawItemText(QPainter *painter, const QRect &rect, int alignment, c } if (!enabled) { if (styleHint(SH_DitherDisabledText)) { - painter->drawText(rect, alignment, text); - painter->fillRect(painter->boundingRect(rect, alignment, text), QBrush(painter->background().color(), Qt::Dense5Pattern)); + QRect br; + painter->drawText(rect, alignment, text, &br); + painter->fillRect(br, QBrush(painter->background().color(), Qt::Dense5Pattern)); return; } else if (styleHint(SH_EtchDisabledText)) { QPen pen = painter->pen(); @@ -1865,6 +1866,8 @@ void QStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment, \value SH_DockWidget_ButtonsHaveFrame Determines if dockwidget buttons should have frames. Default is true. + \value SH_ToolButtonStyle Determines the default system style for tool buttons that uses Qt::ToolButtonFollowStyle. + \omitvalue SH_UnderlineAccelerator \sa styleHint() diff --git a/src/gui/styles/qstyle.h b/src/gui/styles/qstyle.h index d79c39c..f22bf55 100644 --- a/src/gui/styles/qstyle.h +++ b/src/gui/styles/qstyle.h @@ -730,7 +730,7 @@ public: SH_ItemView_DrawDelegateFrame, SH_TabBar_CloseButtonPosition, SH_DockWidget_ButtonsHaveFrame, - + SH_ToolButtonStyle, // Add new style hint values here #ifdef QT3_SUPPORT diff --git a/src/gui/styles/qstyle_p.h b/src/gui/styles/qstyle_p.h index 854874f..2d6ef22 100644 --- a/src/gui/styles/qstyle_p.h +++ b/src/gui/styles/qstyle_p.h @@ -43,6 +43,7 @@ #define QSTYLE_P_H #include "private/qobject_p.h" +#include "private/qstylehelper_p.h" #include <QtGui/qstyle.h> QT_BEGIN_NAMESPACE @@ -78,7 +79,7 @@ public: QPixmap internalPixmapCache; \ QImage imageCache; \ QPainter *p = painter; \ - QString unique = uniqueName((a), option, option->rect.size()); \ + QString unique = QStyleHelper::uniqueName((a), option, option->rect.size()); \ int txType = painter->deviceTransform().type() | painter->worldTransform().type(); \ bool doPixmapCache = txType <= QTransform::TxTranslate; \ if (doPixmapCache && QPixmapCache::find(unique, internalPixmapCache)) { \ diff --git a/src/gui/styles/qstylehelper.cpp b/src/gui/styles/qstylehelper.cpp index f9010e8..4877ec4 100644 --- a/src/gui/styles/qstylehelper.cpp +++ b/src/gui/styles/qstylehelper.cpp @@ -60,11 +60,10 @@ namespace QStyleHelper { QString uniqueName(const QString &key, const QStyleOption *option, const QSize &size) { - QString tmp; const QStyleOptionComplex *complexOption = qstyleoption_cast<const QStyleOptionComplex *>(option); - tmp.sprintf("%s-%d-%d-%lld-%dx%d-%d", key.toLatin1().constData(), uint(option->state), - complexOption ? uint(complexOption->activeSubControls) : uint(0), - option->palette.cacheKey(), size.width(), size.height(), option->direction); + QString tmp = QString::fromLatin1("%1-%2-%3-%4-%5-%6x%7").arg(key).arg(uint(option->state)).arg(option->direction) + .arg(complexOption ? uint(complexOption->activeSubControls) : uint(0)) + .arg(option->palette.cacheKey()).arg(size.width()).arg(size.height()); #ifndef QT_NO_SPINBOX if (const QStyleOptionSpinBox *spinBox = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) { tmp.append(QLatin1Char('-')); diff --git a/src/gui/styles/qstylesheetstyle.cpp b/src/gui/styles/qstylesheetstyle.cpp index 01d8aad..2efa4a7 100644 --- a/src/gui/styles/qstylesheetstyle.cpp +++ b/src/gui/styles/qstylesheetstyle.cpp @@ -4171,7 +4171,7 @@ void QStyleSheetStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *op if (!rule.hasDrawable()) { QWidget *container = containerWidget(w); if (autoFillDisabledWidgets->contains(container) - && (container == w || !renderRule(container, opt).hasDrawable())) { + && (container == w || !renderRule(container, opt).hasBackground())) { //we do not have a background, but we disabled the autofillbackground anyway. so fill the background now. // (this may happen if we have rules like :focus) p->fillRect(opt->rect, opt->palette.brush(w->backgroundRole())); diff --git a/src/gui/styles/qwindowsstyle.cpp b/src/gui/styles/qwindowsstyle.cpp index 4f25e68..4c66bbb 100644 --- a/src/gui/styles/qwindowsstyle.cpp +++ b/src/gui/styles/qwindowsstyle.cpp @@ -1061,6 +1061,8 @@ QPixmap QWindowsStyle::standardPixmap(StandardPixmap standardPixmap, const QStyl } } break; + default: + break; } if (!desktopIcon.isNull()) { return desktopIcon; @@ -1375,11 +1377,8 @@ void QWindowsStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QRect r = opt->rect; int size = qMin(r.height(), r.width()); QPixmap pixmap; - QString pixmapName; - pixmapName.sprintf("%s-%s-%d-%d-%d-%lld", - "$qt_ia", metaObject()->className(), - uint(opt->state), pe, - size, opt->palette.cacheKey()); + QString pixmapName = QStyleHelper::uniqueName(QLatin1String("$qt_ia-") + QLatin1String(metaObject()->className()), opt, QSize(size, size)) + + QLatin1Char('-') + QString::number(pe); if (!QPixmapCache::find(pixmapName, pixmap)) { int border = size/5; int sqsize = 2*(size/2); diff --git a/src/gui/styles/qwindowsvistastyle.cpp b/src/gui/styles/qwindowsvistastyle.cpp index 3e65eef..f3d0f04 100644 --- a/src/gui/styles/qwindowsvistastyle.cpp +++ b/src/gui/styles/qwindowsvistastyle.cpp @@ -735,7 +735,7 @@ void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOpt if (const QListView *listview = qobject_cast<const QListView *>(widget)) { if (listview->viewMode() == QListView::IconMode) newStyle = true; - } else if (const QTreeView* treeview = qobject_cast<const QTreeView *>(widget)) { + } else if (qobject_cast<const QTreeView *>(widget)) { newStyle = true; } if (newStyle && view && (vopt = qstyleoption_cast<const QStyleOptionViewItemV4 *>(option))) { @@ -1093,7 +1093,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption XPThemeData theme(widget, painter, QLatin1String("PROGRESS"), vertical ? PP_FILLVERT : PP_FILL); theme.rect = option->rect; - bool reverse = bar->direction == Qt::LeftToRight && inverted || bar->direction == Qt::RightToLeft && !inverted; + bool reverse = bar->direction == (Qt::LeftToRight && inverted) || (bar->direction == Qt::RightToLeft && !inverted); QTime current = QTime::currentTime(); if (isIndeterminate) { @@ -1271,7 +1271,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption int yoff = y-2 + h / 2; QPoint p1 = QPoint(x + checkcol, yoff); QPoint p2 = QPoint(x + w + 6 , yoff); - int stateId = stateId = MBI_HOT; + stateId = MBI_HOT; QRect subRect(p1.x(), p1.y(), p2.x() - p1.x(), 6); subRect = QStyle::visualRect(option->direction, option->rect, subRect ); XPThemeData theme2(widget, painter, QLatin1String("MENU"), MENU_POPUPSEPARATOR, stateId, subRect); @@ -1283,7 +1283,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption menuitem->rect.y(), checkcol - 6, menuitem->rect.height())); if (act) { - int stateId = stateId = MBI_HOT; + stateId = MBI_HOT; XPThemeData theme2(widget, painter, QLatin1String("MENU"), MENU_POPUPITEM, stateId, option->rect); d->drawBackground(theme2); } @@ -1403,7 +1403,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption break; case CE_MenuBarEmptyArea: { - int stateId = MBI_NORMAL; + stateId = MBI_NORMAL; if (!(state & State_Enabled)) stateId = MBI_DISABLED; XPThemeData theme(widget, painter, QLatin1String("MENU"), MENU_BARBACKGROUND, stateId, option->rect); @@ -1500,7 +1500,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption if (const QListView *listview = qobject_cast<const QListView *>(widget)) { if (listview->viewMode() == QListView::IconMode) newStyle = true; - } else if (const QTreeView* treeview = qobject_cast<const QTreeView *>(widget)) { + } else if (qobject_cast<const QTreeView *>(widget)) { newStyle = true; } if (newStyle && view && (vopt = qstyleoption_cast<const QStyleOptionViewItemV4 *>(option))) { @@ -2014,7 +2014,7 @@ QRect QWindowsVistaStyle::subElementRect(SubElement element, const QStyleOption MARGINS borderSize; HTHEME theme = pOpenThemeData(widget ? QWindowsVistaStylePrivate::winId(widget) : 0, L"Button"); if (theme) { - int stateId; + int stateId = PBS_NORMAL; if (!(option->state & State_Enabled)) stateId = PBS_DISABLED; else if (option->state & State_Sunken) @@ -2023,8 +2023,6 @@ QRect QWindowsVistaStyle::subElementRect(SubElement element, const QStyleOption stateId = PBS_HOT; else if (btn->features & QStyleOptionButton::DefaultButton) stateId = PBS_DEFAULTED; - else - stateId = PBS_NORMAL; int border = proxy()->pixelMetric(PM_DefaultFrameWidth, btn, widget); rect = option->rect.adjusted(border, border, -border, -border); @@ -2097,7 +2095,7 @@ QRect QWindowsVistaStyle::subElementRect(SubElement element, const QStyleOption rect = QCommonStyle::subElementRect(SE_ProgressBarGroove, option, widget); break; case SE_ItemViewItemDecoration: - if (const QStyleOptionViewItemV4 *vopt = qstyleoption_cast<const QStyleOptionViewItemV4 *>(option)) + if (qstyleoption_cast<const QStyleOptionViewItemV4 *>(option)) rect.adjust(-2, 0, 2, 0); break; case SE_ItemViewItemFocusRect: @@ -2303,6 +2301,8 @@ QRect QWindowsVistaStyle::subControlRect(ComplexControl control, const QStyleOpt rect = visualRect(option->direction, option->rect, rect); } break; + default: + break; } } break; diff --git a/src/gui/styles/qwindowsxpstyle.cpp b/src/gui/styles/qwindowsxpstyle.cpp index 9c4afee..9560c4b 100644 --- a/src/gui/styles/qwindowsxpstyle.cpp +++ b/src/gui/styles/qwindowsxpstyle.cpp @@ -1202,7 +1202,8 @@ QRect QWindowsXPStyle::subElementRect(SubElement sr, const QStyleOption *option, if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option)) { MARGINS borderSize; if (widget) { - HTHEME theme = pOpenThemeData(QWindowsXPStylePrivate::winId(widget), L"Button"); + XPThemeData buttontheme(widget, 0, QLatin1String("Button")); + HTHEME theme = buttontheme.handle(); if (theme) { int stateId; if (!(option->state & State_Enabled)) @@ -1918,8 +1919,8 @@ void QWindowsXPStyle::drawControl(ControlElement element, const QStyleOption *op { name = QLatin1String("BUTTON"); partId = BP_PUSHBUTTON; - bool justFlat = (btn->features & QStyleOptionButton::Flat) && !(flags & (State_On|State_Sunken)) - || (btn->features & QStyleOptionButton::CommandLinkButton + bool justFlat = ((btn->features & QStyleOptionButton::Flat) && !(flags & (State_On|State_Sunken))) + || ((btn->features & QStyleOptionButton::CommandLinkButton) && !(flags & State_MouseOver) && !(btn->features & QStyleOptionButton::DefaultButton)); if (!(flags & State_Enabled) && !(btn->features & QStyleOptionButton::Flat)) @@ -3244,7 +3245,7 @@ int QWindowsXPStyle::pixelMetric(PixelMetric pm, const QStyleOption *option, con if (theme.isValid()) { SIZE size; pGetThemePartSize(theme.handle(), 0, theme.partId, theme.stateId, 0, TS_TRUE, &size); - res = (pm == PM_IndicatorWidth ? size.cx : res = size.cy); + res = (pm == PM_IndicatorWidth) ? size.cx : size.cy; } } break; @@ -3256,7 +3257,7 @@ int QWindowsXPStyle::pixelMetric(PixelMetric pm, const QStyleOption *option, con if (theme.isValid()) { SIZE size; pGetThemePartSize(theme.handle(), 0, theme.partId, theme.stateId, 0, TS_TRUE, &size); - res = (pm == PM_ExclusiveIndicatorWidth ? size.cx : res = size.cy); + res = (pm == PM_ExclusiveIndicatorWidth) ? size.cx : size.cy; } } break; @@ -3536,6 +3537,8 @@ QRect QWindowsXPStyle::subControlRect(ComplexControl cc, const QStyleOptionCompl rect = QRect(frameWidth + hPad, controlTop + vPad, iconSize.width(), iconSize.height()); } break; + default: + break; } } break; @@ -3562,6 +3565,9 @@ QRect QWindowsXPStyle::subControlRect(ComplexControl cc, const QStyleOptionCompl case SC_ComboBoxListBoxPopup: rect = cmb->rect; break; + + default: + break; } } break; @@ -3626,7 +3632,8 @@ QSize QWindowsXPStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt case CT_LineEdit: case CT_ComboBox: { - HTHEME theme = pOpenThemeData(QWindowsXPStylePrivate::winId(widget), L"Button"); + XPThemeData buttontheme(widget, 0, QLatin1String("Button")); + HTHEME theme = buttontheme.handle(); MARGINS borderSize; if (theme) { int result = pGetThemeMargins(theme, @@ -3802,6 +3809,8 @@ QPixmap QWindowsXPStyle::standardPixmap(StandardPixmap standardPixmap, const QSt } } break; + default: + break; } return QWindowsStyle::standardPixmap(standardPixmap, option, widget); } @@ -3923,6 +3932,8 @@ QIcon QWindowsXPStyle::standardIconImplementation(StandardPixmap standardIcon, } break; + default: + break; } return QWindowsStyle::standardIconImplementation(standardIcon, option, widget); diff --git a/src/gui/text/qabstracttextdocumentlayout.cpp b/src/gui/text/qabstracttextdocumentlayout.cpp index 8d7540c..04df2aa 100644 --- a/src/gui/text/qabstracttextdocumentlayout.cpp +++ b/src/gui/text/qabstracttextdocumentlayout.cpp @@ -79,6 +79,7 @@ QT_BEGIN_NAMESPACE \class QTextObjectInterface \brief The QTextObjectInterface class allows drawing of custom text objects in \l{QTextDocument}s. + \since 4.5 A text object describes the structure of one or more elements in a text document; for instance, images imported from HTML are diff --git a/src/gui/text/qfontdatabase_win.cpp b/src/gui/text/qfontdatabase_win.cpp index 2e8e5e4..974b955 100644 --- a/src/gui/text/qfontdatabase_win.cpp +++ b/src/gui/text/qfontdatabase_win.cpp @@ -1026,6 +1026,8 @@ static void getFamiliesAndSignatures(const QByteArray &fontData, QFontDatabasePr signature.fsCsb[0] = qFromBigEndian<quint32>(table + 78); signature.fsCsb[1] = qFromBigEndian<quint32>(table + 82); + } else { + memset(&signature, 0, sizeof(signature)); } appFont->signatures << signature; } diff --git a/src/gui/text/qfontengine_win.cpp b/src/gui/text/qfontengine_win.cpp index f4adc9a..c6717e3 100644 --- a/src/gui/text/qfontengine_win.cpp +++ b/src/gui/text/qfontengine_win.cpp @@ -125,8 +125,6 @@ HDC shared_dc() } #endif -static HFONT stock_sysfont = 0; - typedef BOOL (WINAPI *PtrGetCharWidthI)(HDC, UINT, UINT, LPWORD, LPINT); static PtrGetCharWidthI ptrGetCharWidthI = 0; static bool resolvedGetCharWidthI = false; @@ -542,13 +540,6 @@ glyph_metrics_t QFontEngineWin::boundingBox(const QGlyphLayout &glyphs) } - - -#ifndef Q_WS_WINCE -typedef HRESULT (WINAPI *pGetCharABCWidthsFloat)(HDC, UINT, UINT, LPABCFLOAT); -static pGetCharABCWidthsFloat qt_GetCharABCWidthsFloat = 0; -#endif - glyph_metrics_t QFontEngineWin::boundingBox(glyph_t glyph, const QTransform &t) { #ifndef Q_WS_WINCE @@ -1143,8 +1134,7 @@ QNativeImage *QFontEngineWin::drawGDIGlyph(HFONT font, glyph_t glyph, int margin memset(&mat, 0, sizeof(mat)); mat.eM11.value = mat.eM22.value = 1; - int error = GetGlyphOutline(hdc, glyph, ggo_options, &tgm, 0, 0, &mat); - if (error == GDI_ERROR) { + if (GetGlyphOutline(hdc, glyph, ggo_options, &tgm, 0, 0, &mat) == GDI_ERROR) { qWarning("QWinFontEngine: unable to query transformed glyph metrics..."); return 0; } diff --git a/src/gui/text/qsyntaxhighlighter.cpp b/src/gui/text/qsyntaxhighlighter.cpp index f69562d..56c7ca1 100644 --- a/src/gui/text/qsyntaxhighlighter.cpp +++ b/src/gui/text/qsyntaxhighlighter.cpp @@ -367,7 +367,7 @@ QTextDocument *QSyntaxHighlighter::document() const /*! \since 4.2 - Redoes the highlighting of the whole document. + Reapplies the highlighting to the whole document. \sa rehighlightBlock() */ @@ -384,7 +384,7 @@ void QSyntaxHighlighter::rehighlight() /*! \since 4.6 - Redoes the highlighting of the given QTextBlock \a block. + Reapplies the highlighting to the given QTextBlock \a block. \sa rehighlight() */ diff --git a/src/gui/text/qtextcursor.cpp b/src/gui/text/qtextcursor.cpp index 0e3cb56..19d4cc4 100644 --- a/src/gui/text/qtextcursor.cpp +++ b/src/gui/text/qtextcursor.cpp @@ -1856,6 +1856,8 @@ bool QTextCursor::atStart() const } /*! + \since 4.6 + Returns true if the cursor is at the end of the document; otherwise returns false. diff --git a/src/gui/text/qzip.cpp b/src/gui/text/qzip.cpp index 5fbc36d..ccb4e6b 100644 --- a/src/gui/text/qzip.cpp +++ b/src/gui/text/qzip.cpp @@ -56,13 +56,23 @@ #if defined(Q_OS_WIN) #undef S_IFREG #define S_IFREG 0100000 -# define S_ISDIR(x) ((x) & 0040000) > 0 -# define S_ISREG(x) ((x) & 0170000) == S_IFREG +# ifndef S_ISDIR +# define S_ISDIR(x) ((x) & 0040000) > 0 +# endif +# ifndef S_ISREG +# define S_ISREG(x) ((x) & 0170000) == S_IFREG +# endif # define S_IFLNK 020000 # define S_ISLNK(x) ((x) & S_IFLNK) > 0 -# define S_IRUSR 0400 -# define S_IWUSR 0200 -# define S_IXUSR 0100 +# ifndef S_IRUSR +# define S_IRUSR 0400 +# endif +# ifndef S_IWUSR +# define S_IWUSR 0200 +# endif +# ifndef S_IXUSR +# define S_IXUSR 0100 +# endif # define S_IRGRP 0040 # define S_IWGRP 0020 # define S_IXGRP 0010 diff --git a/src/gui/util/qcompleter.cpp b/src/gui/util/qcompleter.cpp index d68e309..bf1fa6a 100644 --- a/src/gui/util/qcompleter.cpp +++ b/src/gui/util/qcompleter.cpp @@ -134,7 +134,7 @@ To provide completions, QCompleter needs to know the path from an index. This is provided by pathFromIndex(). The default implementation of - pathFromIndex(), returns the data for the \l{Qt::EditRole}{edit role} + pathFromIndex(), returns the data for the \l{Qt::EditRole}{edit role} for list models and the absolute file path if the mode is a QDirModel. \sa QAbstractItemModel, QLineEdit, QComboBox, {Completer Example} @@ -772,7 +772,7 @@ QMatchData QUnsortedModelEngine::filter(const QString& part, const QModelIndex& /////////////////////////////////////////////////////////////////////////////// QCompleterPrivate::QCompleterPrivate() : widget(0), proxy(0), popup(0), cs(Qt::CaseSensitive), role(Qt::EditRole), column(0), - sorting(QCompleter::UnsortedModel), wrap(true), eatFocusOut(true) + sorting(QCompleter::UnsortedModel), wrap(true), maxVisibleItems(7), eatFocusOut(true) { } @@ -861,7 +861,7 @@ void QCompleterPrivate::showPopup(const QRect& rect) Qt::LayoutDirection dir = widget->layoutDirection(); QPoint pos; int rw, rh, w; - int h = (popup->sizeHintForRow(0) * qMin(7, popup->model()->rowCount()) + 3) + 3; + int h = (popup->sizeHintForRow(0) * qMin(maxVisibleItems, popup->model()->rowCount()) + 3) + 3; QScrollBar *hsb = popup->horizontalScrollBar(); if (hsb && hsb->isVisible()) h += popup->horizontalScrollBar()->sizeHint().height(); @@ -1510,6 +1510,30 @@ bool QCompleter::wrapAround() const } /*! + \property QCompleter::maxVisibleItems + \brief the maximum allowed size on screen of the completer, measured in items + \since 4.6 + + By default, this property has a value of 7. +*/ +int QCompleter::maxVisibleItems() const +{ + Q_D(const QCompleter); + return d->maxVisibleItems; +} + +void QCompleter::setMaxVisibleItems(int maxItems) +{ + Q_D(QCompleter); + if (maxItems < 0) { + qWarning("QCompleter::setMaxVisibleItems: " + "Invalid max visible items (%d) must be >= 0", maxItems); + return; + } + d->maxVisibleItems = maxItems; +} + +/*! \property QCompleter::caseSensitivity \brief the case sensitivity of the matching diff --git a/src/gui/util/qcompleter.h b/src/gui/util/qcompleter.h index c1169ef..a419154 100644 --- a/src/gui/util/qcompleter.h +++ b/src/gui/util/qcompleter.h @@ -69,6 +69,7 @@ class Q_GUI_EXPORT QCompleter : public QObject Q_PROPERTY(CompletionMode completionMode READ completionMode WRITE setCompletionMode) Q_PROPERTY(int completionColumn READ completionColumn WRITE setCompletionColumn) Q_PROPERTY(int completionRole READ completionRole WRITE setCompletionRole) + Q_PROPERTY(int maxVisibleItems READ maxVisibleItems WRITE setMaxVisibleItems) Q_PROPERTY(Qt::CaseSensitivity caseSensitivity READ caseSensitivity WRITE setCaseSensitivity) Q_PROPERTY(bool wrapAround READ wrapAround WRITE setWrapAround) @@ -118,6 +119,9 @@ public: bool wrapAround() const; + int maxVisibleItems() const; + void setMaxVisibleItems(int maxItems); + int completionCount() const; bool setCurrentRow(int row); int currentRow() const; diff --git a/src/gui/util/qcompleter_p.h b/src/gui/util/qcompleter_p.h index dc4189f..288f531 100644 --- a/src/gui/util/qcompleter_p.h +++ b/src/gui/util/qcompleter_p.h @@ -87,6 +87,7 @@ public: Qt::CaseSensitivity cs; int role; int column; + int maxVisibleItems; QCompleter::ModelSorting sorting; bool wrap; diff --git a/src/gui/util/qdesktopservices_win.cpp b/src/gui/util/qdesktopservices_win.cpp index 00cb4ae..62ab2f7 100644 --- a/src/gui/util/qdesktopservices_win.cpp +++ b/src/gui/util/qdesktopservices_win.cpp @@ -66,8 +66,10 @@ static bool openDocument(const QUrl &file) { if (!file.isValid()) return false; - - quintptr returnValue = (quintptr)ShellExecute(0, 0, (wchar_t*)file.toString().utf16(), 0, 0, SW_SHOWNORMAL); + QString filePath = file.toLocalFile(); + if (filePath.isEmpty()) + filePath = file.toString(); + quintptr returnValue = (quintptr)ShellExecute(0, 0, (wchar_t*)filePath.utf16(), 0, 0, SW_SHOWNORMAL); return (returnValue > 32); //ShellExecute returns a value greater than 32 if successful } diff --git a/src/gui/widgets/qdatetimeedit.cpp b/src/gui/widgets/qdatetimeedit.cpp index 1a5fa8d..5ddf7f7 100644 --- a/src/gui/widgets/qdatetimeedit.cpp +++ b/src/gui/widgets/qdatetimeedit.cpp @@ -1934,7 +1934,6 @@ QDateTime QDateTimeEditPrivate::validateAndInterpret(QString &input, int &positi /*! \internal - \reimp */ QString QDateTimeEditPrivate::textFromValue(const QVariant &f) const @@ -1945,7 +1944,6 @@ QString QDateTimeEditPrivate::textFromValue(const QVariant &f) const /*! \internal - \reimp This function's name is slightly confusing; it is not to be confused with QAbstractSpinBox::valueFromText(). @@ -2103,7 +2101,6 @@ QDateTime QDateTimeEditPrivate::stepBy(int sectionIndex, int steps, bool test) c /*! \internal - \reimp */ void QDateTimeEditPrivate::emitSignals(EmitPolicy ep, const QVariant &old) @@ -2133,7 +2130,6 @@ void QDateTimeEditPrivate::emitSignals(EmitPolicy ep, const QVariant &old) /*! \internal - \reimp */ void QDateTimeEditPrivate::_q_editorCursorPositionChanged(int oldpos, int newpos) diff --git a/src/gui/widgets/qprogressbar.cpp b/src/gui/widgets/qprogressbar.cpp index d168028..6593cd6 100644 --- a/src/gui/widgets/qprogressbar.cpp +++ b/src/gui/widgets/qprogressbar.cpp @@ -443,11 +443,11 @@ QSize QProgressBar::minimumSizeHint() const QString QProgressBar::text() const { Q_D(const QProgressBar); - if (d->maximum == 0 || d->value < d->minimum + if ((d->maximum == 0 && d->minimum == 0) || d->value < d->minimum || (d->value == INT_MIN && d->minimum == INT_MIN)) return QString(); - qint64 totalSteps = qint64(d->maximum) - qint64(d->minimum); + qint64 totalSteps = qint64(d->maximum) - d->minimum; QString result = d->format; result.replace(QLatin1String("%m"), QString::number(totalSteps)); @@ -461,7 +461,7 @@ QString QProgressBar::text() const return result; } - int progress = int(((qreal(d->value) - qreal(d->minimum)) * 100.0) / totalSteps); + int progress = (qreal(d->value) - d->minimum) * 100.0 / totalSteps; result.replace(QLatin1String("%p"), QString::number(progress)); return result; } diff --git a/src/gui/widgets/qspinbox.cpp b/src/gui/widgets/qspinbox.cpp index 3933272..7441df4 100644 --- a/src/gui/widgets/qspinbox.cpp +++ b/src/gui/widgets/qspinbox.cpp @@ -1206,7 +1206,7 @@ bool QDoubleSpinBoxPrivate::isIntermediateValue(const QString &str) const return false; } if (doright) { - QSBDEBUG("match %lld min_left %lld max_left %lld", match, min_left, max_left); + QSBDEBUG() << "match" << match << "min_left" << min_left << "max_left" << max_left; if (!doleft) { if (min_left == max_left) { const bool ret = isIntermediateValueHelper(qAbs(left), @@ -1473,7 +1473,7 @@ QString QDoubleSpinBoxPrivate::textFromValue(const QVariant &f) const static bool isIntermediateValueHelper(qint64 num, qint64 min, qint64 max, qint64 *match) { - QSBDEBUG("%lld %lld %lld", num, min, max); + QSBDEBUG() << num << min << max; if (num >= min && num <= max) { if (match) diff --git a/src/gui/widgets/qtoolbar.cpp b/src/gui/widgets/qtoolbar.cpp index b65f1ba..426c3e1 100644 --- a/src/gui/widgets/qtoolbar.cpp +++ b/src/gui/widgets/qtoolbar.cpp @@ -874,7 +874,7 @@ QAction *QToolBar::insertSeparator(QAction *before) If you add a QToolButton with this method, the tools bar's Qt::ToolButtonStyle will not be respected. - Note: You should use QAction::setVisible() to change the + \note You should use QAction::setVisible() to change the visibility of the widget. Using QWidget::setVisible(), QWidget::show() and QWidget::hide() does not work. diff --git a/src/gui/widgets/qtoolbutton.cpp b/src/gui/widgets/qtoolbutton.cpp index 6dcbfec..2c85dc5 100644 --- a/src/gui/widgets/qtoolbutton.cpp +++ b/src/gui/widgets/qtoolbutton.cpp @@ -378,7 +378,17 @@ void QToolButton::initStyleOption(QStyleOptionToolButton *option) const if (d->hasMenu()) option->features |= QStyleOptionToolButton::HasMenu; #endif - option->toolButtonStyle = d->toolButtonStyle; + if (d->toolButtonStyle == Qt::ToolButtonFollowStyle) { + option->toolButtonStyle = Qt::ToolButtonStyle(style()->styleHint(QStyle::SH_ToolButtonStyle, option, this)); + } else + option->toolButtonStyle = d->toolButtonStyle; + + if (option->toolButtonStyle == Qt::ToolButtonTextBesideIcon) { + // If the action is not prioritized, remove the text label to save space + if (d->defaultAction && d->defaultAction->priority() < QAction::NormalPriority) + option->toolButtonStyle = Qt::ToolButtonIconOnly; + } + if (d->icon.isNull() && d->arrowType == Qt::NoArrow && !forceNoText) { if (!d->text.isEmpty()) option->toolButtonStyle = Qt::ToolButtonTextOnly; @@ -476,6 +486,9 @@ QSize QToolButton::minimumSizeHint() const The default is Qt::ToolButtonIconOnly. + To have the style of toolbuttons follow the system settings (as available + in GNOME and KDE desktop environments), set this property to Qt::ToolButtonFollowStyle. + QToolButton automatically connects this slot to the relevant signal in the QMainWindow in which is resides. */ diff --git a/src/network/access/qabstractnetworkcache.cpp b/src/network/access/qabstractnetworkcache.cpp index cfc9fe7..3f44059 100644 --- a/src/network/access/qabstractnetworkcache.cpp +++ b/src/network/access/qabstractnetworkcache.cpp @@ -283,6 +283,8 @@ void QNetworkCacheMetaData::setExpirationDate(const QDateTime &dateTime) } /*! + \since 4.6 + Returns all the attributes stored with this cache item. \sa setAttributes(), QNetworkRequest::Attribute @@ -293,6 +295,8 @@ QNetworkCacheMetaData::AttributesMap QNetworkCacheMetaData::attributes() const } /*! + \since 4.6 + Sets all attributes of this cache item to be the map \a attributes. \sa attributes(), QNetworkRequest::setAttribute() diff --git a/src/network/access/qhttp.cpp b/src/network/access/qhttp.cpp index 7a02ab6..faa2398 100644 --- a/src/network/access/qhttp.cpp +++ b/src/network/access/qhttp.cpp @@ -513,6 +513,7 @@ public: /*! \class QHttpHeader + \obsolete \brief The QHttpHeader class contains header information for HTTP. \ingroup io @@ -1007,6 +1008,7 @@ public: /*! \class QHttpResponseHeader + \obsolete \brief The QHttpResponseHeader class contains response header information for HTTP. \ingroup io @@ -1152,7 +1154,7 @@ int QHttpResponseHeader::minorVersion() const return d->minVer; } -/*! \reimp +/*! \internal */ bool QHttpResponseHeader::parseLine(const QString &line, int number) { @@ -1211,6 +1213,7 @@ public: /*! \class QHttpRequestHeader + \obsolete \brief The QHttpRequestHeader class contains request header information for HTTP. \ingroup io @@ -1366,7 +1369,7 @@ int QHttpRequestHeader::minorVersion() const return d->minVer; } -/*! \reimp +/*! \internal */ bool QHttpRequestHeader::parseLine(const QString &line, int number) { diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index f1da244..c824fac 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -175,26 +175,43 @@ bool QHttpNetworkConnectionPrivate::isSocketReading(QAbstractSocket *socket) con return (i != -1 && (channels[i].state & ReadingState)); } +void QHttpNetworkConnectionPrivate::appendUncompressedData(QHttpNetworkReply &reply, QByteArray &qba) +{ + reply.d_func()->responseData.append(qba); + + // clear the original! helps with implicit sharing and + // avoiding memcpy when the user is reading the data + qba.clear(); +} -void QHttpNetworkConnectionPrivate::appendUncompressedData(QHttpNetworkReply &reply, const QByteArray &fragment) +void QHttpNetworkConnectionPrivate::appendUncompressedData(QHttpNetworkReply &reply, QByteDataBuffer &data) { - char *dst = reply.d_func()->responseData.reserve(fragment.size()); - qMemCopy(dst, fragment.constData(), fragment.size()); + reply.d_func()->responseData.append(data); + + // clear the original! helps with implicit sharing and + // avoiding memcpy when the user is reading the data + data.clear(); } -void QHttpNetworkConnectionPrivate::appendCompressedData(QHttpNetworkReply &reply, const QByteArray &fragment) +void QHttpNetworkConnectionPrivate::appendCompressedData(QHttpNetworkReply &reply, QByteDataBuffer &data) { - reply.d_func()->compressedData.append(fragment); + // Work in progress: Later we will directly use a list of QByteArray or a QRingBuffer + // instead of one QByteArray. + for(int i = 0; i < data.bufferCount(); i++) { + QByteArray &byteData = data[i]; + reply.d_func()->compressedData.append(byteData.constData(), byteData.size()); + } + data.clear(); } qint64 QHttpNetworkConnectionPrivate::uncompressedBytesAvailable(const QHttpNetworkReply &reply) const { - return reply.d_func()->responseData.size(); + return reply.d_func()->responseData.byteAmount(); } qint64 QHttpNetworkConnectionPrivate::uncompressedBytesAvailableNextBlock(const QHttpNetworkReply &reply) const { - return reply.d_func()->responseData.nextDataBlockSize(); + return reply.d_func()->responseData.sizeNextBlock(); } qint64 QHttpNetworkConnectionPrivate::compressedBytesAvailable(const QHttpNetworkReply &reply) const @@ -202,21 +219,6 @@ qint64 QHttpNetworkConnectionPrivate::compressedBytesAvailable(const QHttpNetwor return reply.d_func()->compressedData.size(); } -qint64 QHttpNetworkConnectionPrivate::read(QHttpNetworkReply &reply, QByteArray &data, qint64 maxSize) -{ - QRingBuffer *rb = &reply.d_func()->responseData; - if (maxSize == -1 || maxSize >= rb->size()) { - // read the whole data - data = rb->readAll(); - rb->clear(); - } else { - // read only the requested length - data.resize(maxSize); - rb->read(data.data(), maxSize); - } - return data.size(); -} - void QHttpNetworkConnectionPrivate::eraseData(QHttpNetworkReply *reply) { reply->d_func()->compressedData.clear(); @@ -259,7 +261,12 @@ void QHttpNetworkConnectionPrivate::prepareRequest(HttpMessagePair &messagePair) #ifndef QT_NO_NETWORKPROXY } #endif - // set the gzip header + + // If the request had a accept-encoding set, we better not mess + // with it. If it was not set, we announce that we understand gzip + // and remember this fact in request.d->autoDecompress so that + // we can later decompress the HTTP reply if it has such an + // encoding. value = request.headerField("accept-encoding"); if (value.isEmpty()) { #ifndef QT_NO_COMPRESS @@ -333,8 +340,9 @@ bool QHttpNetworkConnectionPrivate::ensureConnection(QAbstractSocket *socket) #ifndef QT_NO_OPENSSL QSslSocket *sslSocket = qobject_cast<QSslSocket*>(socket); sslSocket->connectToHostEncrypted(connectHost, connectPort); - if (channels[index].ignoreSSLErrors) + if (channels[index].ignoreAllSslErrors) sslSocket->ignoreSslErrors(); + sslSocket->ignoreSslErrors(channels[index].ignoreSslErrorsList); #else emitReplyError(socket, channels[index].reply, QNetworkReply::ProtocolUnknownError); #endif @@ -556,6 +564,8 @@ bool QHttpNetworkConnectionPrivate::expand(QAbstractSocket *socket, QHttpNetwork reply->d_func()->totalProgress += inflated.size(); appendUncompressedData(*reply, inflated); if (shouldEmitSignals(reply)) { + // important: At the point of this readyRead(), inflated must be cleared, + // else implicit sharing will trigger memcpy when the user is reading data! emit reply->readyRead(); // make sure that the reply is valid if (channels[i].reply != reply) @@ -672,18 +682,19 @@ void QHttpNetworkConnectionPrivate::receiveReply(QAbstractSocket *socket, QHttpN { // use the traditional slower reading (for compressed encoding, chunked encoding, // no content-length etc) - QBuffer fragment; - fragment.open(QIODevice::WriteOnly); - bytes = reply->d_func()->readBody(socket, &fragment); + QByteDataBuffer byteDatas; + bytes = reply->d_func()->readBody(socket, &byteDatas); if (bytes) { if (reply->d_func()->autoDecompress) - appendCompressedData(*reply, fragment.data()); + appendCompressedData(*reply, byteDatas); else - appendUncompressedData(*reply, fragment.data()); + appendUncompressedData(*reply, byteDatas); if (!reply->d_func()->autoDecompress) { - reply->d_func()->totalProgress += fragment.size(); + reply->d_func()->totalProgress += bytes; if (shouldEmitSignals(reply)) { + // important: At the point of this readyRead(), the byteDatas list must be empty, + // else implicit sharing will trigger memcpy when the user is reading data! emit reply->readyRead(); // make sure that the reply is valid if (channels[i].reply != reply) @@ -1438,15 +1449,32 @@ void QHttpNetworkConnection::ignoreSslErrors(int channel) if (channel == -1) { // ignore for all channels for (int i = 0; i < d->channelCount; ++i) { static_cast<QSslSocket *>(d->channels[i].socket)->ignoreSslErrors(); - d->channels[i].ignoreSSLErrors = true; + d->channels[i].ignoreAllSslErrors = true; } } else { static_cast<QSslSocket *>(d->channels[channel].socket)->ignoreSslErrors(); - d->channels[channel].ignoreSSLErrors = true; + d->channels[channel].ignoreAllSslErrors = true; } } +void QHttpNetworkConnection::ignoreSslErrors(const QList<QSslError> &errors, int channel) +{ + Q_D(QHttpNetworkConnection); + if (!d->encrypt) + return; + + if (channel == -1) { // ignore for all channels + for (int i = 0; i < d->channelCount; ++i) { + static_cast<QSslSocket *>(d->channels[i].socket)->ignoreSslErrors(errors); + d->channels[i].ignoreSslErrorsList = errors; + } + + } else { + static_cast<QSslSocket *>(d->channels[channel].socket)->ignoreSslErrors(errors); + d->channels[channel].ignoreSslErrorsList = errors; + } +} #endif //QT_NO_OPENSSL diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h index a0813d4..52a73a7 100644 --- a/src/network/access/qhttpnetworkconnection_p.h +++ b/src/network/access/qhttpnetworkconnection_p.h @@ -79,6 +79,7 @@ QT_BEGIN_NAMESPACE class QHttpNetworkRequest; class QHttpNetworkReply; +class QByteArray; class QHttpNetworkConnectionPrivate; class Q_AUTOTEST_EXPORT QHttpNetworkConnection : public QObject @@ -116,6 +117,7 @@ public: #ifndef QT_NO_OPENSSL void setSslConfiguration(const QSslConfiguration &config); void ignoreSslErrors(int channel = -1); + void ignoreSslErrors(const QList<QSslError> &errors, int channel = -1); Q_SIGNALS: void sslErrors(const QList<QSslError> &errors); @@ -240,13 +242,14 @@ public: QAuthenticator authenticator; QAuthenticator proxyAuthenticator; #ifndef QT_NO_OPENSSL - bool ignoreSSLErrors; + bool ignoreAllSslErrors; + QList<QSslError> ignoreSslErrorsList; #endif Channel() : socket(0), state(IdleState), reply(0), written(0), bytesTotal(0), resendCurrent(false), lastStatus(0), pendingEncrypt(false), reconnectAttempts(2), authMehtod(QAuthenticatorPrivate::None), proxyAuthMehtod(QAuthenticatorPrivate::None) #ifndef QT_NO_OPENSSL - , ignoreSSLErrors(false) + , ignoreAllSslErrors(false) #endif {} }; @@ -255,15 +258,14 @@ public: bool pendingAuthSignal; // there is an incomplete authentication signal bool pendingProxyAuthSignal; // there is an incomplete proxy authentication signal - void appendUncompressedData(QHttpNetworkReply &reply, const QByteArray &fragment); - void appendCompressedData(QHttpNetworkReply &reply, const QByteArray &fragment); + void appendUncompressedData(QHttpNetworkReply &reply, QByteArray &qba); + void appendUncompressedData(QHttpNetworkReply &reply, QByteDataBuffer &data); + void appendCompressedData(QHttpNetworkReply &reply, QByteDataBuffer &data); qint64 uncompressedBytesAvailable(const QHttpNetworkReply &reply) const; qint64 uncompressedBytesAvailableNextBlock(const QHttpNetworkReply &reply) const; qint64 compressedBytesAvailable(const QHttpNetworkReply &reply) const; - qint64 read(QHttpNetworkReply &reply, QByteArray &data, qint64 maxSize); - void emitReplyError(QAbstractSocket *socket, QHttpNetworkReply *reply, QNetworkReply::NetworkError errorCode); bool handleAuthenticateChallenge(QAbstractSocket *socket, QHttpNetworkReply *reply, bool isProxy, bool &resend); void allDone(QAbstractSocket *socket, QHttpNetworkReply *reply); diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp index 7a616aa..a623999 100644 --- a/src/network/access/qhttpnetworkreply.cpp +++ b/src/network/access/qhttpnetworkreply.cpp @@ -176,15 +176,6 @@ qint64 QHttpNetworkReply::bytesAvailableNextBlock() const return -1; } -QByteArray QHttpNetworkReply::read(qint64 maxSize) -{ - Q_D(QHttpNetworkReply); - QByteArray data; - if (d->connection) - d->connection->d_func()->read(*this, data, maxSize); - return data; -} - QByteArray QHttpNetworkReply::readAny() { Q_D(QHttpNetworkReply); @@ -203,7 +194,7 @@ QHttpNetworkReplyPrivate::QHttpNetworkReplyPrivate(const QUrl &newUrl) majorVersion(0), minorVersion(0), bodyLength(0), contentRead(0), totalProgress(0), chunkedTransferEncoding(0), currentChunkSize(0), currentChunkRead(0), connection(0), initInflate(false), - autoDecompress(false), responseData(0), requestIsPrepared(false) + autoDecompress(false), responseData(), requestIsPrepared(false) { } @@ -561,17 +552,19 @@ bool QHttpNetworkReplyPrivate::connectionCloseEnabled() // note this function can only be used for non-chunked, non-compressed with // known content length -qint64 QHttpNetworkReplyPrivate::readBodyFast(QAbstractSocket *socket, QRingBuffer *rb) -{ - quint64 toBeRead = qMin(socket->bytesAvailable(), bodyLength - contentRead); - char* dst = rb->reserve(toBeRead); - qint64 haveRead = socket->read(dst, toBeRead); +qint64 QHttpNetworkReplyPrivate::readBodyFast(QAbstractSocket *socket, QByteDataBuffer *rb) +{ + qint64 toBeRead = qMin(socket->bytesAvailable(), bodyLength - contentRead); + QByteArray bd; + bd.resize(toBeRead); + qint64 haveRead = socket->read(bd.data(), bd.size()); if (haveRead == -1) { - rb->chop(toBeRead); + bd.clear(); return 0; // ### error checking here; } + bd.resize(haveRead); - rb->chop(toBeRead - haveRead); + rb->append(bd); if (contentRead + haveRead == bodyLength) { state = AllDoneState; @@ -583,7 +576,7 @@ qint64 QHttpNetworkReplyPrivate::readBodyFast(QAbstractSocket *socket, QRingBuff } -qint64 QHttpNetworkReplyPrivate::readBody(QAbstractSocket *socket, QIODevice *out) +qint64 QHttpNetworkReplyPrivate::readBody(QAbstractSocket *socket, QByteDataBuffer *out) { qint64 bytes = 0; if (isChunked()) { @@ -601,33 +594,35 @@ qint64 QHttpNetworkReplyPrivate::readBody(QAbstractSocket *socket, QIODevice *ou return bytes; } -qint64 QHttpNetworkReplyPrivate::readReplyBodyRaw(QIODevice *in, QIODevice *out, qint64 size) +qint64 QHttpNetworkReplyPrivate::readReplyBodyRaw(QIODevice *in, QByteDataBuffer *out, qint64 size) { qint64 bytes = 0; Q_ASSERT(in); Q_ASSERT(out); int toBeRead = qMin<qint64>(128*1024, qMin<qint64>(size, in->bytesAvailable())); - QByteArray raw(toBeRead, 0); - while (size > 0) { - qint64 read = in->read(raw.data(), raw.size()); - if (read == 0) - return bytes; - // ### error checking here - qint64 written = out->write(raw.data(), read); - if (written == 0) + while (toBeRead > 0) { + QByteArray byteData; + byteData.resize(toBeRead); + qint64 haveRead = in->read(byteData.data(), byteData.size()); + if (haveRead <= 0) { + // ### error checking here + byteData.clear(); return bytes; - if (read != written) - qDebug() << "### read" << read << "written" << written; - bytes += read; - size -= read; - out->waitForBytesWritten(-1); // throttle + } + + byteData.resize(haveRead); + out->append(byteData); + bytes += haveRead; + size -= haveRead; + + toBeRead = qMin<qint64>(128*1024, qMin<qint64>(size, in->bytesAvailable())); } return bytes; } -qint64 QHttpNetworkReplyPrivate::readReplyBodyChunked(QIODevice *in, QIODevice *out) +qint64 QHttpNetworkReplyPrivate::readReplyBodyChunked(QIODevice *in, QByteDataBuffer *out) { qint64 bytes = 0; while (in->bytesAvailable()) { // while we can read from input @@ -648,17 +643,14 @@ qint64 QHttpNetworkReplyPrivate::readReplyBodyChunked(QIODevice *in, QIODevice * state = AllDoneState; break; } - // otherwise, read data - qint64 readSize = qMin(in->bytesAvailable(), currentChunkSize - currentChunkRead); - QByteArray buffer(readSize, 0); - qint64 read = in->read(buffer.data(), readSize); - bytes += read; - currentChunkRead += read; - qint64 written = out->write(buffer); - Q_UNUSED(written); // Avoid compile warning when building release - Q_ASSERT(read == written); + + // otherwise, try to read what is missing for this chunk + qint64 haveRead = readReplyBodyRaw (in, out, currentChunkSize - currentChunkRead); + currentChunkRead += haveRead; + bytes += haveRead; + // ### error checking here - out->waitForBytesWritten(-1); + } return bytes; } @@ -720,6 +712,13 @@ void QHttpNetworkReply::ignoreSslErrors() d->connection->ignoreSslErrors(); } +void QHttpNetworkReply::ignoreSslErrors(const QList<QSslError> &errors) +{ + Q_D(QHttpNetworkReply); + if (d->connection) + d->connection->ignoreSslErrors(errors); +} + #endif //QT_NO_OPENSSL diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h index 5eb70ce..575e824 100644 --- a/src/network/access/qhttpnetworkreply_p.h +++ b/src/network/access/qhttpnetworkreply_p.h @@ -80,6 +80,7 @@ static const unsigned char gz_magic[2] = {0x1f, 0x8b}; // gzip magic header #include <private/qhttpnetworkrequest_p.h> #include <private/qauthenticator_p.h> #include <private/qringbuffer_p.h> +#include <private/qbytedata_p.h> QT_BEGIN_NAMESPACE @@ -122,7 +123,6 @@ public: qint64 bytesAvailable() const; qint64 bytesAvailableNextBlock() const; - QByteArray read(qint64 maxSize = -1); QByteArray readAny(); bool isFinished() const; @@ -131,6 +131,7 @@ public: QSslConfiguration sslConfiguration() const; void setSslConfiguration(const QSslConfiguration &config); void ignoreSslErrors(); + void ignoreSslErrors(const QList<QSslError> &errors); Q_SIGNALS: void sslErrors(const QList<QSslError> &errors); @@ -160,14 +161,14 @@ public: bool parseStatus(const QByteArray &status); qint64 readHeader(QAbstractSocket *socket); void parseHeader(const QByteArray &header); - qint64 readBody(QAbstractSocket *socket, QIODevice *out); - qint64 readBodyFast(QAbstractSocket *socket, QRingBuffer *rb); + qint64 readBody(QAbstractSocket *socket, QByteDataBuffer *out); + qint64 readBodyFast(QAbstractSocket *socket, QByteDataBuffer *rb); bool findChallenge(bool forProxy, QByteArray &challenge) const; QAuthenticatorPrivate::Method authenticationMethod(bool isProxy) const; void clear(); - qint64 readReplyBodyRaw(QIODevice *in, QIODevice *out, qint64 size); - qint64 readReplyBodyChunked(QIODevice *in, QIODevice *out); + qint64 readReplyBodyRaw(QIODevice *in, QByteDataBuffer *out, qint64 size); + qint64 readReplyBodyChunked(QIODevice *in, QByteDataBuffer *out); qint64 getChunkSize(QIODevice *in, qint64 *chunkSize); qint64 bytesAvailable() const; @@ -209,7 +210,7 @@ public: #endif bool autoDecompress; - QRingBuffer responseData; // uncompressed body + QByteDataBuffer responseData; // uncompressed body QByteArray compressedData; // compressed body (temporary) bool requestIsPrepared; }; diff --git a/src/network/access/qnetworkaccessbackend.cpp b/src/network/access/qnetworkaccessbackend.cpp index 88ae894..caaa38e 100644 --- a/src/network/access/qnetworkaccessbackend.cpp +++ b/src/network/access/qnetworkaccessbackend.cpp @@ -165,6 +165,12 @@ void QNetworkAccessBackend::ignoreSslErrors() // do nothing } +void QNetworkAccessBackend::ignoreSslErrors(const QList<QSslError> &errors) +{ + Q_UNUSED(errors); + // do nothing +} + void QNetworkAccessBackend::fetchSslConfiguration(QSslConfiguration &) const { // do nothing @@ -217,9 +223,9 @@ qint64 QNetworkAccessBackend::nextDownstreamBlockSize() const return reply->nextDownstreamBlockSize(); } -void QNetworkAccessBackend::writeDownstreamData(const QByteArray &data) +void QNetworkAccessBackend::writeDownstreamData(QByteDataBuffer &list) { - reply->appendDownstreamData(data); + reply->appendDownstreamData(list); } void QNetworkAccessBackend::writeDownstreamData(QIODevice *data) diff --git a/src/network/access/qnetworkaccessbackend_p.h b/src/network/access/qnetworkaccessbackend_p.h index 21cb4a6..27da5bc 100644 --- a/src/network/access/qnetworkaccessbackend_p.h +++ b/src/network/access/qnetworkaccessbackend_p.h @@ -118,6 +118,7 @@ public: virtual void downstreamReadyWrite(); virtual void copyFinished(QIODevice *); virtual void ignoreSslErrors(); + virtual void ignoreSslErrors(const QList<QSslError> &errors); virtual void fetchSslConfiguration(QSslConfiguration &configuration) const; virtual void setSslConfiguration(const QSslConfiguration &configuration); @@ -166,7 +167,7 @@ protected: // these functions control the downstream mechanism // that is, data that has come via the connection and is going out the backend qint64 nextDownstreamBlockSize() const; - void writeDownstreamData(const QByteArray &data); + void writeDownstreamData(QByteDataBuffer &list); public slots: // for task 251801, needs to be a slot to be called asynchronously diff --git a/src/network/access/qnetworkaccesscachebackend.cpp b/src/network/access/qnetworkaccesscachebackend.cpp index f46a50a..8571ba3 100644 --- a/src/network/access/qnetworkaccesscachebackend.cpp +++ b/src/network/access/qnetworkaccesscachebackend.cpp @@ -86,6 +86,20 @@ bool QNetworkAccessCacheBackend::sendCacheContents() setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, attributes.value(QNetworkRequest::HttpReasonPhraseAttribute)); setAttribute(QNetworkRequest::SourceIsFromCacheAttribute, true); + // set the raw headers + QNetworkCacheMetaData::RawHeaderList rawHeaders = item.rawHeaders(); + QNetworkCacheMetaData::RawHeaderList::ConstIterator it = rawHeaders.constBegin(), + end = rawHeaders.constEnd(); + for ( ; it != end; ++it) + setRawHeader(it->first, it->second); + + // handle a possible redirect + QVariant redirectionTarget = attributes.value(QNetworkRequest::RedirectionTargetAttribute); + if (redirectionTarget.isValid()) { + setAttribute(QNetworkRequest::RedirectionTargetAttribute, redirectionTarget); + redirectionRequested(redirectionTarget.toUrl()); + } + // signal we're open metaDataChanged(); diff --git a/src/network/access/qnetworkaccessdatabackend.cpp b/src/network/access/qnetworkaccessdatabackend.cpp index 609f0c5..4436cf4 100644 --- a/src/network/access/qnetworkaccessdatabackend.cpp +++ b/src/network/access/qnetworkaccessdatabackend.cpp @@ -117,7 +117,11 @@ void QNetworkAccessDataBackend::open() setHeader(QNetworkRequest::ContentLengthHeader, payload.size()); emit metaDataChanged(); - writeDownstreamData(payload); + QByteDataBuffer list; + list.append(payload); + payload.clear(); // important because of implicit sharing! + writeDownstreamData(list); + finished(); return; } diff --git a/src/network/access/qnetworkaccessdebugpipebackend.cpp b/src/network/access/qnetworkaccessdebugpipebackend.cpp index 54fcddd..394e196 100644 --- a/src/network/access/qnetworkaccessdebugpipebackend.cpp +++ b/src/network/access/qnetworkaccessdebugpipebackend.cpp @@ -155,7 +155,11 @@ void QNetworkAccessDebugPipeBackend::pushFromSocketToDownstream() // have read something buffer.resize(haveRead); bytesDownloaded += haveRead; - writeDownstreamData(buffer); + + QByteDataBuffer list; + list.append(buffer); + buffer.clear(); // important because of implicit sharing! + writeDownstreamData(list); } } } @@ -276,6 +280,7 @@ void QNetworkAccessDebugPipeBackend::socketConnected() bool QNetworkAccessDebugPipeBackend::waitForDownstreamReadyRead(int ms) { + Q_UNUSED(ms); qCritical("QNetworkAccess: Debug pipe backend does not support waitForReadyRead()"); return false; } diff --git a/src/network/access/qnetworkaccessfilebackend.cpp b/src/network/access/qnetworkaccessfilebackend.cpp index e3fc8bf..533fc75 100644 --- a/src/network/access/qnetworkaccessfilebackend.cpp +++ b/src/network/access/qnetworkaccessfilebackend.cpp @@ -263,7 +263,11 @@ bool QNetworkAccessFileBackend::readMoreFromFile() data.resize(actuallyRead); totalBytes += actuallyRead; - writeDownstreamData(data); + + QByteDataBuffer list; + list.append(data); + data.clear(); // important because of implicit sharing! + writeDownstreamData(list); } return true; } diff --git a/src/network/access/qnetworkaccessftpbackend.cpp b/src/network/access/qnetworkaccessftpbackend.cpp index d6276a3..911b31a 100644 --- a/src/network/access/qnetworkaccessftpbackend.cpp +++ b/src/network/access/qnetworkaccessftpbackend.cpp @@ -355,7 +355,11 @@ void QNetworkAccessFtpBackend::ftpDone() void QNetworkAccessFtpBackend::ftpReadyRead() { - writeDownstreamData(ftp->readAll()); + QByteArray data = ftp->readAll(); + QByteDataBuffer list; + list.append(data); + data.clear(); // important because of implicit sharing! + writeDownstreamData(list); } void QNetworkAccessFtpBackend::ftpRawCommandReply(int code, const QString &text) diff --git a/src/network/access/qnetworkaccesshttpbackend.cpp b/src/network/access/qnetworkaccesshttpbackend.cpp index db84e58..5c85735 100644 --- a/src/network/access/qnetworkaccesshttpbackend.cpp +++ b/src/network/access/qnetworkaccesshttpbackend.cpp @@ -294,7 +294,7 @@ public: QNetworkAccessHttpBackend::QNetworkAccessHttpBackend() : QNetworkAccessBackend(), httpReply(0), http(0), uploadDevice(0) #ifndef QT_NO_OPENSSL - , pendingSslConfiguration(0), pendingIgnoreSslErrors(false) + , pendingSslConfiguration(0), pendingIgnoreAllSslErrors(false) #endif { } @@ -521,8 +521,9 @@ void QNetworkAccessHttpBackend::postRequest() #ifndef QT_NO_OPENSSL if (pendingSslConfiguration) httpReply->setSslConfiguration(*pendingSslConfiguration); - if (pendingIgnoreSslErrors) + if (pendingIgnoreAllSslErrors) httpReply->ignoreSslErrors(); + httpReply->ignoreSslErrors(pendingIgnoreSslErrorsList); #endif connect(httpReply, SIGNAL(readyRead()), SLOT(replyReadyRead())); @@ -653,10 +654,15 @@ void QNetworkAccessHttpBackend::readFromHttp() // this is not a critical thing since it is already in the // memory anyway - while (httpReply->bytesAvailable() != 0 && nextDownstreamBlockSize() != 0) { - const QByteArray data = httpReply->readAny(); - writeDownstreamData(data); + QByteDataBuffer list; + + while (httpReply->bytesAvailable() != 0 && nextDownstreamBlockSize() != 0 && nextDownstreamBlockSize() > list.byteAmount()) { + QByteArray data = httpReply->readAny(); + list.append(data); } + + if (!list.isEmpty()) + writeDownstreamData(list); } void QNetworkAccessHttpBackend::replyFinished() @@ -878,7 +884,18 @@ void QNetworkAccessHttpBackend::ignoreSslErrors() if (httpReply) httpReply->ignoreSslErrors(); else - pendingIgnoreSslErrors = true; + pendingIgnoreAllSslErrors = true; +} + +void QNetworkAccessHttpBackend::ignoreSslErrors(const QList<QSslError> &errors) +{ + if (httpReply) { + httpReply->ignoreSslErrors(errors); + } else { + // the pending list is set if QNetworkReply::ignoreSslErrors(const QList<QSslError> &errors) + // is called before QNetworkAccessManager::get() (or post(), etc.) + pendingIgnoreSslErrorsList = errors; + } } void QNetworkAccessHttpBackend::fetchSslConfiguration(QSslConfiguration &config) const diff --git a/src/network/access/qnetworkaccesshttpbackend_p.h b/src/network/access/qnetworkaccesshttpbackend_p.h index dec69d0..968f4a5 100644 --- a/src/network/access/qnetworkaccesshttpbackend_p.h +++ b/src/network/access/qnetworkaccesshttpbackend_p.h @@ -85,6 +85,7 @@ public: virtual void copyFinished(QIODevice *); #ifndef QT_NO_OPENSSL virtual void ignoreSslErrors(); + virtual void ignoreSslErrors(const QList<QSslError> &errors); virtual void fetchSslConfiguration(QSslConfiguration &configuration) const; virtual void setSslConfiguration(const QSslConfiguration &configuration); @@ -112,7 +113,8 @@ private: #ifndef QT_NO_OPENSSL QSslConfiguration *pendingSslConfiguration; - bool pendingIgnoreSslErrors; + bool pendingIgnoreAllSslErrors; + QList<QSslError> pendingIgnoreSslErrorsList; #endif void disconnectFromHttp(); diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 907aaef..61e5601 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -540,10 +540,10 @@ void QNetworkAccessManager::setCookieJar(QNetworkCookieJar *cookieJar) } /*! - This function is used to post a request to obtain the network - headers for \a request. It takes its name after the HTTP request - associated (HEAD). It returns a new QNetworkReply object which - will contain such headers. + Posts a request to obtain the network headers for \a request + and returns a new QNetworkReply object which will contain such headers + + The function is named after the HTTP request associated (HEAD). */ QNetworkReply *QNetworkAccessManager::head(const QNetworkRequest &request) { @@ -551,11 +551,12 @@ QNetworkReply *QNetworkAccessManager::head(const QNetworkRequest &request) } /*! - This function is used to post a request to obtain the contents of - the target \a request. It will cause the contents to be - downloaded, along with the headers associated with it. It returns - a new QNetworkReply object opened for reading which emits its - QIODevice::readyRead() signal whenever new data arrives. + Posts a request to obtain the contents of the target \a request + and returns a new QNetworkReply object opened for reading which emits the + \l{QIODevice::readyRead()}{readyRead()} signal whenever new data + arrives. + + The contents as well as associated headers will be downloaded. \sa post(), put(), deleteResource() */ @@ -565,18 +566,15 @@ QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request) } /*! - This function is used to send an HTTP POST request to the - destination specified by \a request. The contents of the \a data + Sends an HTTP POST request to the destination specified by \a request + and returns a new QNetworkReply object opened for reading that will + contain the reply sent by the server. The contents of the \a data device will be uploaded to the server. - \a data must be opened for reading when this function is called - and must remain valid until the finished() signal is emitted for - this reply. - - The returned QNetworkReply object will be open for reading and - will contain the reply sent by the server to the POST request. + \a data must be open for reading and must remain valid until the + finished() signal is emitted for this reply. - Note: sending a POST request on protocols other than HTTP and + \note Sending a POST request on protocols other than HTTP and HTTPS is undefined and will probably fail. \sa get(), put(), deleteResource() @@ -588,8 +586,9 @@ QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, QIODe /*! \overload - This function sends the contents of the \a data byte array to the - destination specified by \a request. + + Sends the contents of the \a data byte array to the destination + specified by \a request. */ QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, const QByteArray &data) { @@ -603,20 +602,19 @@ QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, const } /*! - This function is used to upload the contents of \a data to the - destination \a request. + Uploads the contents of \a data to the destination \a request and + returnes a new QNetworkReply object that will be open for reply. \a data must be opened for reading when this function is called and must remain valid until the finished() signal is emitted for this reply. - The returned QNetworkReply object will be open for reply, but - whether anything will be available for reading is protocol - dependent. For HTTP, the server may send a small HTML page - indicating the upload was successful (or not). Other protocols - will probably have content in their replies. + Whether anything will be available for reading from the returned + object is protocol dependent. For HTTP, the server may send a + small HTML page indicating the upload was successful (or not). + Other protocols will probably have content in their replies. - For HTTP, this request will send a PUT request, which most servers + \note For HTTP, this request will send a PUT request, which most servers do not allow. Form upload mechanisms, including that of uploading files through HTML forms, use the POST mechanism. @@ -629,8 +627,8 @@ QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, QIODev /*! \overload - This function sends the contents of the \a data byte array to the - destination specified by \a request. + Sends the contents of the \a data byte array to the destination + specified by \a request. */ QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, const QByteArray &data) { @@ -646,9 +644,10 @@ QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, const /*! \since 4.6 - This function is used to send a request to delete the resource - identified by the URL of \a request. - This feature is currently available for HTTP only, performing an HTTP DELETE request. + Sends a request to delete the resource identified by the URL of \a request. + + \note This feature is currently available for HTTP only, performing an + HTTP DELETE request. \sa get(), post(), put() */ diff --git a/src/network/access/qnetworkreply.cpp b/src/network/access/qnetworkreply.cpp index e807d29..3abf927 100644 --- a/src/network/access/qnetworkreply.cpp +++ b/src/network/access/qnetworkreply.cpp @@ -584,6 +584,38 @@ void QNetworkReply::setSslConfiguration(const QSslConfiguration &config) qt_metacall(QMetaObject::InvokeMetaMethod, id, arr); } } + +/*! + \overload + \since 4.6 + + If this function is called, the SSL errors given in \a errors + will be ignored. + + Note that you can set the expected certificate in the SSL error: + If, for instance, you want to issue a request to a server that uses + a self-signed certificate, consider the following snippet: + + \snippet doc/src/snippets/code/src_network_access_qnetworkreply.cpp 0 + + Multiple calls to this function will replace the list of errors that + were passed in previous calls. + You can clear the list of errors you want to ignore by calling this + function with an empty list. + + \sa sslConfiguration(), sslErrors(), QSslSocket::ignoreSslErrors() +*/ +void QNetworkReply::ignoreSslErrors(const QList<QSslError> &errors) +{ + // do this cryptic trick, because we could not add a virtual method to this class later on + // since that breaks binary compatibility + int id = metaObject()->indexOfMethod("ignoreSslErrorsImplementation(QList<QSslError>)"); + if (id != -1) { + QList<QSslError> copy(errors); + void *arr[] = { 0, © }; + qt_metacall(QMetaObject::InvokeMetaMethod, id, arr); + } +} #endif /*! @@ -598,7 +630,7 @@ void QNetworkReply::setSslConfiguration(const QSslConfiguration &config) sslErrors() signal, which indicates which errors were found. - \sa sslConfiguration(), sslErrors() + \sa sslConfiguration(), sslErrors(), QSslSocket::ignoreSslErrors() */ void QNetworkReply::ignoreSslErrors() { diff --git a/src/network/access/qnetworkreply.h b/src/network/access/qnetworkreply.h index 30e89f1..679ab71 100644 --- a/src/network/access/qnetworkreply.h +++ b/src/network/access/qnetworkreply.h @@ -134,6 +134,7 @@ public: #ifndef QT_NO_OPENSSL QSslConfiguration sslConfiguration() const; void setSslConfiguration(const QSslConfiguration &configuration); + void ignoreSslErrors(const QList<QSslError> &errors); #endif public Q_SLOTS: diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp index 55b8b7f..de7f8b4 100644 --- a/src/network/access/qnetworkreplyimpl.cpp +++ b/src/network/access/qnetworkreplyimpl.cpp @@ -103,16 +103,17 @@ void QNetworkReplyImplPrivate::_q_copyReadyRead() break; bytesToRead = qBound<qint64>(1, bytesToRead, copyDevice->bytesAvailable()); - char *ptr = readBuffer.reserve(bytesToRead); - qint64 bytesActuallyRead = copyDevice->read(ptr, bytesToRead); + QByteArray byteData; + byteData.resize(bytesToRead); + qint64 bytesActuallyRead = copyDevice->read(byteData.data(), byteData.size()); if (bytesActuallyRead == -1) { - readBuffer.chop(bytesToRead); + byteData.clear(); backendNotify(NotifyCopyFinished); break; } - if (bytesActuallyRead != bytesToRead) - readBuffer.chop(bytesToRead - bytesActuallyRead); + byteData.resize(bytesActuallyRead); + readBuffer.append(byteData); if (!copyDevice->isSequential() && copyDevice->atEnd()) { backendNotify(NotifyCopyFinished); @@ -384,25 +385,33 @@ qint64 QNetworkReplyImplPrivate::nextDownstreamBlockSize() const if (readBufferMaxSize == 0) return DesiredBufferSize; - return qMax<qint64>(0, readBufferMaxSize - readBuffer.size()); + return qMax<qint64>(0, readBufferMaxSize - readBuffer.byteAmount()); } // we received downstream data and send this to the cache // and to our readBuffer (which in turn gets read by the user of QNetworkReply) -void QNetworkReplyImplPrivate::appendDownstreamData(const QByteArray &data) +void QNetworkReplyImplPrivate::appendDownstreamData(QByteDataBuffer &data) { Q_Q(QNetworkReplyImpl); if (!q->isOpen()) return; - readBuffer.append(data); - if (cacheEnabled && !cacheSaveDevice) { // save the meta data QNetworkCacheMetaData metaData; metaData.setUrl(url); metaData = backend->fetchCacheMetaData(metaData); + + // save the redirect request also in the cache + QVariant redirectionTarget = q->attribute(QNetworkRequest::RedirectionTargetAttribute); + if (redirectionTarget.isValid()) { + QNetworkCacheMetaData::AttributesMap attributes = metaData.attributes(); + attributes.insert(QNetworkRequest::RedirectionTargetAttribute, redirectionTarget); + metaData.setAttributes(attributes); + } + cacheSaveDevice = networkCache->prepare(metaData); + if (!cacheSaveDevice || (cacheSaveDevice && !cacheSaveDevice->isOpen())) { if (cacheSaveDevice && !cacheSaveDevice->isOpen()) qCritical("QNetworkReplyImpl: network cache returned a device that is not open -- " @@ -415,10 +424,19 @@ void QNetworkReplyImplPrivate::appendDownstreamData(const QByteArray &data) } } - if (cacheSaveDevice) - cacheSaveDevice->write(data); + qint64 bytesWritten = 0; + for (int i = 0; i < data.bufferCount(); i++) { + QByteArray item = data[i]; + + if (cacheSaveDevice) + cacheSaveDevice->write(item.constData(), item.size()); + readBuffer.append(item); - bytesDownloaded += data.size(); + bytesWritten += item.size(); + } + data.clear(); + + bytesDownloaded += bytesWritten; lastBytesDownloaded = bytesDownloaded; QPointer<QNetworkReplyImpl> qq = q; @@ -427,6 +445,8 @@ void QNetworkReplyImplPrivate::appendDownstreamData(const QByteArray &data) pauseNotificationHandling(); emit q->downloadProgress(bytesDownloaded, totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong()); + // important: At the point of this readyRead(), the data parameter list must be empty, + // else implicit sharing will trigger memcpy when the user is reading data! emit q->readyRead(); // hopefully we haven't been deleted here @@ -602,14 +622,14 @@ void QNetworkReplyImpl::close() */ qint64 QNetworkReplyImpl::bytesAvailable() const { - return QNetworkReply::bytesAvailable() + d_func()->readBuffer.size(); + return QNetworkReply::bytesAvailable() + d_func()->readBuffer.byteAmount(); } void QNetworkReplyImpl::setReadBufferSize(qint64 size) { Q_D(QNetworkReplyImpl); if (size > d->readBufferMaxSize && - size == d->readBuffer.size()) + size > d->readBuffer.byteAmount()) d->backendNotify(QNetworkReplyImplPrivate::NotifyDownstreamReadyWrite); QNetworkReply::setReadBufferSize(size); @@ -639,6 +659,12 @@ void QNetworkReplyImpl::ignoreSslErrors() d->backend->ignoreSslErrors(); } +void QNetworkReplyImpl::ignoreSslErrorsImplementation(const QList<QSslError> &errors) +{ + Q_D(QNetworkReplyImpl); + if (d->backend) + d->backend->ignoreSslErrors(errors); +} #endif // QT_NO_OPENSSL /*! @@ -657,7 +683,7 @@ qint64 QNetworkReplyImpl::readData(char *data, qint64 maxlen) return 1; } - maxlen = qMin<qint64>(maxlen, d->readBuffer.size()); + maxlen = qMin<qint64>(maxlen, d->readBuffer.byteAmount()); return d->readBuffer.read(data, maxlen); } diff --git a/src/network/access/qnetworkreplyimpl_p.h b/src/network/access/qnetworkreplyimpl_p.h index 454185a..fba8d34 100644 --- a/src/network/access/qnetworkreplyimpl_p.h +++ b/src/network/access/qnetworkreplyimpl_p.h @@ -61,6 +61,7 @@ #include "QtCore/qqueue.h" #include "QtCore/qbuffer.h" #include "private/qringbuffer_p.h" +#include "private/qbytedata_p.h" QT_BEGIN_NAMESPACE @@ -88,6 +89,7 @@ public: Q_INVOKABLE QSslConfiguration sslConfigurationImplementation() const; Q_INVOKABLE void setSslConfigurationImplementation(const QSslConfiguration &configuration); virtual void ignoreSslErrors(); + Q_INVOKABLE virtual void ignoreSslErrorsImplementation(const QList<QSslError> &errors); #endif Q_DECLARE_PRIVATE(QNetworkReplyImpl) @@ -144,7 +146,7 @@ public: void consume(qint64 count); void emitUploadProgress(qint64 bytesSent, qint64 bytesTotal); qint64 nextDownstreamBlockSize() const; - void appendDownstreamData(const QByteArray &data); + void appendDownstreamData(QByteDataBuffer &data); void appendDownstreamData(QIODevice *data); void finished(); void error(QNetworkReply::NetworkError code, const QString &errorString); @@ -172,7 +174,7 @@ public: QList<QNetworkProxy> proxyList; #endif - QRingBuffer readBuffer; + QByteDataBuffer readBuffer; qint64 bytesDownloaded; qint64 lastBytesDownloaded; qint64 bytesUploaded; diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp index 42e3f09..c1fc87d 100644 --- a/src/network/access/qnetworkrequest.cpp +++ b/src/network/access/qnetworkrequest.cpp @@ -153,9 +153,7 @@ QT_BEGIN_NAMESPACE future uses. If the value is false, the data obtained will not be automatically cached. If true, data may be cached, provided it is cacheable (what is cacheable depends on the protocol - being used). Note that the default QNetworkAccessManager - implementation does not support caching, so it will ignore - this attribute. + being used). \value SourceIsFromCacheAttribute Replies only, type: QVariant::Bool (default: false) diff --git a/src/network/socket/qhttpsocketengine.cpp b/src/network/socket/qhttpsocketengine.cpp index 7bac1f2..156a9f4 100644 --- a/src/network/socket/qhttpsocketengine.cpp +++ b/src/network/socket/qhttpsocketengine.cpp @@ -454,6 +454,7 @@ void QHttpSocketEngine::slotSocketConnected() data += path; data += " HTTP/1.1\r\n"; data += "Proxy-Connection: keep-alive\r\n" + "User-Agent: Mozilla/5.0\r\n" "Host: " + peerAddress + "\r\n"; QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(d->authenticator); //qDebug() << "slotSocketConnected: priv=" << priv << (priv ? (int)priv->method : -1); diff --git a/src/network/socket/qlocalsocket_win.cpp b/src/network/socket/qlocalsocket_win.cpp index 794b2b7..3a36ac0 100644 --- a/src/network/socket/qlocalsocket_win.cpp +++ b/src/network/socket/qlocalsocket_win.cpp @@ -514,7 +514,7 @@ bool QLocalSocket::waitForReadyRead(int msecs) return false; } - qWarning("QLocalSocket::waitForReadyRead WaitForSingleObject failed with error code %d.", GetLastError()); + qWarning("QLocalSocket::waitForReadyRead WaitForSingleObject failed with error code %d.", int(GetLastError())); return false; } diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp index ce8d810..6bc23ce 100644 --- a/src/network/socket/qnativesocketengine_win.cpp +++ b/src/network/socket/qnativesocketengine_win.cpp @@ -166,11 +166,11 @@ static QByteArray qt_prettyDebug(const char *data, int len, int maxLength) Extracts the port and address from a sockaddr, and stores them in \a port and \a addr if they are non-null. */ -static inline void qt_socket_getPortAndAddress(SOCKET socketDescriptor, struct sockaddr *sa, quint16 *port, QHostAddress *address) +static inline void qt_socket_getPortAndAddress(SOCKET socketDescriptor, const qt_sockaddr *sa, quint16 *port, QHostAddress *address) { #if !defined (QT_NO_IPV6) - if (sa->sa_family == AF_INET6) { - qt_sockaddr_in6 *sa6 = (qt_sockaddr_in6 *)sa; + if (sa->a.sa_family == AF_INET6) { + const qt_sockaddr_in6 *sa6 = &sa->a6; Q_IPV6ADDR tmp; for (int i = 0; i < 16; ++i) tmp.c[i] = sa6->sin6_addr.qt_s6_addr[i]; @@ -182,8 +182,8 @@ static inline void qt_socket_getPortAndAddress(SOCKET socketDescriptor, struct s WSANtohs(socketDescriptor, sa6->sin6_port, port); } else #endif - if (sa->sa_family == AF_INET) { - struct sockaddr_in *sa4 = (struct sockaddr_in *)sa; + if (sa->a.sa_family == AF_INET) { + const sockaddr_in *sa4 = &sa->a4; unsigned long addr; WSANtohl(socketDescriptor, sa4->sin_addr.s_addr, &addr); QHostAddress a; @@ -463,20 +463,15 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters() if (socketDescriptor == -1) return false; -#if !defined (QT_NO_IPV6) - struct qt_sockaddr_storage sa; -#else - struct sockaddr_in sa; -#endif - struct sockaddr *pSa = (struct sockaddr *) &sa; - - QT_SOCKLEN_T sz = sizeof(sa); + qt_sockaddr sa; + QT_SOCKLEN_T sockAddrSize = sizeof(sa); + // Determine local address memset(&sa, 0, sizeof(sa)); - if (::getsockname(socketDescriptor, pSa, &sz) == 0) { - qt_socket_getPortAndAddress(socketDescriptor, pSa, &localPort, &localAddress); + if (::getsockname(socketDescriptor, &sa.a, &sockAddrSize) == 0) { + qt_socket_getPortAndAddress(socketDescriptor, &sa, &localPort, &localAddress); // Determine protocol family - switch (pSa->sa_family) { + switch (sa.a.sa_family) { case AF_INET: socketProtocol = QAbstractSocket::IPv4Protocol; break; @@ -500,8 +495,8 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters() } memset(&sa, 0, sizeof(sa)); - if (::getpeername(socketDescriptor, pSa, &sz) == 0) { - qt_socket_getPortAndAddress(socketDescriptor, pSa, &peerPort, &peerAddress); + if (::getpeername(socketDescriptor, &sa.a, &sockAddrSize) == 0) { + qt_socket_getPortAndAddress(socketDescriptor, &sa, &peerPort, &peerAddress); } else { WS_ERROR_DEBUG(WSAGetLastError()); } @@ -533,8 +528,8 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &address, quin struct sockaddr_in sockAddrIPv4; qt_sockaddr_in6 sockAddrIPv6; - struct sockaddr *sockAddrPtr; - QT_SOCKLEN_T sockAddrSize; + struct sockaddr *sockAddrPtr = 0; + QT_SOCKLEN_T sockAddrSize = 0; qt_socket_setPortAndAddress(socketDescriptor, &sockAddrIPv4, &sockAddrIPv6, port, address, &sockAddrPtr, &sockAddrSize); @@ -638,8 +633,8 @@ bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16 { struct sockaddr_in sockAddrIPv4; qt_sockaddr_in6 sockAddrIPv6; - struct sockaddr *sockAddrPtr; - QT_SOCKLEN_T sockAddrSize; + struct sockaddr *sockAddrPtr = 0; + QT_SOCKLEN_T sockAddrSize = 0; qt_socket_setPortAndAddress(socketDescriptor, &sockAddrIPv4, &sockAddrIPv6, port, address, &sockAddrPtr, &sockAddrSize); @@ -766,20 +761,9 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const { #if !defined(Q_OS_WINCE) // Create a sockaddr struct and reset its port number. -#if !defined(QT_NO_IPV6) - qt_sockaddr_in6 storage; - qt_sockaddr_in6 *storagePtrIPv6 = reinterpret_cast<qt_sockaddr_in6 *>(&storage); - storagePtrIPv6->sin6_port = 0; -#else - struct sockaddr storage; -#endif - sockaddr *storagePtr = reinterpret_cast<sockaddr *>(&storage); - storagePtr->sa_family = 0; - - sockaddr_in *storagePtrIPv4 = reinterpret_cast<sockaddr_in *>(&storage); - storagePtrIPv4->sin_port = 0; + qt_sockaddr storage; QT_SOCKLEN_T storageSize = sizeof(storage); - + memset(&storage, 0, storageSize); bool result = false; @@ -791,7 +775,7 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const buf.len = sizeof(c); DWORD available = 0; DWORD flags = MSG_PEEK; - int ret = ::WSARecvFrom(socketDescriptor, &buf, 1, &available, &flags, storagePtr, &storageSize,0,0); + int ret = ::WSARecvFrom(socketDescriptor, &buf, 1, &available, &flags, &storage.a, &storageSize,0,0); int err = WSAGetLastError(); if (ret == SOCKET_ERROR && err != WSAEMSGSIZE) { WS_ERROR_DEBUG(err); @@ -801,7 +785,7 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const // notifiers. flags = 0; ::WSARecvFrom(socketDescriptor, &buf, 1, &available, &flags, - storagePtr, &storageSize, 0, 0); + &storage.a, &storageSize, 0, 0); } } else { // If there's no error, or if our buffer was too small, there must be @@ -893,14 +877,11 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxL { qint64 ret = 0; -#if !defined(QT_NO_IPV6) - qt_sockaddr_storage aa; -#else - struct sockaddr_in aa; -#endif + qt_sockaddr aa; memset(&aa, 0, sizeof(aa)); QT_SOCKLEN_T sz; sz = sizeof(aa); + WSABUF buf; buf.buf = data; buf.len = maxLength; @@ -915,7 +896,7 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxL DWORD flags = 0; DWORD bytesRead = 0; - int wsaRet = ::WSARecvFrom(socketDescriptor, &buf, 1, &bytesRead, &flags, (struct sockaddr *) &aa, &sz,0,0); + int wsaRet = ::WSARecvFrom(socketDescriptor, &buf, 1, &bytesRead, &flags, &aa.a, &sz,0,0); if (wsaRet == SOCKET_ERROR) { int err = WSAGetLastError(); WS_ERROR_DEBUG(err); @@ -925,7 +906,7 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxL ret = qint64(bytesRead); } - qt_socket_getPortAndAddress(socketDescriptor, (struct sockaddr *) &aa, port, address); + qt_socket_getPortAndAddress(socketDescriptor, &aa, port, address); #if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QNativeSocketEnginePrivate::nativeReceiveDatagram(%p \"%s\", %li, %s, %i) == %li", @@ -944,8 +925,8 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l qint64 ret = -1; struct sockaddr_in sockAddrIPv4; qt_sockaddr_in6 sockAddrIPv6; - struct sockaddr *sockAddrPtr; - QT_SOCKLEN_T sockAddrSize; + struct sockaddr *sockAddrPtr = 0; + QT_SOCKLEN_T sockAddrSize = 0; qt_socket_setPortAndAddress(socketDescriptor, &sockAddrIPv4, &sockAddrIPv6, port, address, &sockAddrPtr, &sockAddrSize); diff --git a/src/network/socket/qnet_unix_p.h b/src/network/socket/qnet_unix_p.h index b33d225..03ed3b4 100644 --- a/src/network/socket/qnet_unix_p.h +++ b/src/network/socket/qnet_unix_p.h @@ -138,7 +138,8 @@ static inline int qt_safe_listen(int s, int backlog) static inline int qt_safe_connect(int sockfd, const struct sockaddr *addr, QT_SOCKLEN_T addrlen) { register int ret; - EINTR_LOOP(ret, QT_SOCKET_CONNECT(sockfd, addr, addrlen)); + // Solaris e.g. expects a non-const 2nd parameter + EINTR_LOOP(ret, QT_SOCKET_CONNECT(sockfd, const_cast<struct sockaddr *>(addr), addrlen)); return ret; } #undef QT_SOCKET_CONNECT diff --git a/src/network/socket/qudpsocket.cpp b/src/network/socket/qudpsocket.cpp index ea7753c..797becb 100644 --- a/src/network/socket/qudpsocket.cpp +++ b/src/network/socket/qudpsocket.cpp @@ -70,6 +70,9 @@ pendingDatagramSize() to obtain the size of the first pending datagram, and readDatagram() to read it. + \note An incoming datagram should be read when you receive the readyRead() + signal, otherwise this signal will not be emitted for the next datagram. + Example: \snippet doc/src/snippets/code/src_network_socket_qudpsocket.cpp 0 diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp index fc297e4..df0afe3 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -356,7 +356,7 @@ QSslSocket::~QSslSocket() want to ignore the errors and continue connecting, you must call ignoreSslErrors(), either from inside a slot function connected to the sslErrors() signal, or prior to entering encrypted mode. If - ignoreSslErrors is not called, the connection is dropped, signal + ignoreSslErrors() is not called, the connection is dropped, signal disconnected() is emitted, and QSslSocket returns to the UnconnectedState. @@ -1592,7 +1592,33 @@ void QSslSocket::startServerEncryption() void QSslSocket::ignoreSslErrors() { Q_D(QSslSocket); - d->ignoreSslErrors = true; + d->ignoreAllSslErrors = true; +} + +/*! + \overload + \since 4.6 + + This method tells QSslSocket to ignore only the errors given in \a + errors. + + Note that you can set the expected certificate in the SSL error: + If, for instance, you want to connect to a server that uses + a self-signed certificate, consider the following snippet: + + \snippet doc/src/snippets/code/src_network_ssl_qsslsocket.cpp 6 + + Multiple calls to this function will replace the list of errors that + were passed in previous calls. + You can clear the list of errors you want to ignore by calling this + function with an empty list. + + \sa sslErrors() +*/ +void QSslSocket::ignoreSslErrors(const QList<QSslError> &errors) +{ + Q_D(QSslSocket); + d->ignoreErrorsList = errors; } /*! @@ -1732,7 +1758,11 @@ void QSslSocketPrivate::init() mode = QSslSocket::UnencryptedMode; autoStartHandshake = false; connectionEncrypted = false; - ignoreSslErrors = false; + ignoreAllSslErrors = false; + + // we don't want to clear the ignoreErrorsList, so + // that it is possible setting it before connecting +// ignoreErrorsList.clear(); readBuffer.clear(); writeBuffer.clear(); diff --git a/src/network/ssl/qsslsocket.h b/src/network/ssl/qsslsocket.h index 785a083..cab0667 100644 --- a/src/network/ssl/qsslsocket.h +++ b/src/network/ssl/qsslsocket.h @@ -169,6 +169,7 @@ public: QList<QSslError> sslErrors() const; static bool supportsSsl(); + void ignoreSslErrors(const QList<QSslError> &errors); public Q_SLOTS: void startClientEncryption(); diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index ea62a4d..130494e 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -839,7 +839,27 @@ bool QSslSocketBackendPrivate::startHandshake() if (!errors.isEmpty()) { sslErrors = errors; emit q->sslErrors(errors); - if (doVerifyPeer && !ignoreSslErrors) { + + bool doEmitSslError; + if (!ignoreErrorsList.empty()) { + // check whether the errors we got are all in the list of expected errors + // (applies only if the method QSslSocket::ignoreSslErrors(const QList<QSslError> &errors) + // was called) + doEmitSslError = false; + for (int a = 0; a < errors.count(); a++) { + if (!ignoreErrorsList.contains(errors.at(a))) { + doEmitSslError = true; + break; + } + } + } else { + // if QSslSocket::ignoreSslErrors(const QList<QSslError> &errors) was not called and + // we get an SSL error, emit a signal unless we ignored all errors (by calling + // QSslSocket::ignoreSslErrors() ) + doEmitSslError = !ignoreAllSslErrors; + } + // check whether we need to emit an SSL handshake error + if (doVerifyPeer && doEmitSslError) { q->setErrorString(sslErrors.first().errorString()); q->setSocketError(QAbstractSocket::SslHandshakeFailedError); emit q->error(QAbstractSocket::SslHandshakeFailedError); diff --git a/src/network/ssl/qsslsocket_p.h b/src/network/ssl/qsslsocket_p.h index dc8e4f5..8fd2154 100644 --- a/src/network/ssl/qsslsocket_p.h +++ b/src/network/ssl/qsslsocket_p.h @@ -79,7 +79,8 @@ public: QSslSocket::SslMode mode; bool autoStartHandshake; bool connectionEncrypted; - bool ignoreSslErrors; + bool ignoreAllSslErrors; + QList<QSslError> ignoreErrorsList; bool* readyReadEmittedPointer; QRingBuffer readBuffer; diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp index 27636f4..d7c91b8 100644 --- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp +++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp @@ -49,6 +49,28 @@ QT_BEGIN_NAMESPACE +static void QGLEngineShaderManager_free(void *ptr) +{ + delete reinterpret_cast<QGLEngineShaderManager *>(ptr); +} + +Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_shader_managers, (QGLEngineShaderManager_free)) + +QGLEngineShaderManager *QGLEngineShaderManager::managerForContext(const QGLContext *context) +{ + QGLEngineShaderManager *p = reinterpret_cast<QGLEngineShaderManager *>(qt_shader_managers()->value(context)); + if (!p) { + QGLContext *oldContext = const_cast<QGLContext *>(QGLContext::currentContext()); + if (oldContext != context) + const_cast<QGLContext *>(context)->makeCurrent(); + p = new QGLEngineShaderManager(const_cast<QGLContext *>(context)); + qt_shader_managers()->insert(context, p); + if (oldContext && oldContext != context) + oldContext->makeCurrent(); + } + return p; +} + const char* QGLEngineShaderManager::qglEngineShaderSourceCode[] = { 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h index 442edfe..99711bd40 100644 --- a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h +++ b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h @@ -220,6 +220,7 @@ #include <QGLShader> #include <QGLShaderProgram> #include <QPainter> +#include <private/qgl_p.h> QT_BEGIN_HEADER @@ -314,6 +315,8 @@ public: QGLShaderProgram* simpleProgram(); // Used to draw into e.g. stencil buffers QGLShaderProgram* blitProgram(); // Used to blit a texture into the framebuffer + static QGLEngineShaderManager *managerForContext(const QGLContext *context); + enum ShaderName { MainVertexShader, MainWithTexCoordsVertexShader, diff --git a/src/opengl/gl2paintengineex/qglgradientcache.cpp b/src/opengl/gl2paintengineex/qglgradientcache.cpp index 8c6b4f0..7c54bb9 100644 --- a/src/opengl/gl2paintengineex/qglgradientcache.cpp +++ b/src/opengl/gl2paintengineex/qglgradientcache.cpp @@ -46,6 +46,28 @@ QT_BEGIN_NAMESPACE +static void QGL2GradientCache_free(void *ptr) +{ + delete reinterpret_cast<QGL2GradientCache *>(ptr); +} + +Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_gradient_caches, (QGL2GradientCache_free)) + +QGL2GradientCache *QGL2GradientCache::cacheForContext(const QGLContext *context) +{ + QGL2GradientCache *p = reinterpret_cast<QGL2GradientCache *>(qt_gradient_caches()->value(context)); + if (!p) { + QGLContext *oldContext = const_cast<QGLContext *>(QGLContext::currentContext()); + if (oldContext != context) + const_cast<QGLContext *>(context)->makeCurrent(); + p = new QGL2GradientCache; + qt_gradient_caches()->insert(context, p); + if (oldContext && oldContext != context) + oldContext->makeCurrent(); + } + return p; +} + void QGL2GradientCache::cleanCache() { QGLGradientColorTableHash::const_iterator it = cache.constBegin(); for (; it != cache.constEnd(); ++it) { @@ -55,13 +77,8 @@ void QGL2GradientCache::cleanCache() { cache.clear(); } -GLuint QGL2GradientCache::getBuffer(const QGradient &gradient, qreal opacity, const QGLContext *ctx) +GLuint QGL2GradientCache::getBuffer(const QGradient &gradient, qreal opacity) { - if (buffer_ctx && !qgl_share_reg()->checkSharing(buffer_ctx, ctx)) - cleanCache(); - - buffer_ctx = ctx; - quint64 hash_val = 0; QGradientStops stops = gradient.stops(); diff --git a/src/opengl/gl2paintengineex/qglgradientcache_p.h b/src/opengl/gl2paintengineex/qglgradientcache_p.h index 55c7b65..ba698bc 100644 --- a/src/opengl/gl2paintengineex/qglgradientcache_p.h +++ b/src/opengl/gl2paintengineex/qglgradientcache_p.h @@ -53,12 +53,12 @@ #include <QMultiHash> #include <QObject> #include <QtOpenGL/QtOpenGL> +#include <private/qgl_p.h> QT_BEGIN_NAMESPACE -class QGL2GradientCache : public QObject +class QGL2GradientCache { - Q_OBJECT struct CacheInfo { inline CacheInfo(QGradientStops s, qreal op, QGradient::InterpolationMode mode) : @@ -73,16 +73,12 @@ class QGL2GradientCache : public QObject typedef QMultiHash<quint64, CacheInfo> QGLGradientColorTableHash; public: - QGL2GradientCache() : QObject(), buffer_ctx(0) - { -/* - connect(QGLSignalProxy::instance(), - SIGNAL(aboutToDestroyContext(const QGLContext *)), - SLOT(cleanupGLContextRefs(const QGLContext *))); -*/ - } + static QGL2GradientCache *cacheForContext(const QGLContext *context); + + QGL2GradientCache() { } + ~QGL2GradientCache() {cleanCache();} - GLuint getBuffer(const QGradient &gradient, qreal opacity, const QGLContext *ctx); + GLuint getBuffer(const QGradient &gradient, qreal opacity); inline int paletteSize() const { return 1024; } protected: @@ -95,15 +91,6 @@ protected: void cleanCache(); QGLGradientColorTableHash cache; - const QGLContext *buffer_ctx; - -public slots: - void cleanupGLContextRefs(const QGLContext *context) { - if (context == buffer_ctx) { - cleanCache(); - buffer_ctx = 0; - } - } }; QT_END_NAMESPACE diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index bcff29b..167eb64 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -74,6 +74,7 @@ #include <private/qpainter_p.h> #include <private/qfontengine_p.h> #include <private/qtextureglyphcache_p.h> +#include <private/qpixmapdata_gl_p.h> #include "qglgradientcache_p.h" #include "qglengineshadermanager_p.h" @@ -115,6 +116,7 @@ public Q_SLOTS: glDeleteFramebuffers(1, &m_fbo); if (m_width || m_height) glDeleteTextures(1, &m_texture); + ctx = 0; } else { // since the context holding the texture is shared, and // about to be destroyed, we have to transfer ownership @@ -151,10 +153,17 @@ QGLTextureGlyphCache::QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyph QGLTextureGlyphCache::~QGLTextureGlyphCache() { - glDeleteFramebuffers(1, &m_fbo); - - if (m_width || m_height) - glDeleteTextures(1, &m_texture); + if (ctx) { + QGLContext *oldContext = const_cast<QGLContext *>(QGLContext::currentContext()); + if (oldContext != ctx) + ctx->makeCurrent(); + glDeleteFramebuffers(1, &m_fbo); + + if (m_width || m_height) + glDeleteTextures(1, &m_texture); + if (oldContext && oldContext != ctx) + oldContext->makeCurrent(); + } } void QGLTextureGlyphCache::createTextureData(int width, int height) @@ -252,8 +261,11 @@ void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph) if (mask.format() == QImage::Format_RGB32) { glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, m_height - c.y, maskWidth, maskHeight, GL_BGRA, GL_UNSIGNED_BYTE, mask.bits()); } else { - mask = mask.convertToFormat(QImage::Format_Indexed8); - glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_ALPHA, GL_UNSIGNED_BYTE, mask.bits()); + // If the width of the uploaded data is not a multiple of four bytes, we get some garbage + // in the glyph cache, probably because of a driver bug. + // Convert to ARGB32 to get a multiple of 4 bytes per line. + mask = mask.convertToFormat(QImage::Format_ARGB32); + glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_BGRA, GL_UNSIGNED_BYTE, mask.bits()); } } @@ -263,10 +275,6 @@ extern QImage qt_imageForBrush(int brushStyle, bool invert); QGL2PaintEngineExPrivate::~QGL2PaintEngineExPrivate() { - if (shaderManager) { - delete shaderManager; - shaderManager = 0; - } } void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id) @@ -292,6 +300,7 @@ void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMod QColor QGL2PaintEngineExPrivate::premultiplyColor(QColor c, GLfloat opacity) { qreal alpha = c.alphaF() * opacity; + c.setAlphaF(alpha); c.setRedF(c.redF() * alpha); c.setGreenF(c.greenF() * alpha); c.setBlueF(c.blueF() * alpha); @@ -335,9 +344,6 @@ void QGL2PaintEngineExPrivate::useSimpleShader() } } - -Q_GLOBAL_STATIC(QGL2GradientCache, qt_opengl_gradient_cache) - void QGL2PaintEngineExPrivate::updateBrushTexture() { // qDebug("QGL2PaintEngineExPrivate::updateBrushTexture()"); @@ -358,7 +364,10 @@ void QGL2PaintEngineExPrivate::updateBrushTexture() // We apply global opacity in the fragment shaders, so we always pass 1.0 // for opacity to the cache. - GLuint texId = qt_opengl_gradient_cache()->getBuffer(*g, 1.0, ctx); + GLuint texId = QGL2GradientCache::cacheForContext(ctx)->getBuffer(*g, 1.0); + + glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); + glBindTexture(GL_TEXTURE_2D, texId); if (g->spread() == QGradient::RepeatSpread || g->type() == QGradient::ConicalGradient) updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, true); @@ -366,9 +375,6 @@ void QGL2PaintEngineExPrivate::updateBrushTexture() updateTextureFilter(GL_TEXTURE_2D, GL_MIRRORED_REPEAT_IBM, true); else updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, true); - - glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); - glBindTexture(GL_TEXTURE_2D, texId); } else if (style == Qt::TexturePattern) { const QPixmap& texPixmap = currentBrush->texture(); @@ -1049,14 +1055,18 @@ void QGL2PaintEngineEx::drawPixmap(const QRectF& dest, const QPixmap & pixmap, c QGLContext *ctx = d->ctx; glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); - GLuint id = ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA, true); + QGLTexture *texture = ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA, true, true); + + GLfloat top = texture->yInverted ? (pixmap.height() - src.top()) : src.top(); + GLfloat bottom = texture->yInverted ? (pixmap.height() - src.bottom()) : src.bottom(); + QGLRect srcRect(src.left(), top, src.right(), bottom); bool isBitmap = pixmap.isQBitmap(); bool isOpaque = !isBitmap && !pixmap.hasAlphaChannel(); d->updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, - state()->renderHints & QPainter::SmoothPixmapTransform, id); - d->drawTexture(dest, src, pixmap.size(), isOpaque, isBitmap); + state()->renderHints & QPainter::SmoothPixmapTransform, texture->id); + d->drawTexture(dest, srcRect, pixmap.size(), isOpaque, isBitmap); } void QGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, const QRectF& src, @@ -1068,7 +1078,8 @@ void QGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, const QGLContext *ctx = d->ctx; glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); - GLuint id = ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, true); + QGLTexture *texture = ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, true); + GLuint id = texture->id; d->updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, state()->renderHints & QPainter::SmoothPixmapTransform, id); @@ -1206,11 +1217,8 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) qt_resolve_version_2_0_functions(d->ctx); #endif - if (d->shaderManager) { - d->shaderManager->setDirty(); - } else { - d->shaderManager = new QGLEngineShaderManager(d->ctx); - } + d->shaderManager = QGLEngineShaderManager::managerForContext(d->ctx); + d->shaderManager->setDirty(); glViewport(0, 0, d->width, d->height); @@ -1285,6 +1293,14 @@ bool QGL2PaintEngineEx::end() glUseProgram(0); d->transferMode(BrushDrawingMode); d->drawable.swapBuffers(); +#if defined(Q_WS_X11) + // On some (probably all) drivers, deleting an X pixmap which has been bound to a texture + // before calling glFinish/swapBuffers renders garbage. Presumably this is because X deletes + // the pixmap behind the driver's back before it's had a chance to use it. To fix this, we + // reference all QPixmaps which have been bound to stop them being deleted and only deref + // them here, after swapBuffers, where they can be safely deleted. + ctx->d_func()->boundPixmaps.clear(); +#endif d->drawable.doneCurrent(); d->ctx->d_ptr->active_engine = 0; diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 0169ea2..edda6b6 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -87,7 +87,6 @@ #include <private/qglpixelbuffer_p.h> #include <private/qwindowsurface_gl_p.h> #include "qcolormap.h" -#include "qcache.h" #include "qfile.h" #include "qlibrary.h" @@ -1395,39 +1394,99 @@ int qt_next_power_of_two(int v) return v; } -class QGLTexture { -public: - QGLTexture(const QGLContext *ctx, GLuint tx_id, GLenum tx_target, bool _clean = false) - : context(ctx), id(tx_id), target(tx_target), clean(_clean) {} - ~QGLTexture() { - if (clean) { - QGLContext *current = const_cast<QGLContext *>(QGLContext::currentContext()); - QGLContext *ctx = const_cast<QGLContext *>(context); - bool switch_context = current && current != ctx && !qgl_share_reg()->checkSharing(current, ctx); - if (switch_context) - ctx->makeCurrent(); - glDeleteTextures(1, &id); - if (switch_context) - current->makeCurrent(); - } - } - - const QGLContext *context; - GLuint id; - GLenum target; - bool clean; -}; - -typedef QCache<qint64, QGLTexture> QGLTextureCache; -static int qt_tex_cache_limit = 64*1024; // cache ~64 MB worth of textures - this is not accurate though -static QGLTextureCache *qt_tex_cache = 0; - typedef void (*_qt_pixmap_cleanup_hook_64)(qint64); typedef void (*_qt_image_cleanup_hook_64)(qint64); extern Q_GUI_EXPORT _qt_pixmap_cleanup_hook_64 qt_pixmap_cleanup_hook_64; extern Q_GUI_EXPORT _qt_image_cleanup_hook_64 qt_image_cleanup_hook_64; +static QGLTextureCache *qt_gl_texture_cache = 0; + +QGLTextureCache::QGLTextureCache() + : m_cache(64*1024) // cache ~64 MB worth of textures - this is not accurate though +{ + Q_ASSERT(qt_gl_texture_cache == 0); + qt_gl_texture_cache = this; + qt_pixmap_cleanup_hook_64 = cleanupHook; + qt_image_cleanup_hook_64 = cleanupHook; +} + +QGLTextureCache::~QGLTextureCache() +{ + qt_gl_texture_cache = 0; + qt_pixmap_cleanup_hook_64 = 0; + qt_image_cleanup_hook_64 = 0; +} + +void QGLTextureCache::insert(QGLContext* ctx, qint64 key, QGLTexture* texture, int cost) +{ + if (m_cache.totalCost() + cost > m_cache.maxCost()) { + // the cache is full - make an attempt to remove something + const QList<qint64> keys = m_cache.keys(); + int i = 0; + while (i < m_cache.count() + && (m_cache.totalCost() + cost > m_cache.maxCost())) { + QGLTexture *tex = m_cache.object(keys.at(i)); + if (tex->context == ctx) + m_cache.remove(keys.at(i)); + ++i; + } + } + m_cache.insert(key, texture, cost); +} + +bool QGLTextureCache::remove(QGLContext* ctx, GLuint textureId) +{ + QList<qint64> keys = m_cache.keys(); + for (int i = 0; i < keys.size(); ++i) { + QGLTexture *tex = m_cache.object(keys.at(i)); + if (tex->id == textureId && tex->context == ctx) { + tex->clean = true; // forces a glDeleteTextures() call + m_cache.remove(keys.at(i)); + return true; + } + } + return false; +} + +void QGLTextureCache::removeContextTextures(QGLContext* ctx) +{ + QList<qint64> keys = m_cache.keys(); + for (int i = 0; i < keys.size(); ++i) { + const qint64 &key = keys.at(i); + if (m_cache.object(key)->context == ctx) + m_cache.remove(key); + } +} + +QGLTextureCache* QGLTextureCache::instance() +{ + if (!qt_gl_texture_cache) + qt_gl_texture_cache = new QGLTextureCache; + + return qt_gl_texture_cache; +} + +/* + a hook that removes textures from the cache when a pixmap/image + is deref'ed +*/ +void QGLTextureCache::cleanupHook(qint64 cacheKey) +{ + // ### remove when the GL texture cache becomes thread-safe + if (qApp->thread() != QThread::currentThread()) + return; + QGLTexture *texture = instance()->getTexture(cacheKey); + if (texture && texture->clean) + instance()->remove(cacheKey); +} + +void QGLTextureCache::deleteIfEmpty() +{ + if (instance()->size() == 0) + delete instance(); +} + // DDS format structure struct DDSFormat { quint32 dwSize; @@ -1556,21 +1615,8 @@ QGLContext::~QGLContext() { Q_D(QGLContext); // remove any textures cached in this context - if (qt_tex_cache) { - QList<qint64> keys = qt_tex_cache->keys(); - for (int i = 0; i < keys.size(); ++i) { - const qint64 &key = keys.at(i); - if (qt_tex_cache->object(key)->context == this) - qt_tex_cache->remove(key); - } - // ### thread safety - if (qt_tex_cache->size() == 0) { - qt_pixmap_cleanup_hook_64 = 0; - qt_image_cleanup_hook_64 = 0; - delete qt_tex_cache; - qt_tex_cache = 0; - } - } + QGLTextureCache::instance()->removeContextTextures(this); + QGLTextureCache::deleteIfEmpty(); // ### thread safety QGLSignalProxy::instance()->emitAboutToDestroyContext(this); reset(); @@ -1701,21 +1747,6 @@ GLuint QGLContext::bindTexture(const QString &fileName) return tx_id; } -/* - a hook that removes textures from the cache when a pixmap/image - is deref'ed -*/ -static void qt_gl_clean_cache(qint64 cacheKey) -{ - // ### remove when the GL texture cache becomes thread-safe - if (qApp->thread() != QThread::currentThread()) - return; - if (qt_tex_cache) { - QGLTexture *texture = qt_tex_cache->object(cacheKey); - if (texture && texture->clean) - qt_tex_cache->remove(cacheKey); - } -} static void convertToGLFormatHelper(QImage &dst, const QImage &img, GLenum texture_format) { @@ -1835,7 +1866,28 @@ QImage QGLContextPrivate::convertToGLFormat(const QImage &image, bool force_prem return result; } -GLuint QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint format, +/*! \internal */ +QGLTexture *QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint format, bool clean) +{ + const qint64 key = image.cacheKey(); + QGLTexture *texture = textureCacheLookup(key, target); + if (texture) { + glBindTexture(target, texture->id); + return texture; + } + + if (!texture) + texture = bindTexture(image, target, format, key, clean); + // NOTE: bindTexture(const QImage&, GLenum, GLint, const qint64, bool) should never return null + Q_ASSERT(texture); + + if (texture->id > 0) + const_cast<QImage &>(image).data_ptr()->is_cached = true; + + return texture; +} + +QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint format, const qint64 key, bool clean) { Q_Q(QGLContext); @@ -1853,11 +1905,6 @@ GLuint QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint // the GL_BGRA format is only present in GL version >= 1.2 GLenum texture_format = (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_2) ? GL_BGRA : GL_RGBA; - if (!qt_tex_cache) { - qt_tex_cache = new QGLTextureCache(qt_tex_cache_limit); - qt_pixmap_cleanup_hook_64 = qt_gl_clean_cache; - qt_image_cleanup_hook_64 = qt_gl_clean_cache; - } // Scale the pixmap if needed. GL textures needs to have the // dimensions 2^n+2(border) x 2^m+2(border), unless we're using GL @@ -1930,53 +1977,26 @@ GLuint QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint // this assumes the size of a texture is always smaller than the max cache size int cost = img.width()*img.height()*4/1024; - if (qt_tex_cache->totalCost() + cost > qt_tex_cache->maxCost()) { - // the cache is full - make an attempt to remove something - const QList<qint64> keys = qt_tex_cache->keys(); - int i = 0; - while (i < qt_tex_cache->count() - && (qt_tex_cache->totalCost() + cost > qt_tex_cache->maxCost())) { - QGLTexture *tex = qt_tex_cache->object(keys.at(i)); - if (tex->context == q) - qt_tex_cache->remove(keys.at(i)); - ++i; - } - } - qt_tex_cache->insert(key, new QGLTexture(q, tx_id, target, clean), cost); - return tx_id; + QGLTexture *texture = new QGLTexture(q, tx_id, target, clean, false); + QGLTextureCache::instance()->insert(q, key, texture, cost); + return texture; } -bool QGLContextPrivate::textureCacheLookup(const qint64 key, GLenum target, GLuint *id) +QGLTexture *QGLContextPrivate::textureCacheLookup(const qint64 key, GLenum target) { Q_Q(QGLContext); - if (qt_tex_cache) { - QGLTexture *texture = qt_tex_cache->object(key); - if (texture && texture->target == target - && (texture->context == q || qgl_share_reg()->checkSharing(q, texture->context))) - { - *id = texture->id; - return true; - } + QGLTexture *texture = QGLTextureCache::instance()->getTexture(key); + if (texture && texture->target == target + && (texture->context == q || qgl_share_reg()->checkSharing(q, texture->context))) + { + return texture; } - return false; + return 0; } -/*! \internal */ -GLuint QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint format, bool clean) -{ - const qint64 key = image.cacheKey(); - GLuint id; - if (textureCacheLookup(key, target, &id)) { - glBindTexture(target, id); - return id; - } - GLuint cached = bindTexture(image, target, format, key, clean); - const_cast<QImage &>(image).data_ptr()->is_cached = (cached > 0); - return cached; -} /*! \internal */ -GLuint QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, bool clean) +QGLTexture *QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, bool clean, bool canInvert) { Q_Q(QGLContext); QPixmapData *pd = pixmap.pixmapData(); @@ -1984,20 +2004,41 @@ GLuint QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, GLin if (target == GL_TEXTURE_2D && pd->classId() == QPixmapData::OpenGLClass) { const QGLPixmapData *data = static_cast<const QGLPixmapData *>(pd); - if (data->isValidContext(q)) - return data->bind(); + if (data->isValidContext(q)) { + data->bind(); + return data->texture(); + } } #endif const qint64 key = pixmap.cacheKey(); - GLuint id; - if (textureCacheLookup(key, target, &id)) { - glBindTexture(target, id); - return id; + QGLTexture *texture = textureCacheLookup(key, target); + if (texture) { + glBindTexture(target, texture->id); + return texture; } - GLuint cached = bindTexture(pixmap.toImage(), target, format, key, clean); - const_cast<QPixmap &>(pixmap).data_ptr()->is_cached = (cached > 0); - return cached; + +#if defined(Q_WS_X11) + // Try to use texture_from_pixmap + if (pd->classId() == QPixmapData::X11Class) { + QPixmap *thatPixmap = const_cast<QPixmap*>(&pixmap); + texture = bindTextureFromNativePixmap(thatPixmap, key, canInvert); + if (texture) { + texture->clean = clean; + boundPixmaps.insert(thatPixmap->data_ptr(), QPixmap(pixmap)); + } + } +#endif + + if (!texture) + texture = bindTexture(pixmap.toImage(), target, format, key, clean); + // NOTE: bindTexture(const QImage&, GLenum, GLint, const qint64, bool) should never return null + Q_ASSERT(texture); + + if (texture->id > 0) + const_cast<QPixmap &>(pixmap).data_ptr()->is_cached = true; + + return texture; } /*! \internal */ @@ -2063,7 +2104,8 @@ int QGLContextPrivate::maxTextureSize() GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format) { Q_D(QGLContext); - return d->bindTexture(image, target, format, false); + QGLTexture *texture = d->bindTexture(image, target, format, false); + return texture->id; } #ifdef Q_MAC_COMPAT_GL_FUNCTIONS @@ -2071,7 +2113,8 @@ GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format) GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format) { Q_D(QGLContext); - return d->bindTexture(image, GLenum(target), GLint(format), false); + QGLTexture *texture = d->bindTexture(image, GLenum(target), GLint(format), false); + return texture->id; } #endif @@ -2082,7 +2125,8 @@ GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMa GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint format) { Q_D(QGLContext); - return d->bindTexture(pixmap, target, format, false); + QGLTexture *texture = d->bindTexture(pixmap, target, format, false, false); + return texture->id; } #ifdef Q_MAC_COMPAT_GL_FUNCTIONS @@ -2090,7 +2134,8 @@ GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint forma GLuint QGLContext::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format) { Q_D(QGLContext); - return d->bindTexture(pixmap, GLenum(target), GLint(format), false); + QGLTexture *texture = d->bindTexture(pixmap, GLenum(target), GLint(format), false, false); + return texture->id; } #endif @@ -2103,17 +2148,8 @@ GLuint QGLContext::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, Q */ void QGLContext::deleteTexture(GLuint id) { - if (qt_tex_cache) { - QList<qint64> keys = qt_tex_cache->keys(); - for (int i = 0; i < keys.size(); ++i) { - QGLTexture *tex = qt_tex_cache->object(keys.at(i)); - if (tex->id == id && tex->context == this) { - tex->clean = true; // forces a glDeleteTextures() call - qt_tex_cache->remove(keys.at(i)); - return; - } - } - } + if (QGLTextureCache::instance()->remove(this, id)) + return; // check the DDS cache if the texture wasn't found in the pixmap/image // cache @@ -2307,9 +2343,7 @@ void QGLContext::drawTexture(const QPointF &point, QMacCompatGLuint textureId, Q */ void QGLContext::setTextureCacheLimit(int size) { - qt_tex_cache_limit = size; - if (qt_tex_cache) - qt_tex_cache->setMaxCost(qt_tex_cache_limit); + QGLTextureCache::instance()->setMaxCost(size); } /*! @@ -2319,7 +2353,7 @@ void QGLContext::setTextureCacheLimit(int size) */ int QGLContext::textureCacheLimit() { - return qt_tex_cache_limit; + return QGLTextureCache::instance()->maxCost(); } @@ -3363,8 +3397,13 @@ bool QGLWidget::event(QEvent *e) #elif defined(Q_WS_WIN) if (e->type() == QEvent::ParentChange) { QGLContext *newContext = new QGLContext(d->glcx->requestedFormat(), this); - qgl_share_reg()->replaceShare(d->glcx, newContext); + QList<const QGLContext *> shares = qgl_share_reg()->shares(d->glcx); setContext(newContext); + for (int i = 0; i < shares.size(); ++i) { + if (newContext != shares.at(i)) + qgl_share_reg()->addShare(newContext, shares.at(i)); + } + // the overlay needs to be recreated as well delete d->olcx; if (isValid() && context()->format().hasOverlay()) { @@ -4334,6 +4373,9 @@ void QGLExtensions::init_extensions() if (extensions.contains(QLatin1String("EXT_framebuffer_blit"))) glExtensions |= FramebufferBlit; + if (extensions.contains(QLatin1String("GL_ARB_texture_non_power_of_two"))) + glExtensions |= NPOTTextures; + QGLContext cx(QGLFormat::defaultFormat()); if (glExtensions & TextureCompression) { qt_glCompressedTexImage2DARB = (pfn_glCompressedTexImage2DARB) cx.getProcAddress(QLatin1String("glCompressedTexImage2DARB")); @@ -4541,32 +4583,34 @@ QGLFormat QGLDrawable::format() const GLuint QGLDrawable::bindTexture(const QImage &image, GLenum target, GLint format) { + QGLTexture *texture; if (widget) - return widget->d_func()->glcx->d_func()->bindTexture(image, target, format, true); + texture = widget->d_func()->glcx->d_func()->bindTexture(image, target, format, true); else if (buffer) - return buffer->d_func()->qctx->d_func()->bindTexture(image, target, format, true); + texture = buffer->d_func()->qctx->d_func()->bindTexture(image, target, format, true); else if (fbo && QGLContext::currentContext()) - return const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(image, target, format, true); + texture = const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(image, target, format, true); #if defined(Q_WS_QWS) || (!defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)) else if (wsurf) - return wsurf->context()->d_func()->bindTexture(image, target, format, true); + texture = wsurf->context()->d_func()->bindTexture(image, target, format, true); #endif - return 0; + return texture->id; } GLuint QGLDrawable::bindTexture(const QPixmap &pixmap, GLenum target, GLint format) { + QGLTexture *texture; if (widget) - return widget->d_func()->glcx->d_func()->bindTexture(pixmap, target, format, true); + texture = widget->d_func()->glcx->d_func()->bindTexture(pixmap, target, format, true, true); else if (buffer) - return buffer->d_func()->qctx->d_func()->bindTexture(pixmap, target, format, true); + texture = buffer->d_func()->qctx->d_func()->bindTexture(pixmap, target, format, true, true); else if (fbo && QGLContext::currentContext()) - return const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(pixmap, target, format, true); + texture = const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(pixmap, target, format, true, true); #if defined(Q_WS_QWS) || (!defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)) else if (wsurf) - return wsurf->context()->d_func()->bindTexture(pixmap, target, format, true); + texture = wsurf->context()->d_func()->bindTexture(pixmap, target, format, true, true); #endif - return 0; + return texture->id; } QColor QGLDrawable::backgroundColor() const @@ -4612,4 +4656,156 @@ bool QGLDrawable::autoFillBackground() const return false; } + +bool QGLShareRegister::checkSharing(const QGLContext *context1, const QGLContext *context2) { + bool sharing = (context1 && context2 && context1->d_ptr->groupResources == context2->d_ptr->groupResources); + return sharing; +} + +void QGLShareRegister::addShare(const QGLContext *context, const QGLContext *share) { + Q_ASSERT(context && share); + if (context->d_ptr->groupResources == share->d_ptr->groupResources) + return; + + // Make sure 'context' is not already shared with another group of contexts. + Q_ASSERT(reg.find(context->d_ptr->groupResources) == reg.end()); + Q_ASSERT(context->d_ptr->groupResources->refs == 1); + + // Free 'context' group resources and make it use the same resources as 'share'. + delete context->d_ptr->groupResources; + context->d_ptr->groupResources = share->d_ptr->groupResources; + context->d_ptr->groupResources->refs.ref(); + + // Maintain a list of all the contexts in each group of sharing contexts. + SharingHash::iterator it = reg.find(share->d_ptr->groupResources); + if (it == reg.end()) + it = reg.insert(share->d_ptr->groupResources, ContextList() << share); + it.value() << context; +} + +QList<const QGLContext *> QGLShareRegister::shares(const QGLContext *context) { + SharingHash::const_iterator it = reg.find(context->d_ptr->groupResources); + if (it == reg.end()) + return ContextList(); + return it.value(); +} + +void QGLShareRegister::removeShare(const QGLContext *context) { + SharingHash::iterator it = reg.find(context->d_ptr->groupResources); + if (it == reg.end()) + return; + + int count = it.value().removeAll(context); + Q_ASSERT(count == 1); + + Q_ASSERT(it.value().size() != 0); + if (it.value().size() == 1) + reg.erase(it); +} + +QGLContextResource::QGLContextResource(FreeFunc f, QObject *parent) + : QObject(parent), free(f) +{ + connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext *)), this, SLOT(aboutToDestroyContext(const QGLContext *))); +} + +QGLContextResource::~QGLContextResource() +{ + while (!m_resources.empty()) + remove(m_resources.begin().key()); +} + +void QGLContextResource::insert(const QGLContext *key, void *value) +{ + QList<const QGLContext *> shares = qgl_share_reg()->shares(key); + if (shares.size() == 0) + shares.append(key); + void *oldValue = 0; + for (int i = 0; i < shares.size(); ++i) { + ResourceHash::iterator it = m_resources.find(shares.at(i)); + if (it != m_resources.end()) { + Q_ASSERT(oldValue == 0 || oldValue == it.value()); + oldValue = it.value(); + it.value() = value; + } else { + m_resources.insert(shares.at(i), value); + } + } + if (oldValue != 0 && oldValue != value) { + QGLContext *oldContext = const_cast<QGLContext *>(QGLContext::currentContext()); + if (oldContext != key) + const_cast<QGLContext *>(key)->makeCurrent(); + free(oldValue); + if (oldContext && oldContext != key) + oldContext->makeCurrent(); + } +} + +void *QGLContextResource::value(const QGLContext *key) +{ + ResourceHash::const_iterator it = m_resources.find(key); + // Check if there is a value associated with 'key'. + if (it != m_resources.end()) + return it.value(); + // Check if there is a value associated with sharing contexts. + QList<const QGLContext *> shares = qgl_share_reg()->shares(key); + for (int i = 0; i < shares.size() && it == m_resources.end(); ++i) + it = m_resources.find(shares.at(i)); + if (it == m_resources.end()) + return 0; // Didn't find anything. + + // Found something! Share this info with all the buddies. + for (int i = 0; i < shares.size(); ++i) + m_resources.insert(shares.at(i), it.value()); + return it.value(); +} + +void QGLContextResource::remove(const QGLContext *key) +{ + QList<const QGLContext *> shares = qgl_share_reg()->shares(key); + if (shares.size() == 0) + shares.append(key); + void *oldValue = 0; + for (int i = 0; i < shares.size(); ++i) { + ResourceHash::iterator it = m_resources.find(shares.at(i)); + if (it != m_resources.end()) { + Q_ASSERT(oldValue == 0 || oldValue == it.value()); + oldValue = it.value(); + m_resources.erase(it); + } + } + if (oldValue != 0) { + QGLContext *oldContext = const_cast<QGLContext *>(QGLContext::currentContext()); + if (oldContext != key) + const_cast<QGLContext *>(key)->makeCurrent(); + free(oldValue); + if (oldContext && oldContext != key) + oldContext->makeCurrent(); + } +} + +void QGLContextResource::aboutToDestroyContext(const QGLContext *key) +{ + ResourceHash::iterator it = m_resources.find(key); + if (it == m_resources.end()) + return; + + QList<const QGLContext *> shares = qgl_share_reg()->shares(key); + if (shares.size() > 1) { + Q_ASSERT(key->isSharing()); + // At least one of the shared contexts must stay in the cache. + // Otherwise, the value pointer is lost. + for (int i = 0; i < 2/*shares.size()*/; ++i) + m_resources.insert(shares.at(i), it.value()); + } else { + QGLContext *oldContext = const_cast<QGLContext *>(QGLContext::currentContext()); + if (oldContext != key) + const_cast<QGLContext *>(key)->makeCurrent(); + free(it.value()); + if (oldContext && oldContext != key) + oldContext->makeCurrent(); + } + m_resources.erase(it); +} + QT_END_NAMESPACE diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h index 86555da..31b9543 100644 --- a/src/opengl/qgl.h +++ b/src/opengl/qgl.h @@ -364,6 +364,7 @@ private: friend class QGLPixmapData; friend class QGLPixmapFilterBase; friend class QGLTextureGlyphCache; + friend class QGLShareRegister; friend QGLFormat::OpenGLVersionFlags QGLFormat::openGLVersionFlags(); #ifdef Q_WS_MAC public: diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index ac19d64..85dae0d 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -60,10 +60,7 @@ #include "QtCore/qthreadstorage.h" #include "QtCore/qhash.h" #include "private/qwidget_p.h" - -#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) -#include "private/qpixmapdata_gl_p.h" -#endif +#include "qcache.h" #ifndef QT_OPENGL_ES_1_CL #define q_vertexType float @@ -196,17 +193,26 @@ public: #endif }; +struct QGLContextGroupResources +{ + QGLContextGroupResources() : refs(1) { } + QGLExtensionFuncs extensionFuncs; + QAtomicInt refs; +}; + +class QGLTexture; + class QGLContextPrivate { Q_DECLARE_PUBLIC(QGLContext) public: - explicit QGLContextPrivate(QGLContext *context) : internal_context(false), q_ptr(context) {} - ~QGLContextPrivate() {} - GLuint bindTexture(const QImage &image, GLenum target, GLint format, const qint64 key, + explicit QGLContextPrivate(QGLContext *context) : internal_context(false), q_ptr(context) {groupResources = new QGLContextGroupResources;} + ~QGLContextPrivate() {if (!groupResources->refs.deref()) delete groupResources;} + QGLTexture *bindTexture(const QImage &image, GLenum target, GLint format, bool clean); + QGLTexture *bindTexture(const QImage &image, GLenum target, GLint format, const qint64 key, bool clean = false); - GLuint bindTexture(const QPixmap &pixmap, GLenum target, GLint format, bool clean); - GLuint bindTexture(const QImage &image, GLenum target, GLint format, bool clean); - bool textureCacheLookup(const qint64 key, GLenum target, GLuint *id); + QGLTexture *bindTexture(const QPixmap &pixmap, GLenum target, GLint format, bool clean, bool canInvert = false); + QGLTexture *textureCacheLookup(const qint64 key, GLenum target); void init(QPaintDevice *dev, const QGLFormat &format); QImage convertToGLFormat(const QImage &image, bool force_premul, GLenum texture_format); int maxTextureSize(); @@ -234,6 +240,8 @@ public: void* pbuf; quint32 gpm; int screen; + QHash<QPixmapData*, QPixmap> boundPixmaps; + QGLTexture *bindTextureFromNativePixmap(QPixmap *pm, const qint64 key, bool internal); #endif #if defined(Q_WS_MAC) bool update; @@ -257,14 +265,14 @@ public: QGLContext *q_ptr; QGLFormat::OpenGLVersionFlags version_flags; - QGLExtensionFuncs extensionFuncs; + QGLContextGroupResources *groupResources; GLint max_texture_size; GLuint current_fbo; QPaintEngine *active_engine; #ifdef Q_WS_WIN - static inline QGLExtensionFuncs& qt_get_extension_funcs(const QGLContext *ctx) { return ctx->d_ptr->extensionFuncs; } + static inline QGLExtensionFuncs& qt_get_extension_funcs(const QGLContext *ctx) { return ctx->d_ptr->groupResources->extensionFuncs; } #endif #if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS) @@ -293,6 +301,7 @@ class QGLPixelBuffer; class QGLFramebufferObject; class QWSGLWindowSurface; class QGLWindowSurface; +class QGLPixmapData; class QGLDrawable { public: QGLDrawable() : widget(0), buffer(0), fbo(0) @@ -353,7 +362,8 @@ public: PackedDepthStencil = 0x00000200, NVFloatBuffer = 0x00000400, PixelBufferObject = 0x00000800, - FramebufferBlit = 0x00001000 + FramebufferBlit = 0x00001000, + NPOTTextures = 0x00002000 }; Q_DECLARE_FLAGS(Extensions, Extension) @@ -371,65 +381,89 @@ struct QGLThreadContext { }; extern QThreadStorage<QGLThreadContext *> qgl_context_storage; -typedef QMultiHash<const QGLContext *, const QGLContext *> QGLSharingHash; class QGLShareRegister { public: QGLShareRegister() {} ~QGLShareRegister() { reg.clear(); } - bool checkSharing(const QGLContext *context1, const QGLContext *context2, const QGLContext * skip=0) { - if (context1 == context2) - return true; - QList<const QGLContext *> shares = reg.values(context1); - for (int k=0; k<shares.size(); ++k) { - const QGLContext *ctx = shares.at(k); - if (ctx == skip) // avoid an indirect circular loop (infinite recursion) - continue; - if (ctx == context2) - return true; - if (checkSharing(ctx, context2, context1)) - return true; - } - return false; - } + bool checkSharing(const QGLContext *context1, const QGLContext *context2); + void addShare(const QGLContext *context, const QGLContext *share); + QList<const QGLContext *> shares(const QGLContext *context); + void removeShare(const QGLContext *context); +private: + // Use a context's 'groupResources' pointer to uniquely identify a group. + typedef QList<const QGLContext *> ContextList; + typedef QHash<const QGLContextGroupResources *, ContextList> SharingHash; + SharingHash reg; +}; - void addShare(const QGLContext *context, const QGLContext *share) { - reg.insert(context, share); // context sharing works both ways - reg.insert(share, context); - } +extern Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg(); - void removeShare(const QGLContext *context) { - QGLSharingHash::iterator it = reg.begin(); - while (it != reg.end()) { - if (it.key() == context || it.value() == context) - it = reg.erase(it); - else - ++it; +class QGLTexture { +public: + QGLTexture(QGLContext *ctx = 0, GLuint tx_id = 0, GLenum tx_target = GL_TEXTURE_2D, + bool _clean = false, bool _yInverted = false) + : context(ctx), id(tx_id), target(tx_target), clean(_clean), yInverted(_yInverted) +#if defined(Q_WS_X11) + , boundPixmap(0) +#endif + {} + + ~QGLTexture() { + if (clean) { + QGLContext *current = const_cast<QGLContext *>(QGLContext::currentContext()); + QGLContext *ctx = const_cast<QGLContext *>(context); + Q_ASSERT(ctx); + bool switch_context = current != ctx && !qgl_share_reg()->checkSharing(current, ctx); + if (switch_context) + ctx->makeCurrent(); +#if defined(Q_WS_X11) + // Although glXReleaseTexImage is a glX call, it must be called while there + // is a current context - the context the pixmap was bound to a texture in. + // Otherwise the release doesn't do anything and you get BadDrawable errors + // when you come to delete the context. + deleteBoundPixmap(); +#endif + glDeleteTextures(1, &id); + if (switch_context && current) + current->makeCurrent(); } - } + } - void replaceShare(const QGLContext *oldContext, const QGLContext *newContext) { - QGLSharingHash::iterator it = reg.begin(); - while (it != reg.end()) { - if (it.key() == oldContext) - reg.insert(newContext, it.value()); - else if (it.value() == oldContext) - reg.insert(it.key(), newContext); - ++it; - } - removeShare(oldContext); - } + QGLContext *context; + GLuint id; + GLenum target; + bool clean; + bool yInverted; // NOTE: Y-Inverted textures are for internal use only! +#if defined(Q_WS_X11) + Qt::HANDLE boundPixmap; + void deleteBoundPixmap(); // in qgl_x11.cpp/qgl_x11egl.cpp +#endif +}; - QList<const QGLContext *> shares(const QGLContext *context) { - return reg.values(context); - } +class QGLTextureCache { +public: + QGLTextureCache(); + ~QGLTextureCache(); + + void insert(QGLContext *ctx, qint64 key, QGLTexture *texture, int cost); + void remove(quint64 key) { m_cache.remove(key); } + bool remove(QGLContext *ctx, GLuint textureId); + void removeContextTextures(QGLContext *ctx); + int size() { return m_cache.size(); } + void setMaxCost(int newMax) { m_cache.setMaxCost(newMax); } + int maxCost() {return m_cache.maxCost(); } + QGLTexture* getTexture(quint64 key) { return m_cache.object(key); } + + static QGLTextureCache *instance(); + static void deleteIfEmpty(); + static void cleanupHook(qint64 cacheKey); private: - QGLSharingHash reg; + QCache<qint64, QGLTexture> m_cache; }; -extern Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg(); #ifdef Q_WS_QWS extern QPaintEngine* qt_qgl_paint_engine(); @@ -464,6 +498,29 @@ inline GLenum qt_gl_preferredTextureTarget() #endif } +// One resource per group of shared contexts. +class QGLContextResource : public QObject +{ + Q_OBJECT +public: + typedef void (*FreeFunc)(void *); + QGLContextResource(FreeFunc f, QObject *parent = 0); + ~QGLContextResource(); + // Set resource 'value' for 'key' and all its shared contexts. + void insert(const QGLContext *key, void *value); + // Return resource for 'key' or a shared context. + void *value(const QGLContext *key); + // Free resource for 'key' and all its shared contexts. + void remove(const QGLContext *key); +private slots: + // Remove entry 'key' from cache and delete resource if there are no shared contexts. + void aboutToDestroyContext(const QGLContext *key); +private: + typedef QHash<const QGLContext *, void *> ResourceHash; + ResourceHash m_resources; + FreeFunc free; +}; + QT_END_NAMESPACE #endif // QGL_P_H diff --git a/src/opengl/qgl_win.cpp b/src/opengl/qgl_win.cpp index 400b3bc..232d47b 100644 --- a/src/opengl/qgl_win.cpp +++ b/src/opengl/qgl_win.cpp @@ -1413,7 +1413,7 @@ void QGLWidget::setContext(QGLContext *context, } if (!d->glcx->isValid()) { - bool wasSharing = shareContext || oldcx && oldcx->isSharing(); + bool wasSharing = shareContext || (oldcx && oldcx->isSharing()); d->glcx->create(shareContext ? shareContext : oldcx); // the above is a trick to keep disp lists etc when a // QGLWidget has been reparented, so remove the sharing diff --git a/src/opengl/qgl_x11.cpp b/src/opengl/qgl_x11.cpp index 631625b..d8af4d5 100644 --- a/src/opengl/qgl_x11.cpp +++ b/src/opengl/qgl_x11.cpp @@ -52,6 +52,7 @@ #include "qdebug.h" #include <private/qfontengine_ft_p.h> #include <private/qt_x11_p.h> +#include <private/qpixmap_x11_p.h> #ifdef Q_OS_HPUX // for GLXPBuffer #include <private/qglpixelbuffer_p.h> @@ -1516,4 +1517,124 @@ void QGLExtensions::init() } } + +typedef void (*qt_glXBindTexImageEXT)(Display*, GLXDrawable, int, const int*); +typedef void (*qt_glXReleaseTexImageEXT)(Display*, GLXDrawable, int); +static qt_glXBindTexImageEXT glXBindTexImageEXT = 0; +static qt_glXReleaseTexImageEXT glXReleaseTexImageEXT = 0; +static bool qt_resolved_texture_from_pixmap = false; + +QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmap *pm, const qint64 key, bool canInvert) +{ + Q_Q(QGLContext); + + if (pm->data_ptr()->classId() != QPixmapData::X11Class) + return 0; + QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pm->data_ptr()); + const QX11Info *x11Info = qt_x11Info(pm); + + + // Check to see if we have NPOT texture support + // TODO: Use GLX_TEXTURE_RECTANGLE_EXT texture target on systems without npot textures + if ( !(QGLExtensions::glExtensions & QGLExtensions::NPOTTextures) && + !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0)) + return 0; + + if (!qt_resolved_texture_from_pixmap) { + qt_resolved_texture_from_pixmap = true; + + QString glxExt = QLatin1String(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS)); + if (glxExt.contains(QLatin1String("GLX_EXT_texture_from_pixmap"))) { +#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) + void *handle = dlopen(NULL, RTLD_LAZY); + if (handle) { + glXBindTexImageEXT = (qt_glXBindTexImageEXT) dlsym(handle, "glXBindTexImageEXT"); + glXReleaseTexImageEXT = (qt_glXReleaseTexImageEXT) dlsym(handle, "glXReleaseTexImageEXT"); + dlclose(handle); + } + if (!glXBindTexImageEXT) +#endif + { + extern const QString qt_gl_library_name(); + QLibrary lib(qt_gl_library_name()); + glXBindTexImageEXT = (qt_glXBindTexImageEXT) lib.resolve("glXBindTexImageEXT"); + glXReleaseTexImageEXT = (qt_glXReleaseTexImageEXT) lib.resolve("glXReleaseTexImageEXT"); + } + } + } + + if (!glXBindTexImageEXT) + return 0; + +#if !defined(GLX_VERSION_1_3) || defined(Q_OS_HPUX) + return 0; +#else + GLXFBConfig *configList = 0; + GLXFBConfig glxPixmapConfig; + int configCount = 0; + bool hasAlpha = pixmapData->hasAlphaChannel(); + + int configAttribs[] = { + hasAlpha ? GLX_BIND_TO_TEXTURE_RGBA_EXT : GLX_BIND_TO_TEXTURE_RGB_EXT, True, + GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, + GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT, + // QGLContext::bindTexture() can't return an inverted texture, but QPainter::drawPixmap() can: + GLX_Y_INVERTED_EXT, canInvert ? GLX_DONT_CARE : False, + XNone +// GLX_BIND_TO_MIPMAP_TEXTURE_EXT, False, +// GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_1D_BIT_EXT or GLX_TEXTURE_2D_BIT_EXT or GLX_TEXTURE_RECTANGLE_BIT_EXT + }; + configList = glXChooseFBConfig(x11Info->display(), x11Info->screen(), configAttribs, &configCount); + if (!configList) + return 0; + glxPixmapConfig = configList[0]; + XFree(configList); + + GLXPixmap glxPixmap; + int pixmapAttribs[] = { + GLX_TEXTURE_FORMAT_EXT, hasAlpha ? GLX_TEXTURE_FORMAT_RGBA_EXT : GLX_TEXTURE_FORMAT_RGB_EXT, + GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, + GLX_MIPMAP_TEXTURE_EXT, False, + XNone +// GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT or GLX_TEXTURE_FORMAT_RGB_EXT or GLX_TEXTURE_FORMAT_NONE_EXT, +// GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT or GLX_TEXTURE_RECTANGLE_EXT, +// GLX_MIPMAP_TEXTURE_EXT, True or False, + }; + + // Wrap the X Pixmap into a GLXPixmap: + glxPixmap = glXCreatePixmap(x11Info->display(), glxPixmapConfig, pixmapData->handle(), pixmapAttribs); + + if (!glxPixmap) + return 0; + + int yInverted; + glXGetFBConfigAttrib(x11Info->display(), glxPixmapConfig, GLX_Y_INVERTED_EXT, &yInverted); + + GLuint textureId; + glGenTextures(1, &textureId); + glBindTexture(GL_TEXTURE_2D, textureId); + glXBindTexImageEXT(x11Info->display(), glxPixmap, GLX_FRONT_LEFT_EXT, 0); + + glBindTexture(GL_TEXTURE_2D, textureId); + + QGLTexture *texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, canInvert, yInverted); + texture->boundPixmap = glxPixmap; + + // We assume the cost of bound pixmaps is zero + QGLTextureCache::instance()->insert(q, key, texture, 0); + + return texture; +#endif //!defined(GLX_VERSION_1_3) || defined(Q_OS_HPUX) +} + +void QGLTexture::deleteBoundPixmap() +{ + if (boundPixmap) { + glXReleaseTexImageEXT(QX11Info::display(), boundPixmap, GLX_FRONT_LEFT_EXT); + glXDestroyPixmap(QX11Info::display(), boundPixmap); + boundPixmap = 0; + } +} + + QT_END_NAMESPACE diff --git a/src/opengl/qgl_x11egl.cpp b/src/opengl/qgl_x11egl.cpp index 9db3a30..11131ea 100644 --- a/src/opengl/qgl_x11egl.cpp +++ b/src/opengl/qgl_x11egl.cpp @@ -469,4 +469,15 @@ void QGLWidgetPrivate::recreateEglSurface(bool force) } } +GLuint QGLContextPrivate::bindTextureFromNativePixmap(const QPixmap& pm, const qint64 key, bool canInvert) +{ + // TODO + return 0; +} + +void QGLTexture::deleteBoundPixmap() +{ + //TODO +} + QT_END_NAMESPACE diff --git a/src/opengl/qglextensions_p.h b/src/opengl/qglextensions_p.h index 3bb42c8..4f15197 100644 --- a/src/opengl/qglextensions_p.h +++ b/src/opengl/qglextensions_p.h @@ -535,7 +535,7 @@ struct QGLExtensionFuncs #endif #ifndef GL_MAX_SAMPLES_EXT -#define GL_MAX_SAMPLES_EXT 0x8D5 +#define GL_MAX_SAMPLES_EXT 0x8D57 #endif #ifndef GL_DRAW_FRAMEBUFFER_EXT diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp index eacf5bb..3685661 100644 --- a/src/opengl/qglframebufferobject.cpp +++ b/src/opengl/qglframebufferobject.cpp @@ -109,8 +109,6 @@ public: */ /*! - \since 4.6 - Creates a QGLFramebufferObjectFormat object with properties specifying the format of an OpenGL framebuffer object. @@ -146,8 +144,6 @@ QGLFramebufferObjectFormat::QGLFramebufferObjectFormat(int samples, } /*! - \since 4.6 - Constructs a copy of \a other. */ @@ -158,8 +154,6 @@ QGLFramebufferObjectFormat::QGLFramebufferObjectFormat(const QGLFramebufferObjec } /*! - \since 4.6 - Assigns \a other to this object. */ @@ -170,8 +164,6 @@ QGLFramebufferObjectFormat &QGLFramebufferObjectFormat::operator=(const QGLFrame } /*! - \since 4.6 - Destroys the QGLFramebufferObjectFormat. */ QGLFramebufferObjectFormat::~QGLFramebufferObjectFormat() @@ -180,8 +172,6 @@ QGLFramebufferObjectFormat::~QGLFramebufferObjectFormat() } /*! - \since 4.6 - Sets the number of samples per pixel for a multisample framebuffer object to \a samples. A sample count of 0 represents a regular non-multisample framebuffer object. @@ -194,8 +184,6 @@ void QGLFramebufferObjectFormat::setSamples(int samples) } /*! - \since 4.6 - Returns the number of samples per pixel if a framebuffer object is a multisample framebuffer object. Otherwise, returns 0. @@ -207,8 +195,6 @@ int QGLFramebufferObjectFormat::samples() const } /*! - \since 4.6 - Sets the attachments a framebuffer object should have to \a attachment. \sa attachment() @@ -219,8 +205,6 @@ void QGLFramebufferObjectFormat::setAttachment(QGLFramebufferObject::Attachment } /*! - \since 4.6 - Returns the status of the depth and stencil buffers attached to a framebuffer object. @@ -232,8 +216,6 @@ QGLFramebufferObject::Attachment QGLFramebufferObjectFormat::attachment() const } /*! - \since 4.6 - Sets the texture target of the texture attached to a framebuffer object to \a target. Ignored for multisample framebuffer objects. @@ -245,8 +227,6 @@ void QGLFramebufferObjectFormat::setTextureTarget(GLenum target) } /*! - \since 4.6 - Returns the texture target of the texture attached to a framebuffer object. Ignored for multisample framebuffer objects. @@ -258,8 +238,6 @@ GLenum QGLFramebufferObjectFormat::textureTarget() const } /*! - \since 4.6 - Sets the internal format of a framebuffer object's texture or multisample framebuffer object's color buffer to \a internalFormat. @@ -271,8 +249,6 @@ void QGLFramebufferObjectFormat::setInternalFormat(GLenum internalFormat) } /*! - \since 4.6 - Returns the internal format of a framebuffer object's texture or multisample framebuffer object's color buffer. @@ -1056,8 +1032,7 @@ GLuint QGLFramebufferObject::handle() const } /*! \fn int QGLFramebufferObject::devType() const - - \reimp + \internal */ diff --git a/src/opengl/qglpixelbuffer.cpp b/src/opengl/qglpixelbuffer.cpp index 38fad4e..440694d 100644 --- a/src/opengl/qglpixelbuffer.cpp +++ b/src/opengl/qglpixelbuffer.cpp @@ -591,7 +591,7 @@ QGLFormat QGLPixelBuffer::format() const } /*! \fn int QGLPixelBuffer::devType() const - \reimp + \internal */ QT_END_NAMESPACE diff --git a/src/opengl/qglpixmapfilter.cpp b/src/opengl/qglpixmapfilter.cpp index 7514743..5a06763 100644 --- a/src/opengl/qglpixmapfilter.cpp +++ b/src/opengl/qglpixmapfilter.cpp @@ -56,7 +56,7 @@ QT_BEGIN_NAMESPACE void QGLPixmapFilterBase::bindTexture(const QPixmap &src) const { - const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(src, GL_TEXTURE_2D, GL_RGBA, true); + const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(src, GL_TEXTURE_2D, GL_RGBA, true, false); } void QGLPixmapFilterBase::drawImpl(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF& source) const diff --git a/src/opengl/qpaintengine_opengl.cpp b/src/opengl/qpaintengine_opengl.cpp index eda8d83..685d0f5 100644 --- a/src/opengl/qpaintengine_opengl.cpp +++ b/src/opengl/qpaintengine_opengl.cpp @@ -3963,7 +3963,7 @@ void QOpenGLPaintEnginePrivate::strokePath(const QPainterPath &path, bool use_ca QPen pen = cpen; if (txscale != 1) - pen.setWidthF(pen.width() * txscale); + pen.setWidthF(pen.widthF() * txscale); if (use_cache) fillPath(qt_opengl_stroke_cache()->getStrokedPath(temp.map(path), pen)); else diff --git a/src/opengl/qpixmapdata_gl.cpp b/src/opengl/qpixmapdata_gl.cpp index f0c7e20..e3ee2b2 100644 --- a/src/opengl/qpixmapdata_gl.cpp +++ b/src/opengl/qpixmapdata_gl.cpp @@ -97,7 +97,6 @@ static int qt_gl_pixmap_serial = 0; QGLPixmapData::QGLPixmapData(PixelType type) : QPixmapData(type, OpenGLClass) , m_renderFbo(0) - , m_textureId(0) , m_engine(0) , m_ctx(0) , m_dirty(false) @@ -113,9 +112,9 @@ QGLPixmapData::~QGLPixmapData() if (!shareWidget) return; - if (m_textureId) { + if (m_texture.id) { QGLShareContextScope ctx(shareWidget->context()); - glDeleteTextures(1, &m_textureId); + glDeleteTextures(1, &m_texture.id); } } @@ -148,10 +147,10 @@ void QGLPixmapData::resize(int width, int height) is_null = (w <= 0 || h <= 0); d = pixelType() == QPixmapData::PixmapType ? 32 : 1; - if (m_textureId) { + if (m_texture.id) { QGLShareContextScope ctx(qt_gl_share_widget()->context()); - glDeleteTextures(1, &m_textureId); - m_textureId = 0; + glDeleteTextures(1, &m_texture.id); + m_texture.id = 0; } m_source = QImage(); @@ -172,9 +171,9 @@ void QGLPixmapData::ensureCreated() const const GLenum format = qt_gl_preferredTextureFormat(); const GLenum target = GL_TEXTURE_2D; - if (!m_textureId) { - glGenTextures(1, &m_textureId); - glBindTexture(target, m_textureId); + if (!m_texture.id) { + glGenTextures(1, &m_texture.id); + glBindTexture(target, m_texture.id); GLenum format = m_hasAlpha ? GL_RGBA : GL_RGB; glTexImage2D(target, 0, format, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); @@ -185,13 +184,15 @@ void QGLPixmapData::ensureCreated() const if (!m_source.isNull()) { const QImage tx = ctx->d_func()->convertToGLFormat(m_source, true, format); - glBindTexture(target, m_textureId); + glBindTexture(target, m_texture.id); glTexSubImage2D(target, 0, 0, 0, w, h, format, GL_UNSIGNED_BYTE, tx.bits()); if (useFramebufferObjects()) m_source = QImage(); } + + m_texture.clean = false; } QGLFramebufferObject *QGLPixmapData::fbo() const @@ -223,10 +224,10 @@ void QGLPixmapData::fromImage(const QImage &image, is_null = (w <= 0 || h <= 0); d = pixelType() == QPixmapData::PixmapType ? 32 : 1; - if (m_textureId) { + if (m_texture.id) { QGLShareContextScope ctx(qt_gl_share_widget()->context()); - glDeleteTextures(1, &m_textureId); - m_textureId = 0; + glDeleteTextures(1, &m_texture.id); + m_texture.id = 0; } } @@ -256,9 +257,9 @@ void QGLPixmapData::fill(const QColor &color) bool hasAlpha = color.alpha() != 255; if (hasAlpha && !m_hasAlpha) { - if (m_textureId) { - glDeleteTextures(1, &m_textureId); - m_textureId = 0; + if (m_texture.id) { + glDeleteTextures(1, &m_texture.id); + m_texture.id = 0; m_dirty = true; } m_hasAlpha = color.alpha() != 255; @@ -303,6 +304,8 @@ QImage QGLPixmapData::fillImage(const QColor &color) const return img; } +extern QImage qt_gl_read_texture(const QSize &size, bool alpha_format, bool include_alpha); + QImage QGLPixmapData::toImage() const { if (!isValid()) @@ -319,8 +322,7 @@ QImage QGLPixmapData::toImage() const } QGLShareContextScope ctx(qt_gl_share_widget()->context()); - extern QImage qt_gl_read_texture(const QSize &size, bool alpha_format, bool include_alpha); - glBindTexture(GL_TEXTURE_2D, m_textureId); + glBindTexture(GL_TEXTURE_2D, m_texture.id); return qt_gl_read_texture(QSize(w, h), true, true); } @@ -350,7 +352,7 @@ void QGLPixmapData::copyBackFromRenderFbo(bool keepCurrentFboBound) const glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->fbo); glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, m_textureId, 0); + GL_TEXTURE_2D, m_texture.id, 0); const int x0 = 0; const int x1 = w; @@ -488,7 +490,7 @@ GLuint QGLPixmapData::bind(bool copyBack) const ensureCreated(); } - GLuint id = m_textureId; + GLuint id = m_texture.id; glBindTexture(GL_TEXTURE_2D, id); return id; } @@ -496,7 +498,12 @@ GLuint QGLPixmapData::bind(bool copyBack) const GLuint QGLPixmapData::textureId() const { ensureCreated(); - return m_textureId; + return m_texture.id; +} + +QGLTexture* QGLPixmapData::texture() const +{ + return &m_texture; } extern int qt_defaultDpiX(); diff --git a/src/opengl/qpixmapdata_gl_p.h b/src/opengl/qpixmapdata_gl_p.h index a6aa22d..671f9a7 100644 --- a/src/opengl/qpixmapdata_gl_p.h +++ b/src/opengl/qpixmapdata_gl_p.h @@ -53,6 +53,7 @@ // We mean it. // +#include "qgl_p.h" #include "qgl.h" #include "private/qpixmapdata_p.h" @@ -80,10 +81,11 @@ public: void fill(const QColor &color); bool hasAlphaChannel() const; QImage toImage() const; - QPaintEngine* paintEngine() const; + QPaintEngine *paintEngine() const; GLuint bind(bool copyBack = true) const; GLuint textureId() const; + QGLTexture *texture() const; bool isValidContext(const QGLContext *ctx) const; @@ -116,10 +118,10 @@ private: QImage fillImage(const QColor &color) const; mutable QGLFramebufferObject *m_renderFbo; - mutable GLuint m_textureId; mutable QPaintEngine *m_engine; mutable QGLContext *m_ctx; mutable QImage m_source; + mutable QGLTexture m_texture; // the texture is not in sync with the source image mutable bool m_dirty; diff --git a/src/plugins/accessible/compat/q3complexwidgets.cpp b/src/plugins/accessible/compat/q3complexwidgets.cpp index 696bc99..b911d5e 100644 --- a/src/plugins/accessible/compat/q3complexwidgets.cpp +++ b/src/plugins/accessible/compat/q3complexwidgets.cpp @@ -274,7 +274,7 @@ QString Q3AccessibleTitleBar::text(Text t, int child) const return Q3TitleBar::tr("Contains commands to manipulate the window"); case 3: if (window && window->isMinimized()) - return Q3TitleBar::tr("Puts a minimized back to normal"); + return Q3TitleBar::tr("Puts a minimized window back to normal"); return Q3TitleBar::tr("Moves the window out of the way"); case 4: if (window && window->isMaximized()) diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.cpp index ed59db8..b5376b1 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.cpp @@ -78,7 +78,7 @@ private: DFBEvent event; int bytesRead; -private slots: +private Q_SLOTS: void readKeyboardData(); }; diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbmouse.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbmouse.cpp index 15fb6f4..142993d 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbmouse.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbmouse.cpp @@ -71,7 +71,7 @@ private: DFBEvent event; uint bytesRead; -private slots: +private Q_SLOTS: void readMouseData(); }; @@ -101,7 +101,7 @@ QDirectFBMouseHandlerPrivate::QDirectFBMouseHandlerPrivate(QDirectFBMouseHandler #endif DFBInputDeviceCapabilities caps; - caps = DFBInputDeviceCapabilities(DICAPS_BUTTONS | DICAPS_AXES); + caps = DICAPS_BUTTONS | DICAPS_AXES; result = fb->CreateInputEventBuffer(fb, caps, DFB_TRUE, &eventBuffer); if (result != DFB_OK) { DirectFBError("QDirectFBMouseHandler: " diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.cpp index 905fec3..86e92f7 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.cpp @@ -56,20 +56,17 @@ IDirectFBSurface *QDirectFBPaintDevice::directFBSurface() const } -void QDirectFBPaintDevice::lockDirectFB(uint flags) +void QDirectFBPaintDevice::lockDirectFB(DFBSurfaceLockFlags flags) { if (!(lock & flags)) { if (lock) unlockDirectFB(); - if ((mem = QDirectFBScreen::lockSurface(dfbSurface, flags, &bpl))) { - const QSize s = size(); - lockedImage = new QImage(mem, s.width(), s.height(), bpl, - QDirectFBScreen::getImageFormat(dfbSurface)); - lock = flags; - Q_ASSERT(mem); - } else { - lock = 0; - } + mem = QDirectFBScreen::lockSurface(dfbSurface, flags, &bpl); + Q_ASSERT(mem); + const QSize s = size(); + lockedImage = new QImage(mem, s.width(), s.height(), bpl, + QDirectFBScreen::getImageFormat(dfbSurface)); + lock = flags; } } @@ -83,17 +80,12 @@ void QDirectFBPaintDevice::unlockDirectFB() delete lockedImage; lockedImage = 0; mem = 0; - lock = 0; + lock = DFBSurfaceLockFlags(0); } void *QDirectFBPaintDevice::memory() const { - if (lock != (DSLF_READ|DSLF_WRITE)) { - QDirectFBPaintDevice *that = const_cast<QDirectFBPaintDevice*>(this); - that->lockDirectFB(DSLF_READ|DSLF_WRITE); - Q_ASSERT(that->lockedImage); - } return mem; } diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.h b/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.h index 32c49bb..248a15b 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.h +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.h @@ -51,14 +51,14 @@ QT_BEGIN_HEADER QT_MODULE(Gui) // Inherited by both window surface and pixmap -class QDirectFBPaintDevice : public QCustomRasterPaintDevice + class QDirectFBPaintDevice : public QCustomRasterPaintDevice { public: ~QDirectFBPaintDevice(); IDirectFBSurface *directFBSurface() const; - void lockDirectFB(uint flags); + void lockDirectFB(DFBSurfaceLockFlags lock); void unlockDirectFB(); // Reimplemented from QCustomRasterPaintDevice: @@ -67,16 +67,12 @@ public: int bytesPerLine() const; QSize size() const; int metric(QPaintDevice::PaintDeviceMetric metric) const; - uint lockFlags() const { return lock; } + DFBSurfaceLockFlags lockFlags() const { return lock; } protected: // Shouldn't create QDirectFBPaintDevice by itself but only sub-class it: QDirectFBPaintDevice(QDirectFBScreen *scr = QDirectFBScreen::instance()) - : QCustomRasterPaintDevice(0), - dfbSurface(0), - lockedImage(0), - screen(scr), - lock(0), - mem(0) + : QCustomRasterPaintDevice(0), dfbSurface(0), lockedImage(0), screen(scr), + lock(DFBSurfaceLockFlags(0)), mem(0) {} inline int dotsPerMeterX() const @@ -92,11 +88,11 @@ protected: QImage *lockedImage; QDirectFBScreen *screen; int bpl; - uint lock; + DFBSurfaceLockFlags lock; uchar *mem; private: Q_DISABLE_COPY(QDirectFBPaintDevice) -}; + }; QT_END_HEADER diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp index 4928b67..94f1aeb 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp @@ -54,173 +54,22 @@ #include <private/qpixmapdata_p.h> #include <private/qpixmap_raster_p.h> -#if defined QT_DIRECTFB_WARN_ON_RASTERFALLBACKS || defined QT_DIRECTFB_DISABLE_RASTERFALLBACKS -#define VOID_ARG() static_cast<bool>(false) -enum PaintOperation { - DRAW_RECTS = 0x0001, - DRAW_LINES = 0x0002, - DRAW_IMAGE = 0x0004, - DRAW_PIXMAP = 0x0008, - DRAW_TILED_PIXMAP = 0x0010, - STROKE_PATH = 0x0020, - DRAW_PATH = 0x0040, - DRAW_POINTS = 0x0080, - DRAW_ELLIPSE = 0x0100, - DRAW_POLYGON = 0x0200, - DRAW_TEXT = 0x0400, - FILL_PATH = 0x0800, - FILL_RECT = 0x1000, - DRAW_COLORSPANS = 0x2000, - ALL = 0xffff -}; -#endif - -#ifdef QT_DIRECTFB_WARN_ON_RASTERFALLBACKS -template <typename T> inline const T *ptr(const T &t) { return &t; } -template <> inline const bool* ptr<bool>(const bool &) { return 0; } -template <typename device, typename T1, typename T2, typename T3> -static void rasterFallbackWarn(const char *msg, const char *func, const device *dev, - int scale, bool matrixRotShear, bool simplePen, - bool dfbHandledClip, bool unsupportedCompositionMode, - const char *nameOne, const T1 &one, - const char *nameTwo, const T2 &two, - const char *nameThree, const T3 &three) -{ - QString out; - QDebug dbg(&out); - dbg << msg << (QByteArray(func) + "()") << "painting on"; - if (dev->devType() == QInternal::Widget) { - dbg << static_cast<const QWidget*>(dev); - } else { - dbg << dev << "of type" << dev->devType(); - } - - dbg << "scale" << scale - << "matrixRotShear" << matrixRotShear - << "simplePen" << simplePen - << "dfbHandledClip" << dfbHandledClip - << "unsupportedCompositionMode" << unsupportedCompositionMode; - - const T1 *t1 = ptr(one); - const T2 *t2 = ptr(two); - const T3 *t3 = ptr(three); - - if (t1) { - dbg << nameOne << *t1; - if (t2) { - dbg << nameTwo << *t2; - if (t3) { - dbg << nameThree << *t3; - } - } - } - qWarning("%s", qPrintable(out)); -} -#endif - -#if defined QT_DIRECTFB_WARN_ON_RASTERFALLBACKS && defined QT_DIRECTFB_DISABLE_RASTERFALLBACKS -#define RASTERFALLBACK(op, one, two, three) \ - if (op & (QT_DIRECTFB_WARN_ON_RASTERFALLBACKS)) \ - rasterFallbackWarn("Disabled raster engine operation", \ - __FUNCTION__, state()->painter->device(), \ - d_func()->scale, d_func()->matrixRotShear, \ - d_func()->simplePen, d_func()->dfbCanHandleClip(), \ - d_func()->unsupportedCompositionMode, \ - #one, one, #two, two, #three, three); \ - if (op & (QT_DIRECTFB_DISABLE_RASTERFALLBACKS)) \ - return; -#elif defined QT_DIRECTFB_DISABLE_RASTERFALLBACKS -#define RASTERFALLBACK(op, one, two, three) \ - if (op & (QT_DIRECTFB_DISABLE_RASTERFALLBACKS)) \ - return; -#elif defined QT_DIRECTFB_WARN_ON_RASTERFALLBACKS -#define RASTERFALLBACK(op, one, two, three) \ - if (op & (QT_DIRECTFB_WARN_ON_RASTERFALLBACKS)) \ - rasterFallbackWarn("Falling back to raster engine for", \ - __FUNCTION__, state()->painter->device(), \ - d_func()->scale, d_func()->matrixRotShear, \ - d_func()->simplePen, d_func()->dfbCanHandleClip(), \ - d_func()->unsupportedCompositionMode, \ - #one, one, #two, two, #three, three); -#else -#define RASTERFALLBACK(op, one, two, three) -#endif - -static inline uint ALPHA_MUL(uint x, uint a) -{ - uint t = x * a; - t = ((t + (t >> 8) + 0x80) >> 8) & 0xff; - return t; -} - -class SurfaceCache -{ -public: - SurfaceCache() : surface(0), buffer(0), bufsize(0) {} - ~SurfaceCache() { clear(); } - - - IDirectFBSurface *getSurface(const uint *buf, int size) - { - if (buffer == buf && bufsize == size) - return surface; - - clear(); - - const DFBSurfaceDescription description = QDirectFBScreen::getSurfaceDescription(buf, size); - surface = QDirectFBScreen::instance()->createDFBSurface(description, QDirectFBScreen::TrackSurface); - if (!surface) - qWarning("QDirectFBPaintEngine: SurfaceCache: Unable to create surface"); - - buffer = const_cast<uint*>(buf); - bufsize = size; - - return surface; - } - - void clear() - { - if (surface && QDirectFBScreen::instance()) - QDirectFBScreen::instance()->releaseDFBSurface(surface); - surface = 0; - buffer = 0; - bufsize = 0; - } -private: - IDirectFBSurface *surface; - uint *buffer; - int bufsize; -}; - - -#ifdef QT_DIRECTFB_IMAGECACHE -#include <private/qimage_p.h> -struct CachedImage -{ - IDirectFBSurface *surface; - ~CachedImage() - { - if (surface && QDirectFBScreen::instance()) { - QDirectFBScreen::instance()->releaseDFBSurface(surface); - } - } -}; -static QCache<qint64, CachedImage> imageCache(4*1024*1024); // 4 MB -#endif - +class SurfaceCache; class QDirectFBPaintEnginePrivate : public QRasterPaintEnginePrivate { public: - enum Scale { NoScale, Scaled, NegativeScale }; - + enum TransformationTypeFlags { + NegativeScale = 0x100, + RectsUnsupported = (QTransform::TxRotate|QTransform::TxShear|QTransform::TxProject), + BlitUnsupported = (NegativeScale|RectsUnsupported) + }; QDirectFBPaintEnginePrivate(QDirectFBPaintEngine *p); ~QDirectFBPaintEnginePrivate(); - void setTransform(const QTransform &m); - void setPen(const QPen &pen); + inline void setTransform(const QTransform &transforma); + inline void setPen(const QPen &pen); inline void setCompositionMode(QPainter::CompositionMode mode); - inline void setOpacity(quint8 value); - void setRenderHints(QPainter::RenderHints hints); + inline void setRenderHints(QPainter::RenderHints hints); inline void setDFBColor(const QColor &color); @@ -232,20 +81,11 @@ public: inline bool dfbCanHandleClip() const; inline bool isSimpleBrush(const QBrush &brush) const; - void drawLines(const QLine *lines, int count); - void drawLines(const QLineF *lines, int count); - - void fillRegion(const QRegion &r); - void fillRects(const QRect *rects, int count); - void drawRects(const QRect *rects, int count); - void fillRects(const QRectF *rects, int count); - void drawRects(const QRectF *rects, int count); - void drawTiledPixmap(const QRectF &dest, const QPixmap &pixmap, const QPointF &pos); void blit(const QRectF &dest, IDirectFBSurface *surface, const QRectF &src); inline void updateClip(); - void systemStateChanged(); + virtual void systemStateChanged(); static IDirectFBSurface *getSurface(const QImage &img, bool *release); @@ -257,22 +97,14 @@ public: private: IDirectFBSurface *surface; - QPen pen; - bool antialiased; - bool simplePen; - bool matrixRotShear; - Scale scale; + uint transformationType; // this is QTransform::type() + NegativeScale if qMin(transform.m11(), transform.m22()) < 0 SurfaceCache *surfaceCache; - QTransform transform; - int lastLockedHeight; IDirectFB *fb; - int fbWidth; - int fbHeight; quint8 opacity; @@ -280,7 +112,6 @@ private: bool dfbHandledClip; bool ignoreSystemClip; QDirectFBPaintDevice *dfbDevice; - void *lockedMemory; bool unsupportedCompositionMode; QDirectFBPaintEngine *q; @@ -288,6 +119,90 @@ private: friend class QDirectFBPaintEngine; }; +class SurfaceCache +{ +public: + SurfaceCache() : surface(0), buffer(0), bufsize(0) {} + ~SurfaceCache() { clear(); } + IDirectFBSurface *getSurface(const uint *buf, int size); + void clear(); +private: + IDirectFBSurface *surface; + uint *buffer; + int bufsize; +}; + + +#ifdef QT_DIRECTFB_IMAGECACHE +#include <private/qimage_p.h> +struct CachedImage +{ + IDirectFBSurface *surface; + ~CachedImage() + { + if (surface && QDirectFBScreen::instance()) { + QDirectFBScreen::instance()->releaseDFBSurface(surface); + } + } +}; +static QCache<qint64, CachedImage> imageCache(4*1024*1024); // 4 MB +#endif + +#if defined QT_DIRECTFB_WARN_ON_RASTERFALLBACKS || defined QT_DIRECTFB_DISABLE_RASTERFALLBACKS +#define VOID_ARG() static_cast<bool>(false) +enum PaintOperation { + DRAW_RECTS = 0x0001, DRAW_LINES = 0x0002, DRAW_IMAGE = 0x0004, + DRAW_PIXMAP = 0x0008, DRAW_TILED_PIXMAP = 0x0010, STROKE_PATH = 0x0020, + DRAW_PATH = 0x0040, DRAW_POINTS = 0x0080, DRAW_ELLIPSE = 0x0100, + DRAW_POLYGON = 0x0200, DRAW_TEXT = 0x0400, FILL_PATH = 0x0800, + FILL_RECT = 0x1000, DRAW_COLORSPANS = 0x2000, ALL = 0xffff +}; +#endif + +#ifdef QT_DIRECTFB_WARN_ON_RASTERFALLBACKS +template <typename device, typename T1, typename T2, typename T3> +static void rasterFallbackWarn(const char *msg, const char *, const device *, uint, bool, bool, bool, + const char *, const T1 &, const char *, const T2 &, const char *, const T3 &); +#endif + +#if defined QT_DIRECTFB_WARN_ON_RASTERFALLBACKS && defined QT_DIRECTFB_DISABLE_RASTERFALLBACKS +#define RASTERFALLBACK(op, one, two, three) \ + if (op & (QT_DIRECTFB_WARN_ON_RASTERFALLBACKS)) \ + rasterFallbackWarn("Disabled raster engine operation", \ + __FUNCTION__, state()->painter->device(), \ + d_func()->transformationType, \ + d_func()->simplePen, \ + d_func()->dfbCanHandleClip(), \ + d_func()->unsupportedCompositionMode, \ + #one, one, #two, two, #three, three); \ + if (op & (QT_DIRECTFB_DISABLE_RASTERFALLBACKS)) \ + return; +#elif defined QT_DIRECTFB_DISABLE_RASTERFALLBACKS +#define RASTERFALLBACK(op, one, two, three) \ + if (op & (QT_DIRECTFB_DISABLE_RASTERFALLBACKS)) \ + return; +#elif defined QT_DIRECTFB_WARN_ON_RASTERFALLBACKS +#define RASTERFALLBACK(op, one, two, three) \ + if (op & (QT_DIRECTFB_WARN_ON_RASTERFALLBACKS)) \ + rasterFallbackWarn("Falling back to raster engine for", \ + __FUNCTION__, state()->painter->device(), \ + d_func()->transformationType, \ + d_func()->simplePen, \ + d_func()->dfbCanHandleClip(), \ + d_func()->unsupportedCompositionMode, \ + #one, one, #two, two, #three, three); +#else +#define RASTERFALLBACK(op, one, two, three) +#endif + + +template <class T> +static inline void drawLines(const T *lines, int n, const QTransform &transform, IDirectFBSurface *surface); +template <class T> +static inline void fillRects(const T *rects, int n, const QTransform &transform, IDirectFBSurface *surface); +template <class T> +static inline void drawRects(const T *rects, int n, const QTransform &transform, IDirectFBSurface *surface); + QDirectFBPaintEngine::QDirectFBPaintEngine(QPaintDevice *device) : QRasterPaintEngine(*(new QDirectFBPaintEnginePrivate(this)), device) { @@ -300,7 +215,6 @@ QDirectFBPaintEngine::~QDirectFBPaintEngine() bool QDirectFBPaintEngine::begin(QPaintDevice *device) { Q_D(QDirectFBPaintEngine); - d->lastLockedHeight = -1; if (device->devType() == QInternal::CustomRaster) { d->dfbDevice = static_cast<QDirectFBPaintDevice*>(device); } else if (device->devType() == QInternal::Pixmap) { @@ -317,23 +231,10 @@ bool QDirectFBPaintEngine::begin(QPaintDevice *device) qFatal("QDirectFBPaintEngine used on an invalid device: 0x%x", device->devType()); } - d->lockedMemory = 0; - - d->surface->GetSize(d->surface, &d->fbWidth, &d->fbHeight); - - d->setTransform(QTransform()); - d->antialiased = false; - d->setOpacity(255); - d->setCompositionMode(state()->compositionMode()); - d->dirtyClip = true; - d->setPen(state()->pen); - - const bool status = QRasterPaintEngine::begin(device); - // XXX: QRasterPaintEngine::begin() resets the capabilities - gccaps |= PorterDuff; + d->prepare(d->dfbDevice); - return status; + return QRasterPaintEngine::begin(device); } bool QDirectFBPaintEngine::end() @@ -368,7 +269,7 @@ void QDirectFBPaintEngine::penChanged() void QDirectFBPaintEngine::opacityChanged() { Q_D(QDirectFBPaintEngine); - d->setOpacity(quint8(state()->opacity * 255)); + d->opacity = quint8(state()->opacity * 255); QRasterPaintEngine::opacityChanged(); } @@ -389,32 +290,26 @@ void QDirectFBPaintEngine::renderHintsChanged() void QDirectFBPaintEngine::transformChanged() { Q_D(QDirectFBPaintEngine); - const QDirectFBPaintEnginePrivate::Scale old = d->scale; - d->setTransform(state()->transform()); - if (d->scale != old) { - d->setPen(state()->pen); - } + d->setTransform(state()->matrix); QRasterPaintEngine::transformChanged(); } -void QDirectFBPaintEngine::setState(QPainterState *s) +void QDirectFBPaintEngine::setState(QPainterState *state) { Q_D(QDirectFBPaintEngine); - QRasterPaintEngine::setState(s); + QRasterPaintEngine::setState(state); d->dirtyClip = true; - d->setPen(state()->pen); - d->setOpacity(quint8(state()->opacity * 255)); - d->setCompositionMode(state()->compositionMode()); - d->setTransform(state()->transform()); + d->setPen(state->pen); + d->opacity = quint8(state->opacity * 255); + d->setCompositionMode(state->compositionMode()); + d->setTransform(state->transform()); + d->setRenderHints(state->renderHints); } void QDirectFBPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op) { Q_D(QDirectFBPaintEngine); d->dirtyClip = true; - const QPoint bottom = d->transform.map(QPoint(0, int(path.controlPointRect().bottom()))); - if (bottom.y() > d->lastLockedHeight) - d->lock(); QRasterPaintEngine::clip(path, op); } @@ -422,12 +317,6 @@ void QDirectFBPaintEngine::clip(const QRect &rect, Qt::ClipOperation op) { Q_D(QDirectFBPaintEngine); d->dirtyClip = true; - if (d->clip() && !d->clip()->hasRectClip && d->clip()->enabled) { - const QPoint bottom = d->transform.map(QPoint(0, rect.bottom())); - if (bottom.y() > d->lastLockedHeight) - d->lock(); - } - QRasterPaintEngine::clip(rect, op); } @@ -436,8 +325,11 @@ void QDirectFBPaintEngine::drawRects(const QRect *rects, int rectCount) Q_D(QDirectFBPaintEngine); d->updateClip(); const QBrush &brush = state()->brush; - if (d->unsupportedCompositionMode || !d->dfbCanHandleClip() || d->matrixRotShear - || !d->simplePen || !d->isSimpleBrush(brush)) { + if (d->unsupportedCompositionMode + || (d->transformationType & QDirectFBPaintEnginePrivate::RectsUnsupported) + || !d->simplePen + || !d->dfbCanHandleClip() + || !d->isSimpleBrush(brush)) { RASTERFALLBACK(DRAW_RECTS, rectCount, VOID_ARG(), VOID_ARG()); d->lock(); QRasterPaintEngine::drawRects(rects, rectCount); @@ -448,11 +340,12 @@ void QDirectFBPaintEngine::drawRects(const QRect *rects, int rectCount) if (brush != Qt::NoBrush) { d->setDFBColor(brush.color()); - d->fillRects(rects, rectCount); + ::fillRects<QRect>(rects, rectCount, state()->matrix, d->surface); } - if (d->pen != Qt::NoPen) { - d->setDFBColor(d->pen.color()); - d->drawRects(rects, rectCount); + const QPen &pen = state()->pen; + if (pen != Qt::NoPen) { + d->setDFBColor(pen.color()); + ::drawRects<QRect>(rects, rectCount, state()->matrix, d->surface); } } @@ -461,8 +354,11 @@ void QDirectFBPaintEngine::drawRects(const QRectF *rects, int rectCount) Q_D(QDirectFBPaintEngine); d->updateClip(); const QBrush &brush = state()->brush; - if (d->unsupportedCompositionMode || !d->dfbCanHandleClip() || d->matrixRotShear - || !d->simplePen || !d->isSimpleBrush(brush)) { + if (d->unsupportedCompositionMode + || (d->transformationType & QDirectFBPaintEnginePrivate::RectsUnsupported) + || !d->simplePen + || !d->dfbCanHandleClip() + || !d->isSimpleBrush(brush)) { RASTERFALLBACK(DRAW_RECTS, rectCount, VOID_ARG(), VOID_ARG()); d->lock(); QRasterPaintEngine::drawRects(rects, rectCount); @@ -473,11 +369,12 @@ void QDirectFBPaintEngine::drawRects(const QRectF *rects, int rectCount) if (brush != Qt::NoBrush) { d->setDFBColor(brush.color()); - d->fillRects(rects, rectCount); + ::fillRects<QRectF>(rects, rectCount, state()->matrix, d->surface); } - if (d->pen != Qt::NoPen) { - d->setDFBColor(d->pen.color()); - d->drawRects(rects, rectCount); + const QPen &pen = state()->pen; + if (pen != Qt::NoPen) { + d->setDFBColor(pen.color()); + ::drawRects<QRectF>(rects, rectCount, state()->matrix, d->surface); } } @@ -492,10 +389,11 @@ void QDirectFBPaintEngine::drawLines(const QLine *lines, int lineCount) return; } - if (d->pen != Qt::NoPen) { + const QPen &pen = state()->pen; + if (pen != Qt::NoPen) { d->unlock(); - d->setDFBColor(d->pen.color()); - d->drawLines(lines, lineCount); + d->setDFBColor(pen.color()); + ::drawLines<QLine>(lines, lineCount, state()->matrix, d->surface); } } @@ -510,10 +408,11 @@ void QDirectFBPaintEngine::drawLines(const QLineF *lines, int lineCount) return; } - if (d->pen != Qt::NoPen) { + const QPen &pen = state()->pen; + if (pen != Qt::NoPen) { d->unlock(); - d->setDFBColor(d->pen.color()); - d->drawLines(lines, lineCount); + d->setDFBColor(pen.color()); + ::drawLines<QLineF>(lines, lineCount, state()->matrix, d->surface); } } @@ -544,8 +443,7 @@ void QDirectFBPaintEngine::drawImage(const QRectF &r, const QImage &image, d->updateClip(); #if !defined QT_NO_DIRECTFB_PREALLOCATED || defined QT_DIRECTFB_IMAGECACHE if (d->unsupportedCompositionMode - || d->matrixRotShear - || d->scale == QDirectFBPaintEnginePrivate::NegativeScale + || (d->transformationType & QDirectFBPaintEnginePrivate::BlitUnsupported) || !d->dfbCanHandleClip(r) #ifndef QT_DIRECTFB_IMAGECACHE || QDirectFBScreen::getSurfacePixelFormat(image.format()) == DSPF_UNKNOWN @@ -590,8 +488,9 @@ void QDirectFBPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap, RASTERFALLBACK(DRAW_PIXMAP, r, pixmap.size(), sr); d->lock(); QRasterPaintEngine::drawPixmap(r, pixmap, sr); - } else if (d->unsupportedCompositionMode || !d->dfbCanHandleClip(r) || d->matrixRotShear - || d->scale == QDirectFBPaintEnginePrivate::NegativeScale) { + } else if (d->unsupportedCompositionMode + || (d->transformationType & QDirectFBPaintEnginePrivate::BlitUnsupported) + || !d->dfbCanHandleClip(r)) { RASTERFALLBACK(DRAW_PIXMAP, r, pixmap.size(), sr); const QImage *img = static_cast<QDirectFBPixmapData*>(pixmap.pixmapData())->buffer(DSLF_READ); d->lock(); @@ -623,8 +522,9 @@ void QDirectFBPaintEngine::drawTiledPixmap(const QRectF &r, RASTERFALLBACK(DRAW_TILED_PIXMAP, r, pixmap.size(), offset); d->lock(); QRasterPaintEngine::drawTiledPixmap(r, pixmap, offset); - } else if (d->unsupportedCompositionMode || !d->dfbCanHandleClip(r) || d->matrixRotShear - || d->scale == QDirectFBPaintEnginePrivate::NegativeScale) { + } else if (d->unsupportedCompositionMode + || (d->transformationType & QDirectFBPaintEnginePrivate::BlitUnsupported) + || !d->dfbCanHandleClip(r)) { RASTERFALLBACK(DRAW_TILED_PIXMAP, r, pixmap.size(), offset); const QImage *img = static_cast<QDirectFBPixmapData*>(pixmap.pixmapData())->buffer(DSLF_READ); d->lock(); @@ -719,7 +619,9 @@ void QDirectFBPaintEngine::fillRect(const QRectF &rect, const QBrush &brush) { Q_D(QDirectFBPaintEngine); d->updateClip(); - if (!d->unsupportedCompositionMode && d->dfbCanHandleClip(rect) && !d->matrixRotShear) { + if (!d->unsupportedCompositionMode + && !(d->transformationType & (QDirectFBPaintEnginePrivate::RectsUnsupported)) + && d->dfbCanHandleClip(rect)) { switch (brush.style()) { case Qt::SolidPattern: { const QColor color = brush.color(); @@ -727,12 +629,12 @@ void QDirectFBPaintEngine::fillRect(const QRectF &rect, const QBrush &brush) return; d->unlock(); d->setDFBColor(color); - const QRect r = d->transform.mapRect(rect).toRect(); + const QRect r = state()->matrix.mapRect(rect).toRect(); d->surface->FillRectangle(d->surface, r.x(), r.y(), r.width(), r.height()); return; } case Qt::TexturePattern: { - if (d->scale == QDirectFBPaintEnginePrivate::NegativeScale) + if (d->transformationType & QDirectFBPaintEnginePrivate::NegativeScale) break; const QPixmap texture = brush.texture(); @@ -757,51 +659,21 @@ void QDirectFBPaintEngine::fillRect(const QRectF &rect, const QColor &color) return; Q_D(QDirectFBPaintEngine); d->updateClip(); - if (d->unsupportedCompositionMode || !d->dfbCanHandleClip() || d->matrixRotShear) { + if (d->unsupportedCompositionMode + || (d->transformationType & QDirectFBPaintEnginePrivate::RectsUnsupported) + || !d->dfbCanHandleClip()) { RASTERFALLBACK(FILL_RECT, rect, color, VOID_ARG()); d->lock(); QRasterPaintEngine::fillRect(rect, color); } else { d->unlock(); d->setDFBColor(color); - const QRect r = d->transform.mapRect(rect).toRect(); + const QRect r = state()->matrix.mapRect(rect).toRect(); d->surface->FillRectangle(d->surface, r.x(), r.y(), r.width(), r.height()); } } -void QDirectFBPaintEngine::drawColorSpans(const QSpan *spans, int count, - uint color) -{ - Q_D(QDirectFBPaintEngine); - color = INV_PREMUL(color); - - QVarLengthArray<DFBRegion> lines(count); - int j = 0; - for (int i = 0; i < count; ++i) { - if (spans[i].coverage == 255) { - lines[j].x1 = spans[i].x; - lines[j].y1 = spans[i].y; - lines[j].x2 = spans[i].x + spans[i].len - 1; - lines[j].y2 = spans[i].y; - ++j; - } else { - DFBSpan span = { spans[i].x, spans[i].len }; - uint c = BYTE_MUL(color, spans[i].coverage); - // ### how does this play with setDFBColor - d->surface->SetColor(d->surface, - qRed(c), qGreen(c), qBlue(c), qAlpha(c)); - d->surface->FillSpans(d->surface, spans[i].y, &span, 1); - } - } - if (j > 0) { - d->surface->SetColor(d->surface, - qRed(color), qGreen(color), qBlue(color), - qAlpha(color)); - d->surface->DrawLines(d->surface, lines.data(), j); - } -} - void QDirectFBPaintEngine::drawBufferSpan(const uint *buffer, int bufsize, int x, int y, int length, uint const_alpha) @@ -835,9 +707,8 @@ void QDirectFBPaintEngine::initImageCache(int size) QDirectFBPaintEnginePrivate::QDirectFBPaintEnginePrivate(QDirectFBPaintEngine *p) : surface(0), antialiased(false), simplePen(false), - matrixRotShear(false), scale(NoScale), lastLockedHeight(-1), - fbWidth(-1), fbHeight(-1), opacity(255), dirtyClip(true), - dfbHandledClip(false), dfbDevice(0), lockedMemory(0), + transformationType(0), opacity(255), dirtyClip(true), + dfbHandledClip(false), dfbDevice(0), unsupportedCompositionMode(false), q(p) { fb = QDirectFBScreen::instance()->dfb(); @@ -878,12 +749,9 @@ void QDirectFBPaintEnginePrivate::lock() // lock so we need to call the base implementation of prepare so // it updates its rasterBuffer to point to the new buffer address. Q_ASSERT(dfbDevice); - if (dfbDevice->lockFlags() != (DSLF_WRITE|DSLF_READ) - || dfbDevice->height() != lastLockedHeight - || dfbDevice->memory() != lockedMemory) { + if (dfbDevice->lockFlags() != (DSLF_WRITE|DSLF_READ)) { + dfbDevice->lockDirectFB(DSLF_READ|DSLF_WRITE); prepare(dfbDevice); - lastLockedHeight = dfbDevice->height(); - lockedMemory = dfbDevice->memory(); } } @@ -891,32 +759,26 @@ void QDirectFBPaintEnginePrivate::unlock() { Q_ASSERT(dfbDevice); dfbDevice->unlockDirectFB(); - lockedMemory = 0; } -void QDirectFBPaintEnginePrivate::setTransform(const QTransform &m) +void QDirectFBPaintEnginePrivate::setTransform(const QTransform &transform) { - transform = m; - matrixRotShear = (transform.m12() != 0 || transform.m21() != 0); + transformationType = transform.type(); if (qMin(transform.m11(), transform.m22()) < 0) { - scale = NegativeScale; - } else if (transform.m11() != 1 || transform.m22() != 1) { - scale = Scaled; - } else { - scale = NoScale; + transformationType |= QDirectFBPaintEnginePrivate::NegativeScale; } + setPen(q->state()->pen); } -void QDirectFBPaintEnginePrivate::setPen(const QPen &p) +void QDirectFBPaintEnginePrivate::setPen(const QPen &pen) { - pen = p; if (pen.style() == Qt::NoPen) { simplePen = true; } else if (pen.style() == Qt::SolidLine && !antialiased && pen.brush().style() == Qt::SolidPattern && pen.widthF() <= 1.0 - && (scale == NoScale || pen.isCosmetic())) { + && (transformationType < QTransform::TxScale || pen.isCosmetic())) { simplePen = true; } else { simplePen = false; @@ -928,12 +790,6 @@ void QDirectFBPaintEnginePrivate::setCompositionMode(QPainter::CompositionMode m unsupportedCompositionMode = (mode != QPainter::CompositionMode_SourceOver); } - -void QDirectFBPaintEnginePrivate::setOpacity(quint8 op) -{ - opacity = op; -} - void QDirectFBPaintEnginePrivate::setRenderHints(QPainter::RenderHints hints) { const bool old = antialiased; @@ -953,6 +809,13 @@ void QDirectFBPaintEnginePrivate::prepareForBlit(bool alpha) surface->SetBlittingFlags(surface, DFBSurfaceBlittingFlags(blittingFlags)); } +static inline uint ALPHA_MUL(uint x, uint a) +{ + uint t = x * a; + t = ((t + (t >> 8) + 0x80) >> 8) & 0xff; + return t; +} + void QDirectFBPaintEnginePrivate::setDFBColor(const QColor &color) { Q_ASSERT(surface); @@ -963,67 +826,6 @@ void QDirectFBPaintEnginePrivate::setDFBColor(const QColor &color) surface->SetDrawingFlags(surface, alpha == 255 ? DSDRAW_NOFX : DSDRAW_BLEND); } -void QDirectFBPaintEnginePrivate::drawLines(const QLine *lines, int n) -{ - for (int i = 0; i < n; ++i) { - const QLine l = transform.map(lines[i]); - surface->DrawLine(surface, l.x1(), l.y1(), l.x2(), l.y2()); - } -} - -void QDirectFBPaintEnginePrivate::drawLines(const QLineF *lines, int n) -{ - for (int i = 0; i < n; ++i) { - const QLine l = transform.map(lines[i]).toLine(); - surface->DrawLine(surface, l.x1(), l.y1(), l.x2(), l.y2()); - } -} - -void QDirectFBPaintEnginePrivate::fillRegion(const QRegion ®ion) -{ - Q_ASSERT(isSimpleBrush(q->state()->brush)); - setDFBColor(q->state()->brush.color()); - const QVector<QRect> rects = region.rects(); - const int n = rects.size(); - fillRects(rects.constData(), n); -} - -void QDirectFBPaintEnginePrivate::fillRects(const QRect *rects, int n) -{ - for (int i = 0; i < n; ++i) { - const QRect r = transform.mapRect(rects[i]); - surface->FillRectangle(surface, r.x(), r.y(), - r.width(), r.height()); - } -} - -void QDirectFBPaintEnginePrivate::fillRects(const QRectF *rects, int n) -{ - for (int i = 0; i < n; ++i) { - const QRect r = transform.mapRect(rects[i]).toRect(); - surface->FillRectangle(surface, r.x(), r.y(), - r.width(), r.height()); - } -} - -void QDirectFBPaintEnginePrivate::drawRects(const QRect *rects, int n) -{ - for (int i = 0; i < n; ++i) { - const QRect r = transform.mapRect(rects[i]); - surface->DrawRectangle(surface, r.x(), r.y(), - r.width() + 1, r.height() + 1); - } -} - -void QDirectFBPaintEnginePrivate::drawRects(const QRectF *rects, int n) -{ - for (int i = 0; i < n; ++i) { - const QRect r = transform.mapRect(rects[i]).toRect(); - surface->DrawRectangle(surface, r.x(), r.y(), - r.width() + 1, r.height() + 1); - } -} - IDirectFBSurface *QDirectFBPaintEnginePrivate::getSurface(const QImage &img, bool *release) { #ifndef QT_DIRECTFB_IMAGECACHE @@ -1062,7 +864,7 @@ IDirectFBSurface *QDirectFBPaintEnginePrivate::getSurface(const QImage &img, boo void QDirectFBPaintEnginePrivate::blit(const QRectF &dest, IDirectFBSurface *s, const QRectF &src) { const QRect sr = src.toRect(); - const QRect dr = transform.mapRect(dest).toRect(); + const QRect dr = q->state()->matrix.mapRect(dest).toRect(); if (dr.isEmpty()) return; const DFBRectangle sRect = { sr.x(), sr.y(), sr.width(), sr.height() }; @@ -1091,6 +893,8 @@ static inline qreal fixCoord(qreal rect_pos, qreal pixmapSize, qreal offset) void QDirectFBPaintEnginePrivate::drawTiledPixmap(const QRectF &dest, const QPixmap &pixmap, const QPointF &off) { Q_ASSERT(!dirtyClip); + Q_ASSERT(!(transformationType & BlitUnsupported)); + const QTransform &transform = q->state()->matrix; const QRect destinationRect = transform.mapRect(dest).toRect().normalized(); QRect newClip = destinationRect; if (!currentClip.isEmpty()) @@ -1124,9 +928,9 @@ void QDirectFBPaintEnginePrivate::drawTiledPixmap(const QRectF &dest, const QPix const QSizeF mappedSize(pixmapSize.width() * transform.m11(), pixmapSize.height() * transform.m22()); qreal y = ::fixCoord(destinationRect.y(), mappedSize.height(), offset.y()); const qreal startX = ::fixCoord(destinationRect.x(), mappedSize.width(), offset.x()); - while (y < destinationRect.bottom()) { + while (y <= destinationRect.bottom()) { qreal x = startX; - while (x < destinationRect.right()) { + while (x <= destinationRect.right()) { const DFBRectangle destination = { qRound(x), qRound(y), mappedSize.width(), mappedSize.height() }; surface->StretchBlit(surface, sourceSurface, 0, &destination); x += mappedSize.width(); @@ -1148,10 +952,10 @@ void QDirectFBPaintEnginePrivate::drawTiledPixmap(const QRectF &dest, const QPix QVarLengthArray<DFBPoint, 16> points(maxCount); int i = 0; - while (y < destinationRect.bottom()) { + while (y <= destinationRect.bottom()) { Q_ASSERT(i < maxCount); qreal x = startX; - while (x < destinationRect.right()) { + while (x <= destinationRect.right()) { points[i].x = qRound(x); points[i].y = qRound(y); sourceRects[i].x = 0; @@ -1215,4 +1019,126 @@ void QDirectFBPaintEnginePrivate::systemStateChanged() QRasterPaintEnginePrivate::systemStateChanged(); } +IDirectFBSurface *SurfaceCache::getSurface(const uint *buf, int size) +{ + if (buffer == buf && bufsize == size) + return surface; + + clear(); + + const DFBSurfaceDescription description = QDirectFBScreen::getSurfaceDescription(buf, size); + surface = QDirectFBScreen::instance()->createDFBSurface(description, QDirectFBScreen::TrackSurface); + if (!surface) + qWarning("QDirectFBPaintEngine: SurfaceCache: Unable to create surface"); + + buffer = const_cast<uint*>(buf); + bufsize = size; + + return surface; +} + +void SurfaceCache::clear() +{ + if (surface && QDirectFBScreen::instance()) + QDirectFBScreen::instance()->releaseDFBSurface(surface); + surface = 0; + buffer = 0; + bufsize = 0; +} + + +static inline QRect mapRect(const QTransform &transform, const QRect &rect) { return transform.mapRect(rect); } +static inline QRect mapRect(const QTransform &transform, const QRectF &rect) { return transform.mapRect(rect).toRect(); } +static inline QLine map(const QTransform &transform, const QLine &line) { return transform.map(line); } +static inline QLine map(const QTransform &transform, const QLineF &line) { return transform.map(line).toLine(); } +template <class T> +static inline void drawLines(const T *lines, int n, const QTransform &transform, IDirectFBSurface *surface) +{ + if (n == 1) { + const QLine l = ::map(transform, lines[0]); + surface->DrawLine(surface, l.x1(), l.y1(), l.x2(), l.y2()); + } else { + QVarLengthArray<DFBRegion, 32> lineArray(n); + for (int i=0; i<n; ++i) { + const QLine l = ::map(transform, lines[i]); + lineArray[i].x1 = l.x1(); + lineArray[i].y1 = l.y1(); + lineArray[i].x2 = l.x2(); + lineArray[i].y2 = l.y2(); + } + surface->DrawLines(surface, lineArray.constData(), n); + } +} + +template <class T> +static inline void fillRects(const T *rects, int n, const QTransform &transform, IDirectFBSurface *surface) +{ + if (n == 1) { + const QRect r = ::mapRect(transform, rects[0]); + surface->FillRectangle(surface, r.x(), r.y(), r.width(), r.height()); + } else { + QVarLengthArray<DFBRectangle, 32> rectArray(n); + for (int i=0; i<n; ++i) { + const QRect r = ::mapRect(transform, rects[i]); + rectArray[i].x = r.x(); + rectArray[i].y = r.y(); + rectArray[i].w = r.width(); + rectArray[i].h = r.height(); + } + surface->FillRectangles(surface, rectArray.constData(), n); + } +} + +template <class T> +static inline void drawRects(const T *rects, int n, const QTransform &transform, IDirectFBSurface *surface) +{ + for (int i=0; i<n; ++i) { + const QRect r = ::mapRect(transform, rects[i]); + surface->DrawRectangle(surface, r.x(), r.y(), r.width(), r.height()); + } +} + +#ifdef QT_DIRECTFB_WARN_ON_RASTERFALLBACKS +template <typename T> inline const T *ptr(const T &t) { return &t; } +template <> inline const bool* ptr<bool>(const bool &) { return 0; } +template <typename device, typename T1, typename T2, typename T3> +static void rasterFallbackWarn(const char *msg, const char *func, const device *dev, + uint transformationType, bool simplePen, + bool dfbHandledClip, bool unsupportedCompositionMode, + const char *nameOne, const T1 &one, + const char *nameTwo, const T2 &two, + const char *nameThree, const T3 &three) +{ + QString out; + QDebug dbg(&out); + dbg << msg << (QByteArray(func) + "()") << "painting on"; + if (dev->devType() == QInternal::Widget) { + dbg << static_cast<const QWidget*>(dev); + } else { + dbg << dev << "of type" << dev->devType(); + } + + dbg << QString("transformationType 0x%1").arg(transformationType, 3, 16, QLatin1Char('0')) + << "simplePen" << simplePen + << "dfbHandledClip" << dfbHandledClip + << "unsupportedCompositionMode" << unsupportedCompositionMode; + + const T1 *t1 = ptr(one); + const T2 *t2 = ptr(two); + const T3 *t3 = ptr(three); + + if (t1) { + dbg << nameOne << *t1; + if (t2) { + dbg << nameTwo << *t2; + if (t3) { + dbg << nameThree << *t3; + } + } + } + qWarning("%s", qPrintable(out)); +} +#endif + + #endif // QT_NO_DIRECTFB diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h index 8c5877b..6148b14 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h @@ -56,43 +56,40 @@ class QDirectFBPaintEngine : public QRasterPaintEngine Q_DECLARE_PRIVATE(QDirectFBPaintEngine) public: QDirectFBPaintEngine(QPaintDevice *device); - ~QDirectFBPaintEngine(); + virtual ~QDirectFBPaintEngine(); - bool begin(QPaintDevice *device); - bool end(); + virtual bool begin(QPaintDevice *device); + virtual bool end(); - void drawRects(const QRect *rects, int rectCount); - void drawRects(const QRectF *rects, int rectCount); + virtual void drawRects(const QRect *rects, int rectCount); + virtual void drawRects(const QRectF *rects, int rectCount); - void fillRect(const QRectF &r, const QBrush &brush); - void fillRect(const QRectF &r, const QColor &color); + virtual void fillRect(const QRectF &r, const QBrush &brush); + virtual void fillRect(const QRectF &r, const QColor &color); - void drawLines(const QLine *line, int lineCount); - void drawLines(const QLineF *line, int lineCount); + virtual void drawLines(const QLine *line, int lineCount); + virtual void drawLines(const QLineF *line, int lineCount); - void drawImage(const QPointF &p, const QImage &img); - void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, - Qt::ImageConversionFlags falgs = Qt::AutoColor); + virtual void drawImage(const QPointF &p, const QImage &img); + virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, + Qt::ImageConversionFlags falgs = Qt::AutoColor); - void drawPixmap(const QPointF &p, const QPixmap &pm); - void drawPixmap(const QRectF &r, const QPixmap &pixmap, const QRectF &sr); - void drawTiledPixmap(const QRectF &r, const QPixmap &pm, const QPointF &sr); + virtual void drawPixmap(const QPointF &p, const QPixmap &pm); + virtual void drawPixmap(const QRectF &r, const QPixmap &pixmap, const QRectF &sr); + virtual void drawTiledPixmap(const QRectF &r, const QPixmap &pm, const QPointF &sr); - void drawColorSpans(const QSpan *spans, int count, uint color); - void drawBufferSpan(const uint *buffer, int bufsize, - int x, int y, int length, uint const_alpha); + virtual void drawBufferSpan(const uint *buffer, int bufsize, + int x, int y, int length, uint const_alpha); - - // The following methods simply lock the surface & call the base implementation - void stroke(const QVectorPath &path, const QPen &pen); - void drawPath(const QPainterPath &path); - void drawPoints(const QPointF *points, int pointCount); - void drawPoints(const QPoint *points, int pointCount); - void drawEllipse(const QRectF &rect); - void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode); - void drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode); - void drawTextItem(const QPointF &p, const QTextItem &textItem); - void fill(const QVectorPath &path, const QBrush &brush); + virtual void stroke(const QVectorPath &path, const QPen &pen); + virtual void drawPath(const QPainterPath &path); + virtual void drawPoints(const QPointF *points, int pointCount); + virtual void drawPoints(const QPoint *points, int pointCount); + virtual void drawEllipse(const QRectF &rect); + virtual void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode); + virtual void drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode); + virtual void drawTextItem(const QPointF &p, const QTextItem &textItem); + virtual void fill(const QVectorPath &path, const QBrush &brush); virtual void clipEnabledChanged(); virtual void penChanged(); diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp index c9d5d7c..52e85ba 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp @@ -345,6 +345,10 @@ QImage QDirectFBPixmapData::toImage() const if (!dfbSurface) return QImage(); +#if 0 + // In later versions of DirectFB one can set a flag to tell + // DirectFB not to move the surface to videomemory. When that + // happens we can use this (hopefully faster) codepath #ifndef QT_NO_DIRECTFB_PREALLOCATED QImage ret(w, h, QDirectFBScreen::getImageFormat(dfbSurface)); if (IDirectFBSurface *imgSurface = screen->createDFBSurface(ret, QDirectFBScreen::DontTrackSurface)) { @@ -362,6 +366,7 @@ QImage QDirectFBPixmapData::toImage() const return ret; } #endif +#endif QDirectFBPixmapData *that = const_cast<QDirectFBPixmapData*>(this); const QImage *img = that->buffer(); @@ -385,7 +390,7 @@ QImage *QDirectFBPixmapData::buffer() return lockedImage; } -QImage * QDirectFBPixmapData::buffer(uint lockFlags) +QImage * QDirectFBPixmapData::buffer(DFBSurfaceLockFlags lockFlags) { lockDirectFB(lockFlags); return lockedImage; diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h index e81aef4..0204061 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h @@ -71,7 +71,7 @@ public: virtual QImage *buffer(); virtual int metric(QPaintDevice::PaintDeviceMetric m) const {return QDirectFBPaintDevice::metric(m);} - QImage *buffer(uint lockFlags); + QImage *buffer(DFBSurfaceLockFlags lockFlags); // Pure virtual in QPixmapData, so re-implement here and delegate to QDirectFBPaintDevice inline QImage::Format pixelFormat() const { return format; } diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp index 76064ad..0928643 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp @@ -208,7 +208,7 @@ IDirectFBSurface *QDirectFBScreen::createDFBSurface(const QSize &size, { DFBSurfaceDescription desc; memset(&desc, 0, sizeof(DFBSurfaceDescription)); - desc.flags = DFBSurfaceDescriptionFlags(DSDESC_WIDTH|DSDESC_HEIGHT); + desc.flags |= DSDESC_WIDTH|DSDESC_HEIGHT; if (!QDirectFBScreen::initSurfaceDescriptionPixelFormat(&desc, format)) return 0; desc.width = size.width(); @@ -226,13 +226,15 @@ IDirectFBSurface *QDirectFBScreen::createDFBSurface(DFBSurfaceDescription desc, return 0; } - if (d_ptr->directFBFlags & VideoOnly && !(desc.flags & DSDESC_PREALLOCATED)) { + if (d_ptr->directFBFlags & VideoOnly + && !(desc.flags & DSDESC_PREALLOCATED) + && (!(desc.flags & DSDESC_CAPS) || !(desc.caps & DSCAPS_SYSTEMONLY))) { // Add the video only capability. This means the surface will be created in video ram if (!(desc.flags & DSDESC_CAPS)) { desc.caps = DSCAPS_VIDEOONLY; - desc.flags = DFBSurfaceDescriptionFlags(desc.flags | DSDESC_CAPS); + desc.flags |= DSDESC_CAPS; } else { - desc.caps = DFBSurfaceCapabilities(desc.caps | DSCAPS_VIDEOONLY); + desc.caps |= DSCAPS_VIDEOONLY; } result = d_ptr->dfb->CreateSurface(d_ptr->dfb, &desc, &newSurface); if (result != DFB_OK @@ -247,11 +249,11 @@ IDirectFBSurface *QDirectFBScreen::createDFBSurface(DFBSurfaceDescription desc, desc.preallocated[0].data, desc.preallocated[0].pitch, DirectFBErrorString(result)); } - desc.caps = DFBSurfaceCapabilities(desc.caps & ~DSCAPS_VIDEOONLY); + desc.caps &= ~DSCAPS_VIDEOONLY; } if (d_ptr->directFBFlags & SystemOnly) - desc.caps = DFBSurfaceCapabilities(desc.caps | DSCAPS_SYSTEMONLY); + desc.caps |= DSCAPS_SYSTEMONLY; if (!newSurface) result = d_ptr->dfb->CreateSurface(d_ptr->dfb, &desc, &newSurface); @@ -459,20 +461,16 @@ DFBSurfaceDescription QDirectFBScreen::getSurfaceDescription(const QImage &image const DFBSurfacePixelFormat format = getSurfacePixelFormat(image.format()); if (format == DSPF_UNKNOWN || image.isNull()) { - description.flags = DFBSurfaceDescriptionFlags(0); + description.flags = DSDESC_NONE; return description; } - description.flags = DFBSurfaceDescriptionFlags(DSDESC_WIDTH - | DSDESC_HEIGHT -#ifndef QT_NO_DIRECTFB_PREALLOCATED - | DSDESC_PREALLOCATED -#endif - | DSDESC_PIXELFORMAT); + description.flags = DSDESC_WIDTH|DSDESC_HEIGHT|DSDESC_PIXELFORMAT; QDirectFBScreen::initSurfaceDescriptionPixelFormat(&description, image.format()); description.width = image.width(); description.height = image.height(); #ifndef QT_NO_DIRECTFB_PREALLOCATED + description.flags |= DSDESC_PREALLOCATED; description.preallocated[0].data = (void*)(image.bits()); description.preallocated[0].pitch = image.bytesPerLine(); description.preallocated[1].data = 0; @@ -491,11 +489,7 @@ DFBSurfaceDescription QDirectFBScreen::getSurfaceDescription(const uint *buffer, DFBSurfaceDescription description; memset(&description, 0, sizeof(DFBSurfaceDescription)); - description.flags = DFBSurfaceDescriptionFlags(DSDESC_CAPS - | DSDESC_WIDTH - | DSDESC_HEIGHT - | DSDESC_PIXELFORMAT - | DSDESC_PREALLOCATED); + description.flags = DSDESC_CAPS|DSDESC_WIDTH|DSDESC_HEIGHT|DSDESC_PIXELFORMAT|DSDESC_PREALLOCATED; description.caps = DSCAPS_PREMULTIPLIED; description.width = length; description.height = 1; @@ -504,8 +498,7 @@ DFBSurfaceDescription QDirectFBScreen::getSurfaceDescription(const uint *buffer, description.preallocated[0].pitch = length * sizeof(uint); description.preallocated[1].data = 0; description.preallocated[1].pitch = 0; - - return description; +return description; } #ifndef QT_NO_DIRECTFB_PALETTE @@ -727,19 +720,19 @@ void QDirectFBScreenPrivate::setFlipFlags(const QStringList &args) flipFlags = DSFLIP_NONE; foreach(const QString &flip, flips) { if (flip == QLatin1String("wait")) - flipFlags = DFBSurfaceFlipFlags(flipFlags | DSFLIP_WAIT); + flipFlags |= DSFLIP_WAIT; else if (flip == QLatin1String("blit")) - flipFlags = DFBSurfaceFlipFlags(flipFlags | DSFLIP_BLIT); + flipFlags |= DSFLIP_BLIT; else if (flip == QLatin1String("onsync")) - flipFlags = DFBSurfaceFlipFlags(flipFlags | DSFLIP_ONSYNC); + flipFlags |= DSFLIP_ONSYNC; else if (flip == QLatin1String("pipeline")) - flipFlags = DFBSurfaceFlipFlags(flipFlags | DSFLIP_PIPELINE); + flipFlags |= DSFLIP_PIPELINE; else qWarning("QDirectFBScreen: Unknown flip argument: %s", qPrintable(flip)); } } else { - flipFlags = DFBSurfaceFlipFlags(DSFLIP_BLIT); + flipFlags = DSFLIP_BLIT; } } @@ -751,7 +744,12 @@ QPixmapData *QDirectFBScreenPrivate::createPixmapData(QPixmapData::PixelType typ return new QDirectFBPixmapData(type); } -#ifndef QT_NO_DEBUG +#ifdef QT_NO_DEBUG +struct FlagDescription; +static const FlagDescription *accelerationDescriptions = 0; +static const FlagDescription *blitDescriptions = 0; +static const FlagDescription *drawDescriptions = 0; +#else struct FlagDescription { const char *name; uint flag; @@ -928,13 +926,13 @@ bool QDirectFBScreen::connect(const QString &displaySpec) DFBSurfaceDescription description; memset(&description, 0, sizeof(DFBSurfaceDescription)); - description.flags = DFBSurfaceDescriptionFlags(DSDESC_CAPS); + description.flags = DSDESC_CAPS; if (::setIntOption(displayArgs, QLatin1String("width"), &description.width)) - description.flags = DFBSurfaceDescriptionFlags(description.flags | DSDESC_WIDTH); + description.flags |= DSDESC_WIDTH; if (::setIntOption(displayArgs, QLatin1String("height"), &description.height)) - description.flags = DFBSurfaceDescriptionFlags(description.flags | DSDESC_HEIGHT); + description.flags |= DSDESC_HEIGHT; - uint caps = DSCAPS_PRIMARY|DSCAPS_DOUBLE; + description.caps = DSCAPS_PRIMARY|DSCAPS_DOUBLE; struct { const char *name; const DFBSurfaceCapabilities cap; @@ -948,14 +946,13 @@ bool QDirectFBScreen::connect(const QString &displaySpec) }; for (int i=0; capabilities[i].name; ++i) { if (displayArgs.contains(QString::fromLatin1(capabilities[i].name), Qt::CaseInsensitive)) - caps |= capabilities[i].cap; + description.caps |= capabilities[i].cap; } if (displayArgs.contains(QLatin1String("forcepremultiplied"), Qt::CaseInsensitive)) { - caps |= DSCAPS_PREMULTIPLIED; + description.caps |= DSCAPS_PREMULTIPLIED; } - description.caps = DFBSurfaceCapabilities(caps); // We don't track the primary surface as it's released in disconnect d_ptr->dfbSurface = createDFBSurface(description, DontTrackSurface); if (!d_ptr->dfbSurface) { @@ -1213,10 +1210,10 @@ void QDirectFBScreen::compose(const QRegion ®ion) DFBSurfaceBlittingFlags flags = DSBLIT_NOFX; if (!win->isOpaque()) { - flags = DFBSurfaceBlittingFlags(flags | DSBLIT_BLEND_ALPHACHANNEL); + flags |= DSBLIT_BLEND_ALPHACHANNEL; const uint opacity = win->opacity(); if (opacity < 255) { - flags = DFBSurfaceBlittingFlags(flags | DSBLIT_BLEND_COLORALPHA); + flags |= DSBLIT_BLEND_COLORALPHA; d_ptr->dfbSurface->SetColor(d_ptr->dfbSurface, 0xff, 0xff, 0xff, opacity); } } @@ -1356,14 +1353,14 @@ bool QDirectFBScreen::initSurfaceDescriptionPixelFormat(DFBSurfaceDescription *d const DFBSurfacePixelFormat pixelformat = QDirectFBScreen::getSurfacePixelFormat(format); if (pixelformat == DSPF_UNKNOWN) return false; - description->flags = DFBSurfaceDescriptionFlags(description->flags | DSDESC_PIXELFORMAT); + description->flags |= DSDESC_PIXELFORMAT; description->pixelformat = pixelformat; if (QDirectFBScreen::isPremultiplied(format)) { if (!(description->flags & DSDESC_CAPS)) { description->caps = DSCAPS_PREMULTIPLIED; - description->flags = DFBSurfaceDescriptionFlags(description->flags | DSDESC_CAPS); + description->flags |= DSDESC_CAPS; } else { - description->caps = DFBSurfaceCapabilities(description->caps | DSCAPS_PREMULTIPLIED); + description->caps |= DSCAPS_PREMULTIPLIED; } } return true; diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h index 4239156..69b09e9 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h +++ b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h @@ -44,6 +44,7 @@ #include <QtGui/qscreen_qws.h> #include <directfb.h> +#include <directfb_version.h> QT_BEGIN_HEADER @@ -51,8 +52,24 @@ QT_MODULE(Gui) #define Q_DIRECTFB_VERSION ((DIRECTFB_MAJOR_VERSION << 16) | (DIRECTFB_MINOR_VERION << 8) | DIRECTFB_MICRO_VERSION) -class QDirectFBScreenPrivate; +#include <QDebug> +#define DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(F) \ + static inline F operator~(F f) { return F(~int(f)); } \ + static inline F operator&(F left, F right) { return F(int(left) & int(right)); } \ + static inline F operator|(F left, F right) { return F(int(left) | int(right)); } \ + static inline F &operator|=(F &left, F right) { left = (left | right); return left; } \ + static inline F &operator&=(F &left, F right) { left = (left & right); return left; } + +DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBInputDeviceCapabilities); +DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBWindowDescriptionFlags); +DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBSurfaceDescriptionFlags); +DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBSurfaceCapabilities); +DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBSurfaceLockFlags); +DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBSurfaceBlittingFlags); +DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBSurfaceDrawingFlags); +DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBSurfaceFlipFlags); +class QDirectFBScreenPrivate; class Q_GUI_EXPORT QDirectFBScreen : public QScreen { public: diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp index 86ee62c..7dcf398 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp @@ -106,18 +106,16 @@ void QDirectFBWindowSurface::createWindow() qFatal("QDirectFBWindowSurface: Unable to get primary display layer!"); DFBWindowDescription description; - description.caps = DFBWindowCapabilities(DWCAPS_NODECORATION); - description.flags = DFBWindowDescriptionFlags(DWDESC_CAPS - |DWDESC_SURFACE_CAPS - |DWDESC_PIXELFORMAT); + description.caps = DWCAPS_NODECORATION; + description.flags = DWDESC_CAPS|DWDESC_SURFACE_CAPS|DWDESC_PIXELFORMAT; description.surface_caps = DSCAPS_NONE; if (screen->directFBFlags() & QDirectFBScreen::VideoOnly) - description.surface_caps = DFBSurfaceCapabilities(description.surface_caps|DSCAPS_VIDEOONLY); + description.surface_caps |= DSCAPS_VIDEOONLY; const QImage::Format format = screen->pixelFormat(); description.pixelformat = QDirectFBScreen::getSurfacePixelFormat(format); if (QDirectFBScreen::isPremultiplied(format)) - description.surface_caps = DFBSurfaceCapabilities(DSCAPS_PREMULTIPLIED|description.caps); + description.surface_caps = DSCAPS_PREMULTIPLIED; DFBResult result = layer->CreateWindow(layer, &description, &dfbWindow); if (result != DFB_OK) @@ -370,7 +368,7 @@ void QDirectFBWindowSurface::flush(QWidget *widget, const QRegion ®ion, } else { if (!boundingRectFlip && region.numRects() > 1) { const QVector<QRect> rects = region.rects(); - const DFBSurfaceFlipFlags nonWaitFlags = DFBSurfaceFlipFlags(flipFlags & ~DSFLIP_WAIT); + const DFBSurfaceFlipFlags nonWaitFlags = flipFlags & ~DSFLIP_WAIT; for (int i=0; i<rects.size(); ++i) { const QRect &r = rects.at(i); const DFBRegion dfbReg = { r.x() + offset.x(), r.y() + offset.y(), diff --git a/src/plugins/graphicssystems/openvg/openvg.pro b/src/plugins/graphicssystems/openvg/openvg.pro index 0abbfbd..d36570c 100644 --- a/src/plugins/graphicssystems/openvg/openvg.pro +++ b/src/plugins/graphicssystems/openvg/openvg.pro @@ -10,11 +10,3 @@ HEADERS = qgraphicssystem_vg_p.h target.path += $$[QT_INSTALL_PLUGINS]/graphicssystems INSTALLS += target - -!isEmpty(QMAKE_INCDIR_OPENVG): INCLUDEPATH += $$QMAKE_INCDIR_OPENVG -!isEmpty(QMAKE_LIBDIR_OPENVG): LIBS += -L$$QMAKE_LIBDIR_OPENVG -!isEmpty(QMAKE_LIBS_OPENVG): LIBS += $$QMAKE_LIBS_OPENVG - -!isEmpty(QMAKE_INCDIR_EGL): INCLUDEPATH += $$QMAKE_INCDIR_EGL -!isEmpty(QMAKE_LIBDIR_EGL): LIBS += -L$$QMAKE_LIBDIR_EGL -!isEmpty(QMAKE_LIBS_EGL): LIBS += $$QMAKE_LIBS_EGL diff --git a/src/plugins/graphicssystems/shivavg/shivavg.pro b/src/plugins/graphicssystems/shivavg/shivavg.pro index 68345af..b8ea12a 100644 --- a/src/plugins/graphicssystems/shivavg/shivavg.pro +++ b/src/plugins/graphicssystems/shivavg/shivavg.pro @@ -10,7 +10,3 @@ HEADERS = shivavggraphicssystem.h shivavgwindowsurface.h target.path += $$[QT_INSTALL_PLUGINS]/graphicssystems INSTALLS += target - -!isEmpty(QMAKE_INCDIR_OPENVG): INCLUDEPATH += $$QMAKE_INCDIR_OPENVG -!isEmpty(QMAKE_LIBDIR_OPENVG): LIBS += -L$$QMAKE_LIBDIR_OPENVG -!isEmpty(QMAKE_LIBS_OPENVG): LIBS += $$QMAKE_LIBS_OPENVG diff --git a/src/plugins/imageformats/ico/qicohandler.cpp b/src/plugins/imageformats/ico/qicohandler.cpp index 43e35c0..c9e04a4 100644 --- a/src/plugins/imageformats/ico/qicohandler.cpp +++ b/src/plugins/imageformats/ico/qicohandler.cpp @@ -522,6 +522,18 @@ QImage ICOReader::iconAt(int index) ICONDIRENTRY iconEntry; if (readIconEntry(index, &iconEntry)) { + static const uchar pngMagicData[] = { 137, 80, 78, 71, 13, 10, 26, 10 }; + + iod->seek(iconEntry.dwImageOffset); + + const QByteArray pngMagic = QByteArray::fromRawData((char*)pngMagicData, sizeof(pngMagicData)); + const bool isPngImage = (iod->read(pngMagic.size()) == pngMagic); + + if (isPngImage) { + iod->seek(iconEntry.dwImageOffset); + return QImage::fromData(iod->read(iconEntry.dwBytesInRes), "png"); + } + BMP_INFOHDR header; if (readBMPHeader(iconEntry.dwImageOffset, &header)) { icoAttrib.nbits = header.biBitCount ? header.biBitCount : iconEntry.wBitCount; diff --git a/src/qt3support/canvas/q3canvas.cpp b/src/qt3support/canvas/q3canvas.cpp index 034aff5..948935c 100644 --- a/src/qt3support/canvas/q3canvas.cpp +++ b/src/qt3support/canvas/q3canvas.cpp @@ -4828,7 +4828,7 @@ void Q3CanvasText::draw(QPainter& painter) } /*! - \reimp + \internal */ void Q3CanvasText::changeChunks() { diff --git a/src/qt3support/dialogs/q3tabdialog.cpp b/src/qt3support/dialogs/q3tabdialog.cpp index 50dbd48..a65affc 100644 --- a/src/qt3support/dialogs/q3tabdialog.cpp +++ b/src/qt3support/dialogs/q3tabdialog.cpp @@ -1038,7 +1038,7 @@ QString Q3TabDialog::tabLabel(QWidget * w) } -/*! \reimp +/*! \internal */ void Q3TabDialog::styleChange(QStyle& s) { diff --git a/src/qt3support/itemviews/q3table.cpp b/src/qt3support/itemviews/q3table.cpp index 11c70b4..6c3e90c 100644 --- a/src/qt3support/itemviews/q3table.cpp +++ b/src/qt3support/itemviews/q3table.cpp @@ -6411,7 +6411,7 @@ void Q3Table::startDrag() #endif -/*! \reimp */ +/*! \internal */ void Q3Table::windowActivationChange(bool oldActive) { if (oldActive && autoScrollTimer) diff --git a/src/qt3support/network/q3http.cpp b/src/qt3support/network/q3http.cpp index 59adc27..dba4e88 100644 --- a/src/qt3support/network/q3http.cpp +++ b/src/qt3support/network/q3http.cpp @@ -785,7 +785,7 @@ int Q3HttpResponseHeader::minorVersion() const return minVer; } -/*! \reimp +/*! \internal */ bool Q3HttpResponseHeader::parseLine( const QString& line, int number ) { @@ -952,7 +952,7 @@ int Q3HttpRequestHeader::minorVersion() const return minVer; } -/*! \reimp +/*! \internal */ bool Q3HttpRequestHeader::parseLine( const QString& line, int number ) { diff --git a/src/qt3support/widgets/q3datetimeedit.cpp b/src/qt3support/widgets/q3datetimeedit.cpp index 9c2f289..71a8ffd 100644 --- a/src/qt3support/widgets/q3datetimeedit.cpp +++ b/src/qt3support/widgets/q3datetimeedit.cpp @@ -1244,7 +1244,7 @@ Q3DateEdit::Order Q3DateEdit::order() const } -/*! \reimp +/*! \internal */ void Q3DateEdit::stepUp() @@ -1276,7 +1276,7 @@ void Q3DateEdit::stepUp() -/*! \reimp +/*! \internal */ @@ -1440,7 +1440,7 @@ bool Q3DateEdit::outOfRange(int y, int m, int d) const return false; /* assume ok */ } -/*! \reimp +/*! \internal */ @@ -1534,7 +1534,7 @@ void Q3DateEdit::addNumber(int sec, int num) } -/*! \reimp +/*! \internal */ @@ -1681,7 +1681,7 @@ void Q3DateEdit::removeFirstNumber(int sec) d->ed->repaint(d->ed->rect()); } -/*! \reimp +/*! \internal */ @@ -2059,7 +2059,7 @@ void Q3TimeEdit::timerEvent(QTimerEvent *) } -/*! \reimp +/*! \internal */ @@ -2105,7 +2105,7 @@ void Q3TimeEdit::stepUp() } -/*! \reimp +/*! \internal */ @@ -2173,7 +2173,7 @@ QString Q3TimeEdit::sectionFormattedText(int sec) } -/*! \reimp +/*! \internal */ @@ -2308,7 +2308,7 @@ bool Q3TimeEdit::outOfRange(int h, int m, int s) const return true; } -/*! \reimp +/*! \internal */ @@ -2477,7 +2477,7 @@ void Q3TimeEdit::removeFirstNumber(int sec) d->ed->repaint(d->ed->rect()); } -/*! \reimp +/*! \internal */ void Q3TimeEdit::removeLastNumber(int sec) diff --git a/src/qt3support/widgets/q3scrollview.cpp b/src/qt3support/widgets/q3scrollview.cpp index cea385a..95e2117 100644 --- a/src/qt3support/widgets/q3scrollview.cpp +++ b/src/qt3support/widgets/q3scrollview.cpp @@ -669,7 +669,7 @@ bool Q3ScrollView::isVerticalSliderPressed() } /*! - \reimp + \internal */ void Q3ScrollView::styleChange(QStyle& old) { @@ -679,7 +679,7 @@ void Q3ScrollView::styleChange(QStyle& old) } /*! - \reimp + \internal */ void Q3ScrollView::fontChange(const QFont &old) { diff --git a/src/script/qscriptvalue.cpp b/src/script/qscriptvalue.cpp index 97ce61a..48e1318 100644 --- a/src/script/qscriptvalue.cpp +++ b/src/script/qscriptvalue.cpp @@ -574,9 +574,11 @@ void QScriptValue::setPrototype(const QScriptValue &prototype) } /*! - Returns the scope object of this QScriptValue. This function is only - relevant for function objects. The scope determines how variables are - resolved when the function is invoked. + \since 4.6 + + Returns the scope object of this QScriptValue. This function is only + relevant for function objects. The scope determines how variables are + resolved when the function is invoked. */ QScriptValue QScriptValue::scope() const { @@ -588,9 +590,11 @@ QScriptValue QScriptValue::scope() const } /*! - Sets the \a scope object of this QScriptValue. This function is only - relevant for function objects. Changing the scope is useful when creating - closures; see \l{Nested Functions and the Scope Chain}. + \since 4.6 + + Sets the \a scope object of this QScriptValue. This function is only + relevant for function objects. Changing the scope is useful when creating + closures; see \l{Nested Functions and the Scope Chain}. */ void QScriptValue::setScope(const QScriptValue &scope) { diff --git a/src/scripttools/debugging/qscriptdebuggerscriptedconsolecommand.cpp b/src/scripttools/debugging/qscriptdebuggerscriptedconsolecommand.cpp index 1324c01..92fa36c 100644 --- a/src/scripttools/debugging/qscriptdebuggerscriptedconsolecommand.cpp +++ b/src/scripttools/debugging/qscriptdebuggerscriptedconsolecommand.cpp @@ -460,7 +460,7 @@ void QScriptDebuggerScriptedConsoleCommandJob::handleResponse( } /*! - \reimp + \internal */ QString QScriptDebuggerScriptedConsoleCommand::name() const { @@ -469,7 +469,7 @@ QString QScriptDebuggerScriptedConsoleCommand::name() const } /*! - \reimp + \internal */ QString QScriptDebuggerScriptedConsoleCommand::group() const { @@ -478,7 +478,7 @@ QString QScriptDebuggerScriptedConsoleCommand::group() const } /*! - \reimp + \internal */ QString QScriptDebuggerScriptedConsoleCommand::shortDescription() const { @@ -487,7 +487,7 @@ QString QScriptDebuggerScriptedConsoleCommand::shortDescription() const } /*! - \reimp + \internal */ QString QScriptDebuggerScriptedConsoleCommand::longDescription() const { @@ -496,7 +496,7 @@ QString QScriptDebuggerScriptedConsoleCommand::longDescription() const } /*! - \reimp + \internal */ QStringList QScriptDebuggerScriptedConsoleCommand::aliases() const { @@ -505,7 +505,7 @@ QStringList QScriptDebuggerScriptedConsoleCommand::aliases() const } /*! - \reimp + \internal */ QStringList QScriptDebuggerScriptedConsoleCommand::seeAlso() const { @@ -514,7 +514,7 @@ QStringList QScriptDebuggerScriptedConsoleCommand::seeAlso() const } /*! - \reimp + \internal */ QStringList QScriptDebuggerScriptedConsoleCommand::argumentTypes() const { @@ -523,7 +523,7 @@ QStringList QScriptDebuggerScriptedConsoleCommand::argumentTypes() const } /*! - \reimp + \internal */ QStringList QScriptDebuggerScriptedConsoleCommand::subCommands() const { @@ -532,7 +532,7 @@ QStringList QScriptDebuggerScriptedConsoleCommand::subCommands() const } /*! - \reimp + \internal */ QScriptDebuggerConsoleCommandJob *QScriptDebuggerScriptedConsoleCommand::createJob( const QStringList &arguments, diff --git a/src/scripttools/debugging/qscriptenginedebuggerfrontend.cpp b/src/scripttools/debugging/qscriptenginedebuggerfrontend.cpp index c5e21ef..5b58c52 100644 --- a/src/scripttools/debugging/qscriptenginedebuggerfrontend.cpp +++ b/src/scripttools/debugging/qscriptenginedebuggerfrontend.cpp @@ -323,7 +323,7 @@ QScriptDebuggerBackend *QScriptEngineDebuggerFrontend::backend() const } /*! - \reimp + \internal */ void QScriptEngineDebuggerFrontend::processCommand(int id, const QScriptDebuggerCommand &command) { diff --git a/src/sql/drivers/db2/qsql_db2.cpp b/src/sql/drivers/db2/qsql_db2.cpp index e4f564a..474c53d 100644 --- a/src/sql/drivers/db2/qsql_db2.cpp +++ b/src/sql/drivers/db2/qsql_db2.cpp @@ -59,6 +59,8 @@ #define SQL_BIGUINT_TYPE quint64 #endif +#define UNICODE + #include <sqlcli1.h> #include <string.h> diff --git a/src/sql/drivers/odbc/qsql_odbc.cpp b/src/sql/drivers/odbc/qsql_odbc.cpp index fa9031a..2df0073 100644 --- a/src/sql/drivers/odbc/qsql_odbc.cpp +++ b/src/sql/drivers/odbc/qsql_odbc.cpp @@ -1783,7 +1783,7 @@ bool QODBCDriver::open(const QString & db, if (!d->checkDriver()) { setLastError(qMakeError(tr("Unable to connect - Driver doesn't support all " - "needed functionality"), QSqlError::ConnectionError, d)); + "functionality required"), QSqlError::ConnectionError, d)); setOpenError(true); return false; } diff --git a/src/sql/drivers/sqlite2/qsql_sqlite2.cpp b/src/sql/drivers/sqlite2/qsql_sqlite2.cpp index 1989c45..d30e82c 100644 --- a/src/sql/drivers/sqlite2/qsql_sqlite2.cpp +++ b/src/sql/drivers/sqlite2/qsql_sqlite2.cpp @@ -388,7 +388,7 @@ bool QSQLite2Driver::open(const QString & db, const QString &, const QString &, char* err = 0; d->access = sqlite_open(QFile::encodeName(db), 0, &err); if (err) { - setLastError(QSqlError(tr("Error to open database"), QString::fromAscii(err), + setLastError(QSqlError(tr("Error opening database"), QString::fromAscii(err), QSqlError::ConnectionError)); sqlite_freemem(err); err = 0; @@ -463,7 +463,7 @@ bool QSQLite2Driver::rollbackTransaction() if (res == SQLITE_OK) return true; - setLastError(QSqlError(tr("Unable to rollback Transaction"), + setLastError(QSqlError(tr("Unable to rollback transaction"), QString::fromAscii(err), QSqlError::TransactionError, res)); sqlite_freemem(err); return false; diff --git a/src/sql/kernel/qsqldatabase.cpp b/src/sql/kernel/qsqldatabase.cpp index 5aef39e..4950303 100644 --- a/src/sql/kernel/qsqldatabase.cpp +++ b/src/sql/kernel/qsqldatabase.cpp @@ -1481,18 +1481,21 @@ QString QSqlDatabase::connectionName() const } /*! - Sets the default numerical precision policy used by queries created - on this database connection to \a precisionPolicy. + \since 4.6 - Note: Drivers that don't support fetching numerical values with low - precision will ignore the precision policy. You can use - QSqlDriver::hasFeature() to find out whether a driver supports this - feature. + Sets the default numerical precision policy used by queries created + on this database connection to \a precisionPolicy. - Note: Setting the default precision policy to \a precisionPolicy - doesn't affect any currently active queries. + Note: Drivers that don't support fetching numerical values with low + precision will ignore the precision policy. You can use + QSqlDriver::hasFeature() to find out whether a driver supports this + feature. - \sa QSql::NumericalPrecisionPolicy, numericalPrecisionPolicy(), QSqlQuery::setNumericalPrecisionPolicy(), QSqlQuery::numericalPrecisionPolicy() + Note: Setting the default precision policy to \a precisionPolicy + doesn't affect any currently active queries. + + \sa QSql::NumericalPrecisionPolicy, numericalPrecisionPolicy(), + QSqlQuery::setNumericalPrecisionPolicy(), QSqlQuery::numericalPrecisionPolicy() */ void QSqlDatabase::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy precisionPolicy) { @@ -1502,9 +1505,12 @@ void QSqlDatabase::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy pr } /*! - Returns the current default precision policy for the database connection. + \since 4.6 + + Returns the current default precision policy for the database connection. - \sa QSql::NumericalPrecisionPolicy, setNumericalPrecisionPolicy(), QSqlQuery::numericalPrecisionPolicy(), QSqlQuery::setNumericalPrecisionPolicy() + \sa QSql::NumericalPrecisionPolicy, setNumericalPrecisionPolicy(), + QSqlQuery::numericalPrecisionPolicy(), QSqlQuery::setNumericalPrecisionPolicy() */ QSql::NumericalPrecisionPolicy QSqlDatabase::numericalPrecisionPolicy() const { diff --git a/src/sql/kernel/qsqldriver.cpp b/src/sql/kernel/qsqldriver.cpp index 77e389f..ca0da66 100644 --- a/src/sql/kernel/qsqldriver.cpp +++ b/src/sql/kernel/qsqldriver.cpp @@ -865,6 +865,8 @@ QStringList QSqlDriver::subscribedToNotificationsImplementation() const } /*! + \since 4.6 + This slot returns whether \a identifier is escaped according to the database rules. \a identifier can either be a table name or field name, dependent on \a type. @@ -876,7 +878,6 @@ QStringList QSqlDriver::subscribedToNotificationsImplementation() const slot in your own QSqlDriver if your database engine uses a different delimiter character. - \since 4.5 \sa isIdentifierEscaped() */ bool QSqlDriver::isIdentifierEscapedImplementation(const QString &identifier, IdentifierType type) const @@ -888,6 +889,8 @@ bool QSqlDriver::isIdentifierEscapedImplementation(const QString &identifier, Id } /*! + \since 4.6 + This slot returns \a identifier with the leading and trailing delimiters removed, \a identifier can either be a tablename or field name, dependent on \a type. If \a identifier does not have leading and trailing delimiter characters, \a @@ -898,7 +901,6 @@ bool QSqlDriver::isIdentifierEscapedImplementation(const QString &identifier, Id dynamically detect and call \e this slot. It generally unnecessary to reimplement this slot. - \since 4.5 \sa stripDelimiters() */ QString QSqlDriver::stripDelimitersImplementation(const QString &identifier, IdentifierType type) const @@ -914,13 +916,16 @@ QString QSqlDriver::stripDelimitersImplementation(const QString &identifier, Ide } /*! - Sets the default numerical precision policy used by queries created - by this driver to \a precisionPolicy. + \since 4.6 + + Sets the default numerical precision policy used by queries created + by this driver to \a precisionPolicy. - Note: Setting the default precision policy to \a precisionPolicy - doesn't affect any currently active queries. + Note: Setting the default precision policy to \a precisionPolicy + doesn't affect any currently active queries. - \sa QSql::NumericalPrecisionPolicy, numericalPrecisionPolicy(), QSqlQuery::setNumericalPrecisionPolicy(), QSqlQuery::numericalPrecisionPolicy() + \sa QSql::NumericalPrecisionPolicy, numericalPrecisionPolicy(), + QSqlQuery::setNumericalPrecisionPolicy(), QSqlQuery::numericalPrecisionPolicy() */ void QSqlDriver::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy precisionPolicy) { @@ -928,9 +933,12 @@ void QSqlDriver::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy prec } /*! - Returns the current default precision policy for the database connection. + \since 4.6 + + Returns the current default precision policy for the database connection. - \sa QSql::NumericalPrecisionPolicy, setNumericalPrecisionPolicy(), QSqlQuery::numericalPrecisionPolicy(), QSqlQuery::setNumericalPrecisionPolicy() + \sa QSql::NumericalPrecisionPolicy, setNumericalPrecisionPolicy(), + QSqlQuery::numericalPrecisionPolicy(), QSqlQuery::setNumericalPrecisionPolicy() */ QSql::NumericalPrecisionPolicy QSqlDriver::numericalPrecisionPolicy() const { diff --git a/src/svg/qsvghandler.cpp b/src/svg/qsvghandler.cpp index 5f9d1dd..5857e1c 100644 --- a/src/svg/qsvghandler.cpp +++ b/src/svg/qsvghandler.cpp @@ -644,26 +644,19 @@ static void parseBrush(QSvgNode *node, QString opacity = attributes.value(QLatin1String("fill-opacity")).toString(); QString myId = someId(attributes); - QSvgFillStyle *inherited = - static_cast<QSvgFillStyle*>(node->parent()->styleProperty( - QSvgStyleProperty::FILL)); - QSvgFillStyle *prop = new QSvgFillStyle(QColor(Qt::black)); + QSvgFillStyle *prop = new QSvgFillStyle(0); //fill-rule attribute handling - Qt::FillRule f = Qt::WindingFill; if (!fillRule.isEmpty() && fillRule != QLatin1String("inherit")) { if (fillRule == QLatin1String("evenodd")) - f = Qt::OddEvenFill; - } else if (inherited) { - f = inherited->fillRule(); + prop->setFillRule(Qt::OddEvenFill); + else if (fillRule == QLatin1String("nonzero")) + prop->setFillRule(Qt::WindingFill); } //fill-opacity atttribute handling - qreal fillOpacity = 1.0; if (!opacity.isEmpty() && opacity != QLatin1String("inherit")) { - fillOpacity = qMin(qreal(1.0), qMax(qreal(0.0), toDouble(opacity))); - } else if (inherited) { - fillOpacity = inherited->fillOpacity(); + prop->setFillOpacity(qMin(qreal(1.0), qMax(qreal(0.0), toDouble(opacity)))); } //fill attribute handling @@ -685,15 +678,7 @@ static void parseBrush(QSvgNode *node, } else { prop->setBrush(QBrush(Qt::NoBrush)); } - } else if (inherited) { - if (inherited->style()) { - prop->setFillStyle(inherited->style()); - } else { - prop->setBrush(inherited->qbrush()); - } } - prop->setFillOpacity(fillOpacity); - prop->setFillRule(f); node->appendStyleProperty(prop,myId); } diff --git a/src/svg/qsvgstyle.cpp b/src/svg/qsvgstyle.cpp index 4c8247b..c3c0a68 100644 --- a/src/svg/qsvgstyle.cpp +++ b/src/svg/qsvgstyle.cpp @@ -81,12 +81,25 @@ void QSvgQualityStyle::revert(QPainter *, QSvgExtraStates &) } QSvgFillStyle::QSvgFillStyle(const QBrush &brush) - : m_fill(brush), m_style(0), m_fillRuleSet(false), m_fillOpacitySet(false), m_fillRule(Qt::WindingFill), m_fillOpacity(1.0), m_gradientResolved (true) + : m_fill(brush) + , m_style(0) + , m_fillRuleSet(false) + , m_fillRule(Qt::WindingFill) + , m_fillOpacitySet(false) + , m_fillOpacity(1.0) + , m_gradientResolved(true) + , m_fillSet(true) { } QSvgFillStyle::QSvgFillStyle(QSvgStyleProperty *style) - : m_style(style), m_fillRuleSet(false), m_fillOpacitySet(false), m_fillRule(Qt::WindingFill), m_fillOpacity(1.0), m_gradientResolved (true) + : m_style(style) + , m_fillRuleSet(false) + , m_fillRule(Qt::WindingFill) + , m_fillOpacitySet(false) + , m_fillOpacity(1.0) + , m_gradientResolved(true) + , m_fillSet(style != 0) { } @@ -105,11 +118,14 @@ void QSvgFillStyle::setFillOpacity(qreal opacity) void QSvgFillStyle::setFillStyle(QSvgStyleProperty* style) { m_style = style; + m_fillSet = true; } void QSvgFillStyle::setBrush(QBrush brush) { m_fill = brush; + m_style = 0; + m_fillSet = true; } static void recursivelySetFill(QSvgNode *node, Qt::FillRule f) @@ -136,20 +152,26 @@ void QSvgFillStyle::apply(QPainter *p, const QRectF &rect, QSvgNode *node, QSvgE recursivelySetFill(node, m_fillRule); m_fillRuleSet = false;//set it only on the first run } - p->setBrush(m_fill); + if (m_fillSet) { + if (m_style) + m_style->apply(p, rect, node, states); + else + p->setBrush(m_fill); + } if (m_fillOpacitySet) states.fillOpacity = m_fillOpacity; - if (m_style) - m_style->apply(p, rect, node, states); } void QSvgFillStyle::revert(QPainter *p, QSvgExtraStates &states) { - if (m_style) - m_style->revert(p, states); - p->setBrush(m_oldFill); if (m_fillOpacitySet) states.fillOpacity = m_oldOpacity; + if (m_fillSet) { + if (m_style) + m_style->revert(p, states); + else + p->setBrush(m_oldFill); + } } QSvgViewportFillStyle::QSvgViewportFillStyle(const QBrush &brush) diff --git a/src/svg/qsvgstyle_p.h b/src/svg/qsvgstyle_p.h index ac5e109..70ecf5b 100644 --- a/src/svg/qsvgstyle_p.h +++ b/src/svg/qsvgstyle_p.h @@ -281,6 +281,7 @@ private: qreal m_oldOpacity; QString m_gradientId; bool m_gradientResolved; + bool m_fillSet; }; class QSvgViewportFillStyle : public QSvgStyleProperty diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index 435ecf4..1d0bbcf 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -72,6 +72,8 @@ #include <windows.h> // for Sleep #endif #ifdef Q_OS_UNIX +#include <errno.h> +#include <signal.h> #include <time.h> #endif @@ -401,7 +403,8 @@ QT_BEGIN_NAMESPACE \overload - Simulates clicking of \a key with an optional \a modifier on a \a widget. If \a delay is larger than 0, the test will wait for \a delay milliseconds. + Simulates clicking of \a key with an optional \a modifier on a \a widget. + If \a delay is larger than 0, the test will wait for \a delay milliseconds. Example: \snippet doc/src/snippets/code/src_qtestlib_qtestcase.cpp 13 @@ -414,7 +417,8 @@ QT_BEGIN_NAMESPACE /*! \fn void QTest::keyClick(QWidget *widget, Qt::Key key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1) - Simulates clicking of \a key with an optional \a modifier on a \a widget. If \a delay is larger than 0, the test will wait for \a delay milliseconds. + Simulates clicking of \a key with an optional \a modifier on a \a widget. + If \a delay is larger than 0, the test will wait for \a delay milliseconds. Examples: \snippet doc/src/snippets/code/src_qtestlib_qtestcase.cpp 14 @@ -429,20 +433,25 @@ QT_BEGIN_NAMESPACE /*! \fn void QTest::keyEvent(KeyAction action, QWidget *widget, Qt::Key key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1) - Sends a Qt key event to \a widget with the given \a key and an associated \a action. Optionally, a keyboard \a modifier can be specified, as well as a \a delay (in milliseconds) of the test before sending the event. + Sends a Qt key event to \a widget with the given \a key and an associated \a action. + Optionally, a keyboard \a modifier can be specified, as well as a \a delay + (in milliseconds) of the test before sending the event. */ /*! \fn void QTest::keyEvent(KeyAction action, QWidget *widget, char ascii, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1) \overload - Sends a Qt key event to \a widget with the given key \a ascii and an associated \a action. Optionally, a keyboard \a modifier can be specified, as well as a \a delay (in milliseconds) of the test before sending the event. + Sends a Qt key event to \a widget with the given key \a ascii and an associated \a action. + Optionally, a keyboard \a modifier can be specified, as well as a \a delay + (in milliseconds) of the test before sending the event. */ /*! \fn void QTest::keyPress(QWidget *widget, Qt::Key key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1) - Simulates pressing a \a key with an optional \a modifier on a \a widget. If \a delay is larger than 0, the test will wait for \a delay milliseconds. + Simulates pressing a \a key with an optional \a modifier on a \a widget. If \a delay + is larger than 0, the test will wait for \a delay milliseconds. \bold {Note:} At some point you should release the key using \l keyRelease(). @@ -453,7 +462,8 @@ QT_BEGIN_NAMESPACE \overload - Simulates pressing a \a key with an optional \a modifier on a \a widget. If \a delay is larger than 0, the test will wait for \a delay milliseconds. + Simulates pressing a \a key with an optional \a modifier on a \a widget. + If \a delay is larger than 0, the test will wait for \a delay milliseconds. \bold {Note:} At some point you should release the key using \l keyRelease(). @@ -462,7 +472,8 @@ QT_BEGIN_NAMESPACE /*! \fn void QTest::keyRelease(QWidget *widget, Qt::Key key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1) - Simulates releasing a \a key with an optional \a modifier on a \a widget. If \a delay is larger than 0, the test will wait for \a delay milliseconds. + Simulates releasing a \a key with an optional \a modifier on a \a widget. + If \a delay is larger than 0, the test will wait for \a delay milliseconds. \sa QTest::keyPress(), QTest::keyClick() */ @@ -471,7 +482,8 @@ QT_BEGIN_NAMESPACE \overload - Simulates releasing a \a key with an optional \a modifier on a \a widget. If \a delay is larger than 0, the test will wait for \a delay milliseconds. + Simulates releasing a \a key with an optional \a modifier on a \a widget. + If \a delay is larger than 0, the test will wait for \a delay milliseconds. \sa QTest::keyClick() */ @@ -687,6 +699,84 @@ QT_BEGIN_NAMESPACE \sa QTest::qSleep() */ +/*! + \class QTest::QTouchEventSequence + \inmodule QtTest + \since 4.6 + + \brief The QTouchEventSequence class is used to simulate a sequence of touch events. + + To simulate a sequence of touch events on a specific device for a widget, call + QTest::touchEvent to create a QTouchEventSequence instance. Add touch events to + the sequence by calling press(), move(), release() and stationary(), and let the + instance run out of scope to commit the sequence to the event system. +*/ + +/*! + \fn QTest::QTouchEventSequence::~QTouchEventSequence() + + Commits this sequence of touch events and frees allocated resources. +*/ + +/*! + \fn QTouchEventSequence &QTest::QTouchEventSequence::press(int touchId, const QPoint &pt, QWidget *widget) + + Adds a press event for touchpoint \a touchId at position \a pt to this sequence and returns + a reference to this QTouchEventSequence. + + The position \a pt is interpreted as relative to \a widget. If \a widget is the null pointer, then + \a pt is interpreted as relative to the widget provided when instantiating this QTouchEventSequence. + + Simulates that the user pressed the touch screen or pad with the finger identified by \a touchId. +*/ + +/*! + \fn QTouchEventSequence &QTest::QTouchEventSequence::move(int touchId, const QPoint &pt, QWidget *widget) + + Adds a move event for touchpoint \a touchId at position \a pt to this sequence and returns + a reference to this QTouchEventSequence. + + The position \a pt is interpreted as relative to \a widget. If \a widget is the null pointer, then + \a pt is interpreted as relative to the widget provided when instantiating this QTouchEventSequence. + + Simulates that the user moved the finger identified by \a touchId. +*/ + +/*! + \fn QTouchEventSequence &QTest::QTouchEventSequence::release(int touchId, const QPoint &pt, QWidget *widget) + + Adds a release event for touchpoint \a touchId at position \a pt to this sequence and returns + a reference to this QTouchEventSequence. + + The position \a pt is interpreted as relative to \a widget. If \a widget is the null pointer, then + \a pt is interpreted as relative to the widget provided when instantiating this QTouchEventSequence. + + Simulates that the user lifted the finger identified by \a touchId. +*/ + +/*! + \fn QTouchEventSequence &QTest::QTouchEventSequence::stationary(int touchId) + + Adds a stationary event for touchpoint \a touchId to this sequence and returns + a reference to this QTouchEventSequence. + + Simulates that the user did not move the finger identified by \a touchId. +*/ + +/*! + \fn QTouchEventSequence QTest::touchEvent(QWidget *widget, QTouchEvent::DeviceType deviceType) + + Creates and returns a QTouchEventSequence for the device \a deviceType to + simulate events for \a widget. + + When adding touch events to the sequence, \a widget will also be used to translate + the position provided to screen coordinates, unless another widget is provided in the + respective calls to press(), move() etc. + + The touch events are committed to the event system when the destructor of the + QTouchEventSequence is called (ie when the object returned runs out of scope). +*/ + namespace QTest { static QObject *currentTestObject = 0; @@ -847,7 +937,7 @@ static void qParseArgs(int argc, char *argv[]) " -iterations n : Sets the number of accumulation iterations.\n" " -median n : Sets the number of median iterations.\n" " -vb : Print out verbose benchmarking information.\n" -#if !defined(QT_NO_PROCESS) || !defined(QT_NO_SETTINGS) +#if !defined(QT_NO_PROCESS) && !defined(QT_NO_SETTINGS) " -chart : Create chart based on the benchmark result.\n" #endif "\n" @@ -963,7 +1053,7 @@ static void qParseArgs(int argc, char *argv[]) } else if (strcmp(argv[i], "-vb") == 0) { QBenchmarkGlobalData::current->verboseOutput = true; -#if !defined(QT_NO_PROCESS) || !defined(QT_NO_SETTINGS) +#if !defined(QT_NO_PROCESS) && !defined(QT_NO_SETTINGS) } else if (strcmp(argv[i], "-chart") == 0) { QBenchmarkGlobalData::current->createChart = true; QTestLog::setLogMode(QTestLog::XML); @@ -1330,6 +1420,80 @@ static void qInvokeTestMethods(QObject *testObject) QTestLog::stopLogging(); } +#ifdef Q_OS_UNIX +class FatalSignalHandler +{ +public: + FatalSignalHandler(); + ~FatalSignalHandler(); + +private: + static void signal(int); + sigset_t handledSignals; +}; + +void FatalSignalHandler::signal(int signum) +{ + qFatal("Received signal %d", signum); +} + +FatalSignalHandler::FatalSignalHandler() +{ + sigemptyset(&handledSignals); + + const int fatalSignals[] = { + SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGFPE, SIGSEGV, SIGPIPE, SIGTERM, 0 }; + + struct sigaction act; + memset(&act, 0, sizeof(act)); + act.sa_handler = FatalSignalHandler::signal; + + // Remove the handler after it is invoked. + act.sa_flags = SA_RESETHAND; + + // Block all fatal signals in our signal handler so we don't try to close + // the testlog twice. + sigemptyset(&act.sa_mask); + for (int i = 0; fatalSignals[i]; ++i) + sigaddset(&act.sa_mask, fatalSignals[i]); + + struct sigaction oldact; + + for (int i = 0; fatalSignals[i]; ++i) { + sigaction(fatalSignals[i], &act, &oldact); + // Don't overwrite any non-default handlers + if (oldact.sa_flags & SA_SIGINFO || oldact.sa_handler != SIG_DFL) { + sigaction(fatalSignals[i], &oldact, 0); + } else { + sigaddset(&handledSignals, fatalSignals[i]); + } + } +} + + +FatalSignalHandler::~FatalSignalHandler() +{ + // Unregister any of our remaining signal handlers + struct sigaction act; + memset(&act, 0, sizeof(act)); + act.sa_handler = SIG_DFL; + + struct sigaction oldact; + + for (int i = 1; i < 32; ++i) { + if (!sigismember(&handledSignals, i)) + continue; + sigaction(i, &act, &oldact); + + // If someone overwrote it in the mean time, put it back + if (oldact.sa_handler != FatalSignalHandler::signal) + sigaction(i, &oldact, 0); + } +} + +#endif + + } // namespace /*! @@ -1424,14 +1588,14 @@ int QTest::qExec(QObject *testObject, int argc, char **argv) QBenchmarkValgrindUtils::cleanup(); - } else { + } else +#endif + { +#ifdef Q_OS_UNIX + FatalSignalHandler handler; #endif - qInvokeTestMethods(testObject); - -#ifdef QTESTLIB_USE_VALGRIND } -#endif #ifndef QT_NO_EXCEPTIONS } catch (...) { @@ -1463,7 +1627,7 @@ int QTest::qExec(QObject *testObject, int argc, char **argv) #endif -#if !defined(QT_NO_PROCESS) || !defined(QT_NO_SETTINGS) +#if !defined(QT_NO_PROCESS) && !defined(QT_NO_SETTINGS) if (QBenchmarkGlobalData::current->createChart) { QString chartLocation = QLibraryInfo::location(QLibraryInfo::BinariesPath); #ifdef Q_OS_WIN @@ -1927,8 +2091,4 @@ bool QTest::compare_string_helper(const char *t1, const char *t2, const char *ac \internal */ -/*! \fn int QTest::qt_snprintf(char *str, int size, const char *format, ...) - \internal -*/ - QT_END_NAMESPACE diff --git a/src/testlib/qtestfilelogger.cpp b/src/testlib/qtestfilelogger.cpp index 0c146b4..a717058 100644 --- a/src/testlib/qtestfilelogger.cpp +++ b/src/testlib/qtestfilelogger.cpp @@ -72,15 +72,24 @@ void QTestFileLogger::init() QTest::qt_snprintf(filename, sizeof(filename), "%s.log", QTestResult::currentTestObjectName()); - #if defined(_MSC_VER) && _MSC_VER >= 1400 && !defined(Q_OS_WINCE) - if (::fopen_s(&QTest::stream, filename, "wt")) { - #else - QTest::stream = ::fopen(filename, "wt"); - if (!QTest::stream) { - #endif - printf("Unable to open file for simple logging: %s", filename); - ::exit(1); + // Keep filenames simple + for (int i = 0; i < sizeof(filename) && filename[i]; ++i) { + char& c = filename[i]; + if (!(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || c == '-' + || c == '.')) { + c = '_'; } + } + +#if defined(_MSC_VER) && _MSC_VER >= 1400 && !defined(Q_OS_WINCE) + if (::fopen_s(&QTest::stream, filename, "wt")) { +#else + QTest::stream = ::fopen(filename, "wt"); + if (!QTest::stream) { +#endif + printf("Unable to open file for simple logging: %s", filename); + ::exit(1); + } } void QTestFileLogger::flush(const char *msg) diff --git a/src/tools/bootstrap/bootstrap.pri b/src/tools/bootstrap/bootstrap.pri index 1cf103b..b4f9b2f 100644 --- a/src/tools/bootstrap/bootstrap.pri +++ b/src/tools/bootstrap/bootstrap.pri @@ -28,26 +28,26 @@ win32:DEFINES += QT_NODLL INCLUDEPATH += $$QT_BUILD_TREE/include \ $$QT_BUILD_TREE/include/QtCore \ $$QT_BUILD_TREE/include/QtXml \ - ../../xml + $$QT_SOURCE_TREE/src/xml DEPENDPATH += $$INCLUDEPATH \ - ../../corelib/global \ - ../../corelib/kernel \ - ../../corelib/tools \ - ../../corelib/io \ - ../../corelib/codecs \ - ../../xml + $$QT_SOURCE_TREE/src/corelib/global \ + $$QT_SOURCE_TREE/src/corelib/kernel \ + $$QT_SOURCE_TREE/src/corelib/tools \ + $$QT_SOURCE_TREE/src/corelib/io \ + $$QT_SOURCE_TREE/src/corelib/codecs \ + $$QT_SOURCE_TREE/src/xml hpux-acc*|hpuxi-acc* { LIBS += ../bootstrap/libbootstrap.a } else { contains(CONFIG, debug_and_release_target) { CONFIG(debug, debug|release) { - LIBS+=-L../bootstrap/debug + LIBS+=-L$$QT_BUILD_TREE/src/tools/bootstrap/debug } else { - LIBS+=-L../bootstrap/release + LIBS+=-L$$QT_BUILD_TREE/src/tools/bootstrap/release } } else { - LIBS += -L../bootstrap + LIBS += -L$$QT_BUILD_TREE/src/tools/bootstrap } LIBS += -lbootstrap } diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp index d2f40ee..38674fb 100644 --- a/src/tools/moc/moc.cpp +++ b/src/tools/moc/moc.cpp @@ -337,11 +337,10 @@ bool Moc::testFunctionAttribute(Token tok, FunctionDef *def) bool Moc::parseFunction(FunctionDef *def, bool inMacro) { def->isVirtual = false; - while (test(INLINE) || test(STATIC) || test(VIRTUAL) - || testFunctionAttribute(def)) { - if (lookup() == VIRTUAL) - def->isVirtual = true; - } + //skip modifiers and attributes + while (test(INLINE) || test(STATIC) || + (test(VIRTUAL) && (def->isVirtual = true)) //mark as virtual + || testFunctionAttribute(def)) {} bool templateFunction = (lookup() == TEMPLATE); def->type = parseType(); if (def->type.name.isEmpty()) { @@ -429,11 +428,10 @@ bool Moc::parseFunction(FunctionDef *def, bool inMacro) bool Moc::parseMaybeFunction(const ClassDef *cdef, FunctionDef *def) { def->isVirtual = false; - while (test(EXPLICIT) || test(INLINE) || test(STATIC) || test(VIRTUAL) - || testFunctionAttribute(def)) { - if (lookup() == VIRTUAL) - def->isVirtual = true; - } + //skip modifiers and attributes + while (test(INLINE) || test(STATIC) || + (test(VIRTUAL) && (def->isVirtual = true)) //mark as virtual + || testFunctionAttribute(def)) {} bool tilde = test(TILDE); def->type = parseType(); if (def->type.name.isEmpty()) @@ -865,7 +863,7 @@ void Moc::parseSignals(ClassDef *def) funcDef.access = FunctionDef::Protected; parseFunction(&funcDef); if (funcDef.isVirtual) - error("Signals cannot be declared virtual"); + warning("Signals cannot be declared virtual"); if (funcDef.inlineCode) error("Not a signal declaration"); def->signalList += funcDef; diff --git a/src/xmlpatterns/Doxyfile b/src/xmlpatterns/Doxyfile index 60a6c77..83f7062 100644 --- a/src/xmlpatterns/Doxyfile +++ b/src/xmlpatterns/Doxyfile @@ -1157,7 +1157,7 @@ DOT_PATH = # contain dot files that are included in the documentation (see the # \dotfile command). -DOTFILE_DIRS = +DOTFILE_DIRS = schema/doc/ # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, which results in a white background. diff --git a/src/xmlpatterns/acceltree/qacceltree.cpp b/src/xmlpatterns/acceltree/qacceltree.cpp index 6111af2..83ea949 100644 --- a/src/xmlpatterns/acceltree/qacceltree.cpp +++ b/src/xmlpatterns/acceltree/qacceltree.cpp @@ -42,6 +42,7 @@ #include <QStack> #include "qabstractxmlreceiver.h" +#include "qabstractxmlnodemodel_p.h" #include "qacceliterators_p.h" #include "qacceltree_p.h" #include "qatomicstring_p.h" @@ -55,6 +56,37 @@ QT_BEGIN_NAMESPACE using namespace QPatternist; +namespace QPatternist { + + class AccelTreePrivate : public QAbstractXmlNodeModelPrivate + { + public: + AccelTreePrivate(AccelTree *accelTree) + : m_accelTree(accelTree) + { + } + + virtual QSourceLocation sourceLocation(const QXmlNodeModelIndex &index) const + { + return m_accelTree->sourceLocation(index); + } + + private: + AccelTree *m_accelTree; + }; +} + +AccelTree::AccelTree(const QUrl &docURI, const QUrl &bURI) + : QAbstractXmlNodeModel(new AccelTreePrivate(this)) + , m_documentURI(docURI) + , m_baseURI(bURI) +{ + /* Pre-allocate at least a little bit. */ + // TODO. Do it according to what an average 4 KB doc contains. + basicData.reserve(100); + data.reserve(30); +} + void AccelTree::printStats(const NamePool::Ptr &np) const { Q_ASSERT(np); @@ -674,6 +706,17 @@ void AccelTree::copyNodeTo(const QXmlNodeModelIndex &node, } +QSourceLocation AccelTree::sourceLocation(const QXmlNodeModelIndex &index) const +{ + const PreNumber key = toPreNumber(index); + if (sourcePositions.contains(key)) { + const QPair<qint64, qint64> position = sourcePositions.value(key); + return QSourceLocation(m_documentURI, position.first, position.second); + } else { + return QSourceLocation(); + } +} + void AccelTree::copyChildren(const QXmlNodeModelIndex &node, QAbstractXmlReceiver *const receiver, const NodeCopySettings &settings) const diff --git a/src/xmlpatterns/acceltree/qacceltree_p.h b/src/xmlpatterns/acceltree/qacceltree_p.h index 38de08c..0c68fab 100644 --- a/src/xmlpatterns/acceltree/qacceltree_p.h +++ b/src/xmlpatterns/acceltree/qacceltree_p.h @@ -91,6 +91,7 @@ namespace QPatternist */ class AccelTree : public QAbstractXmlNodeModel { + friend class AccelTreePrivate; public: using QAbstractXmlNodeModel::createIndex; @@ -99,15 +100,7 @@ namespace QPatternist typedef PreNumber PostNumber; typedef qint8 Depth; - inline AccelTree(const QUrl &docURI, - const QUrl &bURI) : m_documentURI(docURI), - m_baseURI(bURI) - { - /* Pre-allocate at least a little bit. */ - // TODO. Do it according to what an average 4 KB doc contains. - basicData.reserve(100); - data.reserve(30); - } + AccelTree(const QUrl &docURI, const QUrl &bURI); /** * @short Houses data for a node, and that all node kinds have. @@ -280,6 +273,7 @@ namespace QPatternist QHash<PreNumber, QString> data; QVector<BasicNodeData> basicData; + QHash<PreNumber, QPair<qint64, qint64> > sourcePositions; inline QUrl documentUri() const { @@ -381,6 +375,11 @@ namespace QPatternist private: /** + * Returns the source location for the object with the given @p index. + */ + QSourceLocation sourceLocation(const QXmlNodeModelIndex &index) const; + + /** * Copies the children of @p node to @p receiver. */ inline void copyChildren(const QXmlNodeModelIndex &node, diff --git a/src/xmlpatterns/acceltree/qacceltreebuilder.cpp b/src/xmlpatterns/acceltree/qacceltreebuilder.cpp index 63372ac..e58cc92 100644 --- a/src/xmlpatterns/acceltree/qacceltreebuilder.cpp +++ b/src/xmlpatterns/acceltree/qacceltreebuilder.cpp @@ -49,15 +49,17 @@ template <bool FromDocument> AccelTreeBuilder<FromDocument>::AccelTreeBuilder(const QUrl &docURI, const QUrl &baseURI, const NamePool::Ptr &np, - ReportContext *const context) : m_preNumber(-1) - , m_isPreviousAtomic(false) - , m_hasCharacters(false) - , m_isCharactersCompressed(false) - , m_namePool(np) - , m_document(new AccelTree(docURI, baseURI)) - , m_skippedDocumentNodes(0) - , m_documentURI(docURI) - , m_context(context) + ReportContext *const context, + Features features) : m_preNumber(-1) + , m_isPreviousAtomic(false) + , m_hasCharacters(false) + , m_isCharactersCompressed(false) + , m_namePool(np) + , m_document(new AccelTree(docURI, baseURI)) + , m_skippedDocumentNodes(0) + , m_documentURI(docURI) + , m_context(context) + , m_features(features) { Q_ASSERT(m_namePool); @@ -126,9 +128,18 @@ void AccelTreeBuilder<FromDocument>::item(const Item &it) template <bool FromDocument> void AccelTreeBuilder<FromDocument>::startElement(const QXmlName &name) { + startElement(name, 1, 1); +} + +template <bool FromDocument> +void AccelTreeBuilder<FromDocument>::startElement(const QXmlName &name, qint64 line, qint64 column) +{ startStructure(); - m_document->basicData.append(AccelTree::BasicNodeData(currentDepth(), currentParent(), QXmlNodeModelIndex::Element, -1, name)); + AccelTree::BasicNodeData data(currentDepth(), currentParent(), QXmlNodeModelIndex::Element, -1, name); + m_document->basicData.append(data); + if (m_features & SourceLocationsFeature) + m_document->sourcePositions.insert(m_document->maximumPreNumber(), qMakePair(line, column)); ++m_preNumber; m_ancestors.push(m_preNumber); diff --git a/src/xmlpatterns/acceltree/qacceltreebuilder_p.h b/src/xmlpatterns/acceltree/qacceltreebuilder_p.h index 6eb3102..5f6a287 100644 --- a/src/xmlpatterns/acceltree/qacceltreebuilder_p.h +++ b/src/xmlpatterns/acceltree/qacceltreebuilder_p.h @@ -90,15 +90,27 @@ namespace QPatternist typedef QExplicitlySharedDataPointer<AccelTreeBuilder> Ptr; /** + * Describes the memory relevant features the builder shall support. + */ + enum Feature + { + NoneFeature, ///< No special features are enabled. + SourceLocationsFeature = 1 ///< The accel tree builder will store source locations for each start element. + }; + Q_DECLARE_FLAGS(Features, Feature) + + /** * @param context may be @c null. */ AccelTreeBuilder(const QUrl &docURI, const QUrl &baseURI, const NamePool::Ptr &np, - ReportContext *const context); + ReportContext *const context, + Features features = NoneFeature); virtual void startDocument(); virtual void endDocument(); virtual void startElement(const QXmlName &name); + void startElement(const QXmlName &name, qint64 line, qint64 column); virtual void endElement(); virtual void attribute(const QXmlName &name, const QStringRef &value); virtual void characters(const QStringRef &ch); @@ -175,8 +187,13 @@ namespace QPatternist * a member. */ ReportContext *const m_context; + + Features m_features; }; + Q_DECLARE_OPERATORS_FOR_FLAGS(AccelTreeBuilder<true>::Features) + Q_DECLARE_OPERATORS_FOR_FLAGS(AccelTreeBuilder<false>::Features) + #include "qacceltreebuilder.cpp" } diff --git a/src/xmlpatterns/acceltree/qacceltreeresourceloader.cpp b/src/xmlpatterns/acceltree/qacceltreeresourceloader.cpp index d4297fd..8019551 100644 --- a/src/xmlpatterns/acceltree/qacceltreeresourceloader.cpp +++ b/src/xmlpatterns/acceltree/qacceltreeresourceloader.cpp @@ -46,7 +46,6 @@ #include <QtNetwork/QNetworkRequest> -#include "qacceltreebuilder_p.h" #include "qatomicstring_p.h" #include "qautoptr_p.h" #include "qcommonsequencetypes_p.h" @@ -57,14 +56,12 @@ QT_BEGIN_NAMESPACE using namespace QPatternist; -static inline uint qHash(const QUrl &uri) -{ - return qHash(uri.toString()); -} - AccelTreeResourceLoader::AccelTreeResourceLoader(const NamePool::Ptr &np, - const NetworkAccessDelegator::Ptr &manager) : m_namePool(np) - , m_networkAccessDelegator(manager) + const NetworkAccessDelegator::Ptr &manager, + AccelTreeBuilder<true>::Features features) + : m_namePool(np) + , m_networkAccessDelegator(manager) + , m_features(features) { Q_ASSERT(m_namePool); Q_ASSERT(m_networkAccessDelegator); @@ -74,7 +71,7 @@ bool AccelTreeResourceLoader::retrieveDocument(const QUrl &uri, const ReportContext::Ptr &context) { Q_ASSERT(uri.isValid()); - AccelTreeBuilder<true> builder(uri, uri, m_namePool, context.data()); + AccelTreeBuilder<true> builder(uri, uri, m_namePool, context.data(), m_features); const AutoPtr<QNetworkReply> reply(load(uri, m_networkAccessDelegator, context)); @@ -88,18 +85,35 @@ bool AccelTreeResourceLoader::retrieveDocument(const QUrl &uri, return success; } +bool AccelTreeResourceLoader::retrieveDocument(QIODevice *source, const QUrl &documentUri, const ReportContext::Ptr &context) +{ + Q_ASSERT(source); + Q_ASSERT(source->isReadable()); + Q_ASSERT(documentUri.isValid()); + + AccelTreeBuilder<true> builder(documentUri, documentUri, m_namePool, context.data(), m_features); + + bool success = false; + success = streamToReceiver(source, &builder, m_namePool, context, documentUri); + + m_loadedDocuments.insert(documentUri, builder.builtDocument()); + + return success; +} + QNetworkReply *AccelTreeResourceLoader::load(const QUrl &uri, const NetworkAccessDelegator::Ptr &networkDelegator, - const ReportContext::Ptr &context) + const ReportContext::Ptr &context, ErrorHandling errorHandling) { return load(uri, networkDelegator->managerFor(uri), - context); + context, errorHandling); } QNetworkReply *AccelTreeResourceLoader::load(const QUrl &uri, QNetworkAccessManager *const networkManager, - const ReportContext::Ptr &context) + const ReportContext::Ptr &context, ErrorHandling errorHandling) + { Q_ASSERT(networkManager); Q_ASSERT(uri.isValid()); @@ -120,7 +134,7 @@ QNetworkReply *AccelTreeResourceLoader::load(const QUrl &uri, const QSourceLocation location(uri); - if(context) + if(context && (errorHandling == FailOnError)) context->error(errorMessage, ReportContext::FODC0002, location); return 0; @@ -130,7 +144,7 @@ QNetworkReply *AccelTreeResourceLoader::load(const QUrl &uri, } bool AccelTreeResourceLoader::streamToReceiver(QIODevice *const dev, - QAbstractXmlReceiver *const receiver, + AccelTreeBuilder<true> *const receiver, const NamePool::Ptr &np, const ReportContext::Ptr &context, const QUrl &uri) @@ -154,7 +168,7 @@ bool AccelTreeResourceLoader::streamToReceiver(QIODevice *const dev, { /* Send the name. */ receiver->startElement(np->allocateQName(reader.namespaceUri().toString(), reader.name().toString(), - reader.prefix().toString())); + reader.prefix().toString()), reader.lineNumber(), reader.columnNumber()); /* Send namespace declarations. */ const QXmlStreamNamespaceDeclarations &nss = reader.namespaceDeclarations(); @@ -263,6 +277,22 @@ Item AccelTreeResourceLoader::openDocument(const QUrl &uri, } } +Item AccelTreeResourceLoader::openDocument(QIODevice *source, const QUrl &documentUri, + const ReportContext::Ptr &context) +{ + const AccelTree::Ptr doc(m_loadedDocuments.value(documentUri)); + + if(doc) + return doc->root(QXmlNodeModelIndex()); /* Pass in dummy object. We know AccelTree doesn't use it. */ + else + { + if(retrieveDocument(source, documentUri, context)) + return m_loadedDocuments.value(documentUri)->root(QXmlNodeModelIndex()); /* Pass in dummy object. We know AccelTree doesn't use it. */ + else + return Item(); + } +} + SequenceType::Ptr AccelTreeResourceLoader::announceDocument(const QUrl &uri, const Usage) { // TODO deal with the usage thingy diff --git a/src/xmlpatterns/acceltree/qacceltreeresourceloader_p.h b/src/xmlpatterns/acceltree/qacceltreeresourceloader_p.h index a650dfa..f24a88e 100644 --- a/src/xmlpatterns/acceltree/qacceltreeresourceloader_p.h +++ b/src/xmlpatterns/acceltree/qacceltreeresourceloader_p.h @@ -52,12 +52,12 @@ #ifndef Patternist_AccelTreeResourceLoader_H #define Patternist_AccelTreeResourceLoader_H -#include <QtCore/QHash> #include <QtCore/QEventLoop> #include <QtNetwork/QNetworkReply> #include "qabstractxmlreceiver.h" #include "qacceltree_p.h" +#include "qacceltreebuilder_p.h" #include "qdeviceresourceloader_p.h" #include "qnamepool_p.h" #include "qnetworkaccessdelegator_p.h" @@ -115,13 +115,25 @@ namespace QPatternist { public: /** + * Describes the behaviour of the resource loader in case of an + * error. + */ + enum ErrorHandling + { + FailOnError, ///< The resource loader will report the error via the report context. + ContinueOnError ///< The resource loader will report no error and return an empty QNetworkReply. + }; + + /** * AccelTreeResourceLoader does not own @p context. */ AccelTreeResourceLoader(const NamePool::Ptr &np, - const NetworkAccessDelegator::Ptr &networkDelegator); + const NetworkAccessDelegator::Ptr &networkDelegator, AccelTreeBuilder<true>::Features = AccelTreeBuilder<true>::NoneFeature); virtual Item openDocument(const QUrl &uri, const ReportContext::Ptr &context); + virtual Item openDocument(QIODevice *source, const QUrl &documentUri, + const ReportContext::Ptr &context); virtual SequenceType::Ptr announceDocument(const QUrl &uri, const Usage usageHint); virtual bool isDocumentAvailable(const QUrl &uri); @@ -133,7 +145,6 @@ namespace QPatternist const ReportContext::Ptr &context, const SourceLocationReflection *const where); - /** * @short Helper function that do NetworkAccessDelegator::get(), but * does it blocked. @@ -149,14 +160,14 @@ namespace QPatternist */ static QNetworkReply *load(const QUrl &uri, QNetworkAccessManager *const networkManager, - const ReportContext::Ptr &context); + const ReportContext::Ptr &context, ErrorHandling handling = FailOnError); /** * @overload */ static QNetworkReply *load(const QUrl &uri, const NetworkAccessDelegator::Ptr &networkDelegator, - const ReportContext::Ptr &context); + const ReportContext::Ptr &context, ErrorHandling handling = FailOnError); /** * @short Returns the URIs this AccelTreeResourceLoader has loaded @@ -165,14 +176,17 @@ namespace QPatternist virtual QSet<QUrl> deviceURIs() const; virtual void clear(const QUrl &uri); + private: static bool streamToReceiver(QIODevice *const dev, - QAbstractXmlReceiver *const receiver, + AccelTreeBuilder<true> *const receiver, const NamePool::Ptr &np, const ReportContext::Ptr &context, const QUrl &uri); bool retrieveDocument(const QUrl &uri, const ReportContext::Ptr &context); + bool retrieveDocument(QIODevice *source, const QUrl &documentUri, + const ReportContext::Ptr &context); /** * If @p context is @c null, no error reporting should be done. */ @@ -185,6 +199,7 @@ namespace QPatternist const NamePool::Ptr m_namePool; const NetworkAccessDelegator::Ptr m_networkAccessDelegator; QHash<QPair<QUrl, QString>, QString> m_unparsedTexts; + AccelTreeBuilder<true>::Features m_features; }; } diff --git a/src/xmlpatterns/api/api.pri b/src/xmlpatterns/api/api.pri index a0298f2..9fcc2f5 100644 --- a/src/xmlpatterns/api/api.pri +++ b/src/xmlpatterns/api/api.pri @@ -3,11 +3,13 @@ HEADERS += $$PWD/qabstractxmlforwarditerator_p.h \ $$PWD/qabstracturiresolver.h \ $$PWD/qabstractxmlnodemodel.h \ $$PWD/qabstractxmlnodemodel_p.h \ + $$PWD/qabstractxmlpullprovider_p.h \ $$PWD/qabstractxmlreceiver.h \ $$PWD/qabstractxmlreceiver_p.h \ $$PWD/qdeviceresourceloader_p.h \ $$PWD/qiodevicedelegate_p.h \ $$PWD/qnetworkaccessdelegator_p.h \ + $$PWD/qpullbridge_p.h \ $$PWD/qresourcedelegator_p.h \ $$PWD/qsimplexmlnodemodel.h \ $$PWD/qsourcelocation.h \ @@ -20,6 +22,10 @@ HEADERS += $$PWD/qabstractxmlforwarditerator_p.h \ $$PWD/qxmlquery_p.h \ $$PWD/qxmlresultitems.h \ $$PWD/qxmlresultitems_p.h \ + $$PWD/qxmlschema.h \ + $$PWD/qxmlschema_p.h \ + $$PWD/qxmlschemavalidator.h \ + $$PWD/qxmlschemavalidator_p.h \ $$PWD/qxmlserializer.h \ $$PWD/qxmlserializer_p.h \ $$PWD/../../../tools/xmlpatterns/qcoloringmessagehandler_p.h \ @@ -29,9 +35,11 @@ SOURCES += $$PWD/qvariableloader.cpp \ $$PWD/qabstractmessagehandler.cpp \ $$PWD/qabstracturiresolver.cpp \ $$PWD/qabstractxmlnodemodel.cpp \ + $$PWD/qabstractxmlpullprovider.cpp \ $$PWD/qabstractxmlreceiver.cpp \ $$PWD/qiodevicedelegate.cpp \ $$PWD/qnetworkaccessdelegator.cpp \ + $$PWD/qpullbridge.cpp \ $$PWD/qresourcedelegator.cpp \ $$PWD/qsimplexmlnodemodel.cpp \ $$PWD/qsourcelocation.cpp \ @@ -41,6 +49,9 @@ SOURCES += $$PWD/qvariableloader.cpp \ $$PWD/qxmlnamepool.cpp \ $$PWD/qxmlquery.cpp \ $$PWD/qxmlresultitems.cpp \ + $$PWD/qxmlschema.cpp \ + $$PWD/qxmlschema_p.cpp \ + $$PWD/qxmlschemavalidator.cpp \ $$PWD/qxmlserializer.cpp \ $$PWD/../../../tools/xmlpatterns/qcoloringmessagehandler.cpp \ $$PWD/../../../tools/xmlpatterns/qcoloroutput.cpp diff --git a/src/xmlpatterns/api/qabstractxmlforwarditerator_p.h b/src/xmlpatterns/api/qabstractxmlforwarditerator_p.h index d3188d3..b4eefeb 100644 --- a/src/xmlpatterns/api/qabstractxmlforwarditerator_p.h +++ b/src/xmlpatterns/api/qabstractxmlforwarditerator_p.h @@ -55,7 +55,7 @@ #include <QtCore/QList> #include <QtCore/QVector> #include <QtCore/QSharedData> - +#include <QtCore/QString> QT_BEGIN_HEADER @@ -74,6 +74,19 @@ inline bool qIsForwardIteratorEnd(const T &unit) return !unit; } +/** + * @short Helper class for StringSplitter + * + * Needed by the QAbstractXmlForwardIterator sub-class. + * + * @relates StringSplitter + */ +template<> +inline bool qIsForwardIteratorEnd(const QString &unit) +{ + return unit.isNull(); +} + template<typename T> class QAbstractXmlForwardIterator; class QAbstractXmlForwardIteratorPrivate; diff --git a/src/xmlpatterns/api/qabstractxmlnodemodel.cpp b/src/xmlpatterns/api/qabstractxmlnodemodel.cpp index fde2c17..06f03e6 100644 --- a/src/xmlpatterns/api/qabstractxmlnodemodel.cpp +++ b/src/xmlpatterns/api/qabstractxmlnodemodel.cpp @@ -1666,4 +1666,20 @@ void QAbstractXmlNodeModel::copyNodeTo(const QXmlNodeModelIndex &node, "This function is not expected to be called."); } +/*! + Returns the source location for the object with the given \a index + or a default constructed QSourceLocation in case no location + information is available. + + \since 4.6 +*/ +QSourceLocation QAbstractXmlNodeModel::sourceLocation(const QXmlNodeModelIndex &index) const +{ + // TODO: make this method virtual in Qt5 to allow source location support in custom models + if (d_ptr) + return d_ptr->sourceLocation(index); + else + return QSourceLocation(); +} + QT_END_NAMESPACE diff --git a/src/xmlpatterns/api/qabstractxmlnodemodel.h b/src/xmlpatterns/api/qabstractxmlnodemodel.h index 9629f27..3d44547 100644 --- a/src/xmlpatterns/api/qabstractxmlnodemodel.h +++ b/src/xmlpatterns/api/qabstractxmlnodemodel.h @@ -56,6 +56,7 @@ QT_MODULE(XmlPatterns) class QAbstractXmlNodeModel; class QAbstractXmlNodeModelPrivate; class QAbstractXmlReceiver; +class QSourceLocation; class QUrl; class QXmlName; class QXmlNodeModelIndex; @@ -69,6 +70,7 @@ namespace QPatternist class DynamicContext; class Item; class ItemType; + class XsdValidatedXmlNodeModel; template<typename TResult, typename TSource, typename TMapper, typename Context> class ItemMappingIterator; template<typename TResult, typename TSource, typename TMapper> class SequenceMappingIterator; typedef QExplicitlySharedDataPointer<ItemType> ItemTypePtr; @@ -315,6 +317,8 @@ public: QAbstractXmlReceiver *const receiver, const NodeCopySettings &) const; + QSourceLocation sourceLocation(const QXmlNodeModelIndex &index) const; + protected: virtual QXmlNodeModelIndex nextFromSimpleAxis(SimpleAxis axis, const QXmlNodeModelIndex &origin) const = 0; @@ -343,6 +347,7 @@ protected: private: friend class QPatternist::ItemMappingIterator<QXmlNodeModelIndex, QXmlNodeModelIndex, const QAbstractXmlNodeModel *, QExplicitlySharedDataPointer<QPatternist::DynamicContext> >; friend class QPatternist::SequenceMappingIterator<QXmlNodeModelIndex, QXmlNodeModelIndex, const QAbstractXmlNodeModel *>; + friend class QPatternist::XsdValidatedXmlNodeModel; inline QExplicitlySharedDataPointer<QAbstractXmlForwardIterator<QXmlNodeModelIndex> > mapToSequence(const QXmlNodeModelIndex &ni, const QExplicitlySharedDataPointer<QPatternist::DynamicContext> &) const; diff --git a/src/xmlpatterns/api/qabstractxmlnodemodel_p.h b/src/xmlpatterns/api/qabstractxmlnodemodel_p.h index 5d9e0eb..9061616 100644 --- a/src/xmlpatterns/api/qabstractxmlnodemodel_p.h +++ b/src/xmlpatterns/api/qabstractxmlnodemodel_p.h @@ -52,6 +52,9 @@ #ifndef QABSTRACTXMLNODEMODEL_P_H #define QABSTRACTXMLNODEMODEL_P_H +#include "qabstractxmlnodemodel.h" +#include "qsourcelocation.h" + QT_BEGIN_HEADER QT_BEGIN_NAMESPACE @@ -62,6 +65,13 @@ public: virtual ~QAbstractXmlNodeModelPrivate() { } + + virtual QSourceLocation sourceLocation(const QXmlNodeModelIndex &index) const + { + Q_UNUSED(index); + + return QSourceLocation(); + } }; QT_END_NAMESPACE diff --git a/src/xmlpatterns/api/qabstractxmlpullprovider.cpp b/src/xmlpatterns/api/qabstractxmlpullprovider.cpp new file mode 100644 index 0000000..f006988 --- /dev/null +++ b/src/xmlpatterns/api/qabstractxmlpullprovider.cpp @@ -0,0 +1,177 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QHash> + +#include "qxmlname.h" +#include "qnamepool_p.h" +#include "qabstractxmlpullprovider_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +// TODO have example where query selects, and the events for the result are indented + +/*! + \internal + \class AbstractXmlPullProvider + \brief The AbstractXmlPullProvider class provides a pull-based stream interface for the XPath Data Model. + \reentrant + \ingroup xml-tools + + AbstractXmlPullProvider allows a stream of items from the XPath Data Model -- essentially XML -- + to be iterated over. The subclass of AbstractXmlPullProvider provides the events, and the + user calling next() and so on, consumes them. AbstractXmlPullProvider can be considered + a forward-only, non-reversible iterator. + + Note that the content the events describes, are not necessarily a well-formed XML document, but + rather an instance of the XPath Data model, to be specific. For instance, maybe a pull provider + returns two atomic values, followed by an element tree, and at the end two document nodes. + + If you are subclassing AbstractXmlPullProvider, be careful to correctly implement + the behaviors, as described for the individual members and events. + + \sa AbstractXmlPullProvider::Event + */ + +/*! + \enum AbstractXmlPullProvider::Event + \value StartOfInput The value AbstractXmlPullProvider::current() returns before the first call to next(). + \value AtomicValue an atomic value such as an \c xs:integer, \c xs:hexBinary, or \c xs:dateTime. Atomic values + can only be top level items. + \value StartDocument Signals the start of a document node. Note that a AbstractXmlPullProvider can provide + a sequence of document nodes. + \value EndDocument Signals the end of a document node. StartDocument and EndDocument are always balanced + and always top-level events. For instance, StartDocument can never appear after any StartElement + events that hasn't been balanced by the corresponding amount of EndElement events. + \value StartElement Signals an element start tag. + \value EndElement Signals the end of an element. StartElement and EndElement events are always balanced. + \value Text Signals a text node. Adjacent text nodes cannot occur. + \value ProcessingInstruction A processing instruction. Its name is returned from name(), and its value in stringValue(). + \value Comment a comment node. Its value can be retrieved with stingValue(). + \value Attribute Signals an attribute node. Attribute events can only appear after Namespace events, or + if no such are sent, after the StartElement. In addition they must appear sequentially, + and each name must be unique. The ordering of attribute events is undefined and insignificant. + \value Namespace Signals a namespace binding. They occur very infrequently and are not needed for attributes + and elements. Namespace events can only appear after the StartElement event. The + ordering of namespace events is undefined and insignificant. + \value EndOfInput When next() is called after the last event, EndOfInput is returned. + + \sa AbstractXmlPullProvider::current() + */ + +/*! + Constucts a AbstractXmlPullProvider instance. + */ +AbstractXmlPullProvider::AbstractXmlPullProvider() +{ +} + +/*! + Destructs this AbstractXmlPullProvider. + */ +AbstractXmlPullProvider::~AbstractXmlPullProvider() +{ +} + +/*! + \fn Event AbstractXmlPullProvider::next() = 0; + Advances this AbstractXmlPullProvider, and returns the new event. + + \sa current() + */ + +/*! + \fn Event AbstractXmlPullProvider::current() const = 0; + Returns the event that next() returned the last time it was called. It doesn't + alter this AbstractXmlPullProvider. + + current() may not modify this AbstractXmlPullProvider's state. Subsequent calls to current() + must return the same value. + + \sa AbstractXmlPullProvider::Event + */ + +/*! + \fn QName AbstractXmlPullProvider::name() const = 0; + If the current event is StartElement, + EndElement, ProcessingInstruction, Attribute, or Namespace, the node's name is returned. + + If the current event is ProcessingInstruction, + the processing instruction target is in in the local name. + + If the current event is Namespace, the name's namespace URI is the namespace, and + the local name is the prefix the name is binding to. + + In all other cases, an invalid QName is returned. + */ + +/*! + \fn QVariant AbstractXmlPullProvider::atomicValue() const = 0; + + If current() event is AtomicValue, the atomic value is returned as a QVariant. + In all other cases, this function returns a null QVariant. + */ + +/*! + \fn QString AbstractXmlPullProvider::stringValue() const = 0; + + If current() is Text, the text node's value is returned. + + If the current() event is Comment, its value is returned. The subclasser guarantees + it does not contain the string "-->". + + If the current() event is ProcessingInstruction, its data is returned. The subclasser + guarantees the data does not contain the string "?>". + + In other cases, it returns a default constructed string. + */ + +/*! + \fn QHash<QXmlName, QString> AbstractXmlPullProvider::attributes() = 0; + + If the current() is Element, the attributes of the element are returned, + an empty list of attributes otherwise. + */ + +QT_END_NAMESPACE + diff --git a/src/xmlpatterns/api/qabstractxmlpullprovider_p.h b/src/xmlpatterns/api/qabstractxmlpullprovider_p.h new file mode 100644 index 0000000..59dce72 --- /dev/null +++ b/src/xmlpatterns/api/qabstractxmlpullprovider_p.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QABSTRACTXMLPULLPROVIDER_H +#define QABSTRACTXMLPULLPROVIDER_H + +#include <QtCore/QtGlobal> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QXmlItem; +class QXmlName; +class QString; +class QVariant; +template<typename Key, typename Value> class QHash; + +namespace QPatternist +{ + class AbstractXmlPullProviderPrivate; + + class AbstractXmlPullProvider + { + public: + AbstractXmlPullProvider(); + virtual ~AbstractXmlPullProvider(); + + enum Event + { + StartOfInput = 1, + AtomicValue = 1 << 1, + StartDocument = 1 << 2, + EndDocument = 1 << 3, + StartElement = 1 << 4, + EndElement = 1 << 5, + Text = 1 << 6, + ProcessingInstruction = 1 << 7, + Comment = 1 << 8, + Attribute = 1 << 9, + Namespace = 1 << 10, + EndOfInput = 1 << 11 + }; + + virtual Event next() = 0; + virtual Event current() const = 0; + virtual QXmlName name() const = 0; + virtual QVariant atomicValue() const = 0; + virtual QString stringValue() const = 0; + + virtual QHash<QXmlName, QString> attributes() = 0; + virtual QHash<QXmlName, QXmlItem> attributeItems() = 0; + + /* *** The functions below are internal. */ + private: + Q_DISABLE_COPY(AbstractXmlPullProvider) + AbstractXmlPullProviderPrivate *d; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qpullbridge.cpp b/src/xmlpatterns/api/qpullbridge.cpp new file mode 100644 index 0000000..75df519 --- /dev/null +++ b/src/xmlpatterns/api/qpullbridge.cpp @@ -0,0 +1,232 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QVariant> + +#include "qabstractxmlnodemodel_p.h" +#include "qitemmappingiterator_p.h" +#include "qitem_p.h" +#include "qxmlname.h" +#include "qxmlquery_p.h" + +#include "qpullbridge_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +/*! + \brief Bridges a QPatternist::SequenceIterator to QAbstractXmlPullProvider. + \class QPatternist::PullBridge + \internal + \reentrant + \ingroup xml-tools + + The approach of this class is rather straight forward since QPatternist::SequenceIterator + and QAbstractXmlPullProvider are conceptually similar. While QPatternist::SequenceIterator only + delivers top level items(since it's not an event stream, it's a list of items), PullBridge + needs to recursively iterate the children of nodes too, which is achieved through the + stack m_iterators. + */ + +AbstractXmlPullProvider::Event PullBridge::next() +{ + m_index = m_iterators.top().second->next(); + + if(!m_index.isNull()) + { + Item item(m_index); + + if(item && item.isAtomicValue()) + m_current = AtomicValue; + else + { + Q_ASSERT(item.isNode()); + + switch(m_index.kind()) + { + case QXmlNodeModelIndex::Attribute: + { + m_current = Attribute; + break; + } + case QXmlNodeModelIndex::Comment: + { + m_current = Comment; + break; + } + case QXmlNodeModelIndex::Element: + { + m_iterators.push(qMakePair(StartElement, m_index.iterate(QXmlNodeModelIndex::AxisChild))); + m_current = StartElement; + break; + } + case QXmlNodeModelIndex::Document: + { + m_iterators.push(qMakePair(StartDocument, m_index.iterate(QXmlNodeModelIndex::AxisChild))); + m_current = StartDocument; + break; + } + case QXmlNodeModelIndex::Namespace: + { + m_current = Namespace; + break; + } + case QXmlNodeModelIndex::ProcessingInstruction: + { + m_current = ProcessingInstruction; + break; + } + case QXmlNodeModelIndex::Text: + { + m_current = Text; + break; + } + } + } + } + else + { + if(m_iterators.isEmpty()) + m_current = EndOfInput; + else + { + switch(m_iterators.top().first) + { + case StartOfInput: + { + m_current = EndOfInput; + break; + } + case StartElement: + { + m_current = EndElement; + m_iterators.pop(); + break; + } + case StartDocument: + { + m_current = EndDocument; + m_iterators.pop(); + break; + } + default: + { + Q_ASSERT_X(false, Q_FUNC_INFO, + "Invalid value."); + m_current = EndOfInput; + } + } + } + + } + + return m_current; +} + +AbstractXmlPullProvider::Event PullBridge::current() const +{ + return m_current; +} + +QXmlNodeModelIndex PullBridge::index() const +{ + return m_index; +} + +QSourceLocation PullBridge::sourceLocation() const +{ + return m_index.model()->sourceLocation(m_index); +} + +QXmlName PullBridge::name() const +{ + return m_index.name(); +} + +QVariant PullBridge::atomicValue() const +{ + return QVariant(); +} + +QString PullBridge::stringValue() const +{ + return QString(); +} + +QHash<QXmlName, QString> PullBridge::attributes() +{ + Q_ASSERT(m_current == StartElement); + + QHash<QXmlName, QString> attributes; + + QXmlNodeModelIndex::Iterator::Ptr it = m_index.iterate(QXmlNodeModelIndex::AxisAttribute); + QXmlNodeModelIndex index = it->next(); + while (!index.isNull()) { + const Item attribute(index); + attributes.insert(index.name(), index.stringValue()); + + index = it->next(); + } + + return attributes; +} + +QHash<QXmlName, QXmlItem> PullBridge::attributeItems() +{ + Q_ASSERT(m_current == StartElement); + + QHash<QXmlName, QXmlItem> attributes; + + QXmlNodeModelIndex::Iterator::Ptr it = m_index.iterate(QXmlNodeModelIndex::AxisAttribute); + QXmlNodeModelIndex index = it->next(); + while (!index.isNull()) { + const Item attribute(index); + attributes.insert(index.name(), QXmlItem(index)); + + index = it->next(); + } + + return attributes; +} + +QT_END_NAMESPACE + diff --git a/src/xmlpatterns/api/qpullbridge_p.h b/src/xmlpatterns/api/qpullbridge_p.h new file mode 100644 index 0000000..23b9542 --- /dev/null +++ b/src/xmlpatterns/api/qpullbridge_p.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef PATTERNIST_PULLBRIDGE_P_H +#define PATTERNIST_PULLBRIDGE_P_H + +#include <QtCore/QPair> +#include <QtCore/QStack> + +#include "qabstractxmlforwarditerator_p.h" +#include "qabstractxmlpullprovider_p.h" +#include "qitem_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + class PullBridge : public AbstractXmlPullProvider + { + public: + inline PullBridge(const QXmlNodeModelIndex::Iterator::Ptr &it) : m_current(StartOfInput) + { + Q_ASSERT(it); + m_iterators.push(qMakePair(StartOfInput, it)); + } + + virtual Event next(); + virtual Event current() const; + virtual QXmlName name() const; + /** + * Returns always an empty QVariant. + */ + virtual QVariant atomicValue() const; + virtual QString stringValue() const; + virtual QHash<QXmlName, QString> attributes(); + virtual QHash<QXmlName, QXmlItem> attributeItems(); + + QXmlNodeModelIndex index() const; + QSourceLocation sourceLocation() const; + + private: + typedef QStack<QPair<Event, QXmlNodeModelIndex::Iterator::Ptr> > IteratorStack; + IteratorStack m_iterators; + QXmlNodeModelIndex m_index; + Event m_current; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qresourcedelegator.cpp b/src/xmlpatterns/api/qresourcedelegator.cpp index 5a5bcf4..ad93848 100644 --- a/src/xmlpatterns/api/qresourcedelegator.cpp +++ b/src/xmlpatterns/api/qresourcedelegator.cpp @@ -45,14 +45,6 @@ QT_BEGIN_NAMESPACE using namespace QPatternist; -/** - * Duplicated in qacceltreeresourceloader.cpp. - */ -static inline uint qHash(const QUrl &uri) -{ - return qHash(uri.toString()); -} - bool ResourceDelegator::isUnparsedTextAvailable(const QUrl &uri, const QString &encoding) { diff --git a/src/xmlpatterns/api/qxmlnamepool.cpp b/src/xmlpatterns/api/qxmlnamepool.cpp index 5b03975..66eb788 100644 --- a/src/xmlpatterns/api/qxmlnamepool.cpp +++ b/src/xmlpatterns/api/qxmlnamepool.cpp @@ -96,6 +96,10 @@ QXmlNamePool::~QXmlNamePool() { } +QXmlNamePool::QXmlNamePool(QPatternist::NamePool *namePool) : d(QExplicitlySharedDataPointer<QPatternist::NamePool>(namePool)) +{ +} + /*! Assigns the \a other name pool to this one. */ diff --git a/src/xmlpatterns/api/qxmlnamepool.h b/src/xmlpatterns/api/qxmlnamepool.h index 68cf627..6c1fe4f 100644 --- a/src/xmlpatterns/api/qxmlnamepool.h +++ b/src/xmlpatterns/api/qxmlnamepool.h @@ -54,6 +54,8 @@ QT_MODULE(XmlPatterns) namespace QPatternist { class NamePool; + class XsdSchemaParser; + class XsdValidatingInstanceReader; } namespace QPatternistSDK @@ -73,10 +75,15 @@ public: QXmlNamePool &operator=(const QXmlNamePool &other); private: + QXmlNamePool(QPatternist::NamePool *namePool); friend class QXmlQueryPrivate; friend class QXmlQuery; + friend class QXmlSchemaPrivate; + friend class QXmlSchemaValidatorPrivate; friend class QXmlSerializerPrivate; friend class QXmlName; + friend class QPatternist::XsdSchemaParser; + friend class QPatternist::XsdValidatingInstanceReader; friend class QPatternistSDK::Global; QExplicitlySharedDataPointer<QPatternist::NamePool> d; }; diff --git a/src/xmlpatterns/api/qxmlquery.cpp b/src/xmlpatterns/api/qxmlquery.cpp index 3d023a0..79ae7a9 100644 --- a/src/xmlpatterns/api/qxmlquery.cpp +++ b/src/xmlpatterns/api/qxmlquery.cpp @@ -231,6 +231,18 @@ QT_BEGIN_NAMESPACE \value XQuery10 XQuery 1.0. \value XSLT20 XSLT 2.0 + \omitvalue XmlSchema11IdentityConstraintSelector The selector, the restricted + XPath pattern found in W3C XML Schema 1.1 for uniqueness + contraints. Apart from restricting the syntax, the type check stage + for the expression assumes a sequence of nodes to be the focus. + \omitvalue XmlSchema11IdentityConstraintField The field, the restricted + XPath pattern found in W3C XML Schema 1.1 for uniqueness + contraints. Apart from restricting the syntax, the type check stage + for the expression assumes a sequence of nodes to be the focus. + \omitvalue XPath20 Signifies XPath 2.0. Has no effect in the public API, it's + used internally. As With XmlSchema11IdentityConstraintSelector and + XmlSchema11IdentityConstraintField, the type check stage + for the expression assumes a sequence of nodes to be the focus. \sa setQuery() */ @@ -415,7 +427,7 @@ void QXmlQuery::setQuery(QIODevice *sourceCode, const QUrl &documentURI) return; } - d->queryURI = QXmlQueryPrivate::normalizeQueryURI(documentURI); + d->queryURI = QPatternist::XPathHelper::normalizeQueryURI(documentURI); d->expression(sourceCode); } @@ -463,12 +475,12 @@ void QXmlQuery::setQuery(const QUrl &queryURI, const QUrl &baseURI) { Q_ASSERT_X(queryURI.isValid(), Q_FUNC_INFO, "The passed URI must be valid."); - const QUrl canonicalURI(QXmlQueryPrivate::normalizeQueryURI(queryURI)); + const QUrl canonicalURI(QPatternist::XPathHelper::normalizeQueryURI(queryURI)); Q_ASSERT(canonicalURI.isValid()); Q_ASSERT(!canonicalURI.isRelative()); Q_ASSERT(baseURI.isValid() || baseURI.isEmpty()); - d->queryURI = QXmlQueryPrivate::normalizeQueryURI(baseURI.isEmpty() ? queryURI : baseURI); + d->queryURI = QPatternist::XPathHelper::normalizeQueryURI(baseURI.isEmpty() ? queryURI : baseURI); QPatternist::AutoPtr<QIODevice> result; diff --git a/src/xmlpatterns/api/qxmlquery.h b/src/xmlpatterns/api/qxmlquery.h index 4ddfc76..b4ac121 100644 --- a/src/xmlpatterns/api/qxmlquery.h +++ b/src/xmlpatterns/api/qxmlquery.h @@ -71,6 +71,8 @@ namespace QPatternistSDK namespace QPatternist { + class XsdSchemaParser; + class XsdValidatingInstanceReader; class VariableLoader; }; @@ -79,8 +81,11 @@ class Q_XMLPATTERNS_EXPORT QXmlQuery public: enum QueryLanguage { - XQuery10 = 1, - XSLT20 = 2 + XQuery10 = 1, + XSLT20 = 2, + XmlSchema11IdentityConstraintSelector = 1024, + XmlSchema11IdentityConstraintField = 2048, + XPath20 = 4096 }; QXmlQuery(); @@ -136,6 +141,8 @@ private: friend class QXmlName; friend class QXmlSerializer; friend class QPatternistSDK::TestCase; + friend class QPatternist::XsdSchemaParser; + friend class QPatternist::XsdValidatingInstanceReader; friend class QPatternist::VariableLoader; template<typename TInputType> friend bool setFocusHelper(QXmlQuery *const queryInstance, const TInputType &focusValue); diff --git a/src/xmlpatterns/api/qxmlquery_p.h b/src/xmlpatterns/api/qxmlquery_p.h index 05222be..cb2bbad 100644 --- a/src/xmlpatterns/api/qxmlquery_p.h +++ b/src/xmlpatterns/api/qxmlquery_p.h @@ -142,13 +142,10 @@ public: if(!m_functionFactory) { - if(queryLanguage == QXmlQuery::XQuery10) - m_functionFactory = QPatternist::FunctionFactoryCollection::xpath20Factory(namePool.d); - else - { - Q_ASSERT(queryLanguage == QXmlQuery::XSLT20); + if(queryLanguage == QXmlQuery::XSLT20) m_functionFactory = QPatternist::FunctionFactoryCollection::xslt20Factory(namePool.d); - } + else + m_functionFactory = QPatternist::FunctionFactoryCollection::xpath20Factory(namePool.d); } const QPatternist::GenericStaticContext::Ptr genericStaticContext(new QPatternist::GenericStaticContext(namePool.d, @@ -164,6 +161,14 @@ public: if(!contextItem.isNull()) m_staticContext = QPatternist::StaticContext::Ptr(new QPatternist::StaticFocusContext(QPatternist::AtomicValue::qtToXDMType(contextItem), m_staticContext)); + else if( queryLanguage == QXmlQuery::XmlSchema11IdentityConstraintField + || queryLanguage == QXmlQuery::XmlSchema11IdentityConstraintSelector + || queryLanguage == QXmlQuery::XPath20) + m_staticContext = QPatternist::StaticContext::Ptr(new QPatternist::StaticFocusContext(QPatternist::BuiltinTypes::node, m_staticContext)); + + for (int i = 0; i < m_additionalNamespaceBindings.count(); ++i) { + m_staticContext->namespaceBindings()->addBinding(m_additionalNamespaceBindings.at(i)); + } return m_staticContext; } @@ -207,19 +212,6 @@ public: return m_resourceLoader; } - - static inline QUrl normalizeQueryURI(const QUrl &uri) - { - Q_ASSERT_X(uri.isEmpty() || uri.isValid(), Q_FUNC_INFO, - "The URI passed to QXmlQuery::setQuery() must be valid or empty."); - if(uri.isEmpty()) - return QUrl::fromLocalFile(QCoreApplication::applicationFilePath()); - else if(uri.isRelative()) - return QUrl::fromLocalFile(QCoreApplication::applicationFilePath()).resolved(uri); - else - return uri; - } - void setRequiredType(const QPatternist::SequenceType::Ptr &seqType) { Q_ASSERT(seqType); @@ -278,6 +270,11 @@ public: return m_expr; } + inline void addAdditionalNamespaceBinding(const QXmlName &binding) + { + m_additionalNamespaceBindings.append(binding); + } + QXmlNamePool namePool; QPointer<QAbstractMessageHandler> messageHandler; /** @@ -321,6 +318,8 @@ public: QPatternist::SequenceType::Ptr m_requiredType; QPatternist::FunctionFactory::Ptr m_functionFactory; QPatternist::NetworkAccessDelegator::Ptr m_networkAccessDelegator; + + QList<QXmlName> m_additionalNamespaceBindings; }; QT_END_NAMESPACE diff --git a/src/xmlpatterns/api/qxmlschema.cpp b/src/xmlpatterns/api/qxmlschema.cpp new file mode 100644 index 0000000..e64b388 --- /dev/null +++ b/src/xmlpatterns/api/qxmlschema.cpp @@ -0,0 +1,299 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxmlschema.h" +#include "qxmlschema_p.h" + +#include <QtCore/QIODevice> +#include <QtCore/QUrl> + +QT_BEGIN_NAMESPACE + +/*! + \class QXmlSchema + + \brief The QXmlSchema class provides loading and validation of a W3C XML Schema. + + \reentrant + \since 4.6 + \ingroup xml-tools + + The QXmlSchema class loads, compiles and validates W3C XML Schema files + that can be used further for validation of XML instance documents via + \l{QXmlSchemaValidator}. + + The following example shows how to load a XML Schema file from the network + and test whether it is a valid schema document: + + \snippet doc/src/snippets/qxmlschema/main.cpp 0 + + \sa QXmlSchemaValidator, {xmlpatterns/schema}{XML Schema Validation Example} +*/ + +/*! + Constructs an invalid, empty schema that cannot be used until + load() is called. + */ +QXmlSchema::QXmlSchema() + : d(new QXmlSchemaPrivate(QXmlNamePool())) +{ +} + +/*! + Constructs a QXmlSchema that is a copy of \a other. The new + instance will share resources with the existing schema + to the extent possible. + */ +QXmlSchema::QXmlSchema(const QXmlSchema &other) + : d(other.d) +{ +} + +/*! + Destroys this QXmlSchema. + */ +QXmlSchema::~QXmlSchema() +{ +} + +/*! + Sets this QXmlSchema to a schema loaded from the \a source + URI. + + If the schema \l {isValid()} {is invalid}, \c{false} is returned + and the behavior is undefined. + + Example: + + \snippet doc/src/snippets/qxmlschema/main.cpp 0 + + \sa isValid() + */ +bool QXmlSchema::load(const QUrl &source) +{ + d->load(source, QString()); + return d->isValid(); +} + +/*! + Sets this QXmlSchema to a schema read from the \a source + device. The device must have been opened with at least + QIODevice::ReadOnly. + + \a documentUri represents the schema obtained from the \a source + device. It is the base URI of the schema, that is used + internally to resolve relative URIs that appear in the schema, and + for message reporting. + + If \a source is \c null or not readable, or if \a documentUri is not + a valid URI, behavior is undefined. + + If the schema \l {isValid()} {is invalid}, \c{false} is returned + and the behavior is undefined. + + Example: + + \snippet doc/src/snippets/qxmlschema/main.cpp 1 + + \sa isValid() + */ +bool QXmlSchema::load(QIODevice *source, const QUrl &documentUri) +{ + d->load(source, documentUri, QString()); + return d->isValid(); +} + +/*! + Sets this QXmlSchema to a schema read from the \a data + + \a documentUri represents the schema obtained from the \a data. + It is the base URI of the schema, that is used internally to + resolve relative URIs that appear in the schema, and + for message reporting. + + If \a documentUri is not a valid URI, behavior is undefined. + \sa isValid() + + If the schema \l {isValid()} {is invalid}, \c{false} is returned + and the behavior is undefined. + + Example: + + \snippet doc/src/snippets/qxmlschema/main.cpp 2 + + \sa isValid() + */ +bool QXmlSchema::load(const QByteArray &data, const QUrl &documentUri) +{ + d->load(data, documentUri, QString()); + return d->isValid(); +} + +/*! + Returns true if this schema is valid. Examples of invalid schemas + are ones that contain syntax errors or that do not conform the + W3C XML Schema specification. + */ +bool QXmlSchema::isValid() const +{ + return d->isValid(); +} + +/*! + Returns the name pool used by this QXmlSchema for constructing \l + {QXmlName} {names}. There is no setter for the name pool, because + mixing name pools causes errors due to name confusion. + */ +QXmlNamePool QXmlSchema::namePool() const +{ + return d->namePool(); +} + +/*! + Returns the document URI of the schema or an empty URI if no + schema has been set. + */ +QUrl QXmlSchema::documentUri() const +{ + return d->documentUri(); +} + +/*! + Changes the \l {QAbstractMessageHandler}{message handler} for this + QXmlSchema to \a handler. The schema sends all compile and + validation messages to this message handler. QXmlSchema does not take + ownership of \a handler. + + Normally, the default message handler is sufficient. It writes + compile and validation messages to \e stderr. The default message + handler includes color codes if \e stderr can render colors. + + When QXmlSchema calls QAbstractMessageHandler::message(), + the arguments are as follows: + + \table + \header + \o message() argument + \o Semantics + \row + \o QtMsgType type + \o Only QtWarningMsg and QtFatalMsg are used. The former + identifies a warning, while the latter identifies an error. + \row + \o const QString & description + \o An XHTML document which is the actual message. It is translated + into the current language. + \row + \o const QUrl &identifier + \o Identifies the error with a URI, where the fragment is + the error code, and the rest of the URI is the error namespace. + \row + \o const QSourceLocation & sourceLocation + \o Identifies where the error occurred. + \endtable + + */ +void QXmlSchema::setMessageHandler(QAbstractMessageHandler *handler) +{ + d->setMessageHandler(handler); +} + +/*! + Returns the message handler that handles compile and validation + messages for this QXmlSchema. + */ +QAbstractMessageHandler *QXmlSchema::messageHandler() const +{ + return d->messageHandler(); +} + +/*! + Sets the URI resolver to \a resolver. QXmlSchema does not take + ownership of \a resolver. + + \sa uriResolver() + */ +void QXmlSchema::setUriResolver(const QAbstractUriResolver *resolver) +{ + d->setUriResolver(resolver); +} + +/*! + Returns the schema's URI resolver. If no URI resolver has been set, + QtXmlPatterns will use the URIs in schemas as they are. + + The URI resolver provides a level of abstraction, or \e{polymorphic + URIs}. A resolver can rewrite \e{logical} URIs to physical ones, or + it can translate obsolete or invalid URIs to valid ones. + + When QtXmlPatterns calls QAbstractUriResolver::resolve() the + absolute URI is the URI mandated by the schema specification, and the + relative URI is the URI specified by the user. + + \sa setUriResolver() + */ +const QAbstractUriResolver *QXmlSchema::uriResolver() const +{ + return d->uriResolver(); +} + +/*! + Sets the network manager to \a manager. + QXmlSchema does not take ownership of \a manager. + + \sa networkAccessManager() + */ +void QXmlSchema::setNetworkAccessManager(QNetworkAccessManager *manager) +{ + d->setNetworkAccessManager(manager); +} + +/*! + Returns the network manager, or 0 if it has not been set. + + \sa setNetworkAccessManager() + */ +QNetworkAccessManager *QXmlSchema::networkAccessManager() const +{ + return d->networkAccessManager(); +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/api/qxmlschema.h b/src/xmlpatterns/api/qxmlschema.h new file mode 100644 index 0000000..b6ac010 --- /dev/null +++ b/src/xmlpatterns/api/qxmlschema.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXMLSCHEMA_H +#define QXMLSCHEMA_H + +#include <QtCore/QSharedDataPointer> +#include <QtCore/QUrl> +#include <QtXmlPatterns/QXmlNamePool> + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(XmlPatterns) + +class QAbstractMessageHandler; +class QAbstractUriResolver; +class QIODevice; +class QNetworkAccessManager; +class QUrl; +class QXmlNamePool; +class QXmlSchemaPrivate; + +class Q_XMLPATTERNS_EXPORT QXmlSchema +{ + friend class QXmlSchemaValidatorPrivate; + + public: + QXmlSchema(); + QXmlSchema(const QXmlSchema &other); + ~QXmlSchema(); + + bool load(const QUrl &source); + bool load(QIODevice *source, const QUrl &documentUri = QUrl()); + bool load(const QByteArray &data, const QUrl &documentUri = QUrl()); + + bool isValid() const; + + QXmlNamePool namePool() const; + QUrl documentUri() const; + + void setMessageHandler(QAbstractMessageHandler *handler); + QAbstractMessageHandler *messageHandler() const; + + void setUriResolver(const QAbstractUriResolver *resolver); + const QAbstractUriResolver *uriResolver() const; + + void setNetworkAccessManager(QNetworkAccessManager *networkmanager); + QNetworkAccessManager *networkAccessManager() const; + + private: + QSharedDataPointer<QXmlSchemaPrivate> d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qxmlschema_p.cpp b/src/xmlpatterns/api/qxmlschema_p.cpp new file mode 100644 index 0000000..2dad359 --- /dev/null +++ b/src/xmlpatterns/api/qxmlschema_p.cpp @@ -0,0 +1,203 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qacceltreeresourceloader_p.h" +#include "qxmlschema.h" +#include "qxmlschema_p.h" + +#include <QtCore/QBuffer> +#include <QtCore/QIODevice> +#include <QtCore/QUrl> + +QT_BEGIN_NAMESPACE + +QXmlSchemaPrivate::QXmlSchemaPrivate(const QXmlNamePool &namePool) + : m_namePool(namePool) + , m_userMessageHandler(0) + , m_uriResolver(0) + , m_userNetworkAccessManager(0) + , m_schemaContext(new QPatternist::XsdSchemaContext(m_namePool.d)) + , m_schemaParserContext(new QPatternist::XsdSchemaParserContext(m_namePool.d, m_schemaContext)) + , m_schemaIsValid(false) +{ + m_networkAccessManager = new QPatternist::ReferenceCountedValue<QNetworkAccessManager>(new QNetworkAccessManager()); + m_messageHandler = new QPatternist::ReferenceCountedValue<QAbstractMessageHandler>(new QPatternist::ColoringMessageHandler()); +} + +QXmlSchemaPrivate::QXmlSchemaPrivate(const QPatternist::XsdSchemaContext::Ptr &schemaContext) + : m_namePool(QXmlNamePool(schemaContext->namePool().data())) + , m_userMessageHandler(0) + , m_uriResolver(0) + , m_userNetworkAccessManager(0) + , m_schemaContext(schemaContext) + , m_schemaParserContext(new QPatternist::XsdSchemaParserContext(m_namePool.d, m_schemaContext)) + , m_schemaIsValid(false) +{ + m_networkAccessManager = new QPatternist::ReferenceCountedValue<QNetworkAccessManager>(new QNetworkAccessManager()); + m_messageHandler = new QPatternist::ReferenceCountedValue<QAbstractMessageHandler>(new QPatternist::ColoringMessageHandler()); +} + +QXmlSchemaPrivate::QXmlSchemaPrivate(const QXmlSchemaPrivate &other) + : QSharedData(other) +{ + m_namePool = other.m_namePool; + m_userMessageHandler = other.m_userMessageHandler; + m_uriResolver = other.m_uriResolver; + m_userNetworkAccessManager = other.m_userNetworkAccessManager; + m_messageHandler = other.m_messageHandler; + m_networkAccessManager = other.m_networkAccessManager; + + m_schemaContext = other.m_schemaContext; + m_schemaParserContext = other.m_schemaParserContext; + m_schemaIsValid = other.m_schemaIsValid; + m_documentUri = other.m_documentUri; +} + +void QXmlSchemaPrivate::load(const QUrl &source, const QString &targetNamespace) +{ + m_documentUri = QPatternist::XPathHelper::normalizeQueryURI(source); + + m_schemaContext->setMessageHandler(messageHandler()); + m_schemaContext->setUriResolver(uriResolver()); + m_schemaContext->setNetworkAccessManager(networkAccessManager()); + + const QPatternist::AutoPtr<QNetworkReply> reply(QPatternist::AccelTreeResourceLoader::load(source, m_schemaContext->networkAccessManager(), + m_schemaContext, QPatternist::AccelTreeResourceLoader::ContinueOnError)); + if (reply) + load(reply.data(), source, targetNamespace); +} + +void QXmlSchemaPrivate::load(const QByteArray &data, const QUrl &documentUri, const QString &targetNamespace) +{ + QByteArray localData(data); + + QBuffer buffer(&localData); + buffer.open(QIODevice::ReadOnly); + + load(&buffer, documentUri, targetNamespace); +} + +void QXmlSchemaPrivate::load(QIODevice *source, const QUrl &documentUri, const QString &targetNamespace) +{ + m_schemaParserContext = QPatternist::XsdSchemaParserContext::Ptr(new QPatternist::XsdSchemaParserContext(m_namePool.d, m_schemaContext)); + m_schemaIsValid = false; + + if (!source) { + qWarning("A null QIODevice pointer cannot be passed."); + return; + } + + if (!source->isReadable()) { + qWarning("The device must be readable."); + return; + } + + m_documentUri = QPatternist::XPathHelper::normalizeQueryURI(documentUri); + m_schemaContext->setMessageHandler(messageHandler()); + m_schemaContext->setUriResolver(uriResolver()); + m_schemaContext->setNetworkAccessManager(networkAccessManager()); + + QPatternist::XsdSchemaParser parser(m_schemaContext, m_schemaParserContext, source); + parser.setDocumentURI(documentUri); + parser.setTargetNamespace(targetNamespace); + + try { + parser.parse(); + m_schemaParserContext->resolver()->resolve(); + + m_schemaIsValid = true; + } catch (QPatternist::Exception exception) { + m_schemaIsValid = false; + } +} + +bool QXmlSchemaPrivate::isValid() const +{ + return m_schemaIsValid; +} + +QXmlNamePool QXmlSchemaPrivate::namePool() const +{ + return m_namePool; +} + +QUrl QXmlSchemaPrivate::documentUri() const +{ + return m_documentUri; +} + +void QXmlSchemaPrivate::setMessageHandler(QAbstractMessageHandler *handler) +{ + m_userMessageHandler = handler; +} + +QAbstractMessageHandler *QXmlSchemaPrivate::messageHandler() const +{ + if (m_userMessageHandler) + return m_userMessageHandler; + + return m_messageHandler.data()->value; +} + +void QXmlSchemaPrivate::setUriResolver(const QAbstractUriResolver *resolver) +{ + m_uriResolver = resolver; +} + +const QAbstractUriResolver *QXmlSchemaPrivate::uriResolver() const +{ + return m_uriResolver; +} + +void QXmlSchemaPrivate::setNetworkAccessManager(QNetworkAccessManager *networkmanager) +{ + m_userNetworkAccessManager = networkmanager; +} + +QNetworkAccessManager *QXmlSchemaPrivate::networkAccessManager() const +{ + if (m_userNetworkAccessManager) + return m_userNetworkAccessManager; + + return m_networkAccessManager.data()->value; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/api/qxmlschema_p.h b/src/xmlpatterns/api/qxmlschema_p.h new file mode 100644 index 0000000..be2ebb8 --- /dev/null +++ b/src/xmlpatterns/api/qxmlschema_p.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QXMLSCHEMA_P_H +#define QXMLSCHEMA_P_H + +#include "qabstractmessagehandler.h" +#include "qabstracturiresolver.h" +#include "qautoptr_p.h" +#include "qcoloringmessagehandler_p.h" +#include "qreferencecountedvalue_p.h" + +#include "qxsdschemacontext_p.h" +#include "qxsdschemaparser_p.h" +#include "qxsdschemaparsercontext_p.h" + +#include <QtCore/QSharedData> +#include <QtNetwork/QNetworkAccessManager> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QXmlSchemaPrivate : public QSharedData +{ + public: + QXmlSchemaPrivate(const QXmlNamePool &namePool); + QXmlSchemaPrivate(const QPatternist::XsdSchemaContext::Ptr &schemaContext); + QXmlSchemaPrivate(const QXmlSchemaPrivate &other); + + void load(const QUrl &source, const QString &targetNamespace); + void load(QIODevice *source, const QUrl &documentUri, const QString &targetNamespace); + void load(const QByteArray &data, const QUrl &documentUri, const QString &targetNamespace); + bool isValid() const; + QXmlNamePool namePool() const; + QUrl documentUri() const; + void setMessageHandler(QAbstractMessageHandler *handler); + QAbstractMessageHandler *messageHandler() const; + void setUriResolver(const QAbstractUriResolver *resolver); + const QAbstractUriResolver *uriResolver() const; + void setNetworkAccessManager(QNetworkAccessManager *networkmanager); + QNetworkAccessManager *networkAccessManager() const; + + QXmlNamePool m_namePool; + QAbstractMessageHandler* m_userMessageHandler; + const QAbstractUriResolver* m_uriResolver; + QNetworkAccessManager* m_userNetworkAccessManager; + QPatternist::ReferenceCountedValue<QAbstractMessageHandler>::Ptr m_messageHandler; + QPatternist::ReferenceCountedValue<QNetworkAccessManager>::Ptr m_networkAccessManager; + + QPatternist::XsdSchemaContext::Ptr m_schemaContext; + QPatternist::XsdSchemaParserContext::Ptr m_schemaParserContext; + bool m_schemaIsValid; + QUrl m_documentUri; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qxmlschemavalidator.cpp b/src/xmlpatterns/api/qxmlschemavalidator.cpp new file mode 100644 index 0000000..a864d40 --- /dev/null +++ b/src/xmlpatterns/api/qxmlschemavalidator.cpp @@ -0,0 +1,344 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxmlschemavalidator.h" +#include "qxmlschemavalidator_p.h" + +#include "qacceltreeresourceloader_p.h" +#include "qxmlschema.h" +#include "qxmlschema_p.h" +#include "qxsdvalidatinginstancereader_p.h" + +#include <QtCore/QBuffer> +#include <QtCore/QIODevice> +#include <QtCore/QUrl> + +QT_BEGIN_NAMESPACE + +/*! + \class QXmlSchemaValidator + + \brief The QXmlSchemaValidator class validates XML instance documents against a W3C XML Schema. + + \reentrant + \since 4.6 + \ingroup xml-tools + + The QXmlSchemaValidator class loads, parses an XML instance document and validates it + against a W3C XML Schema that has been compiled with \l{QXmlSchema}. + + The following example shows how to load a XML Schema from a local + file, check whether it is a valid schema document and use it for validation + of an XML instance document: + + \snippet doc/src/snippets/qxmlschemavalidator/main.cpp 3 + + \sa QXmlSchema, {xmlpatterns/schema}{XML Schema Validation Example} +*/ + +/*! + Constructs a schema validator. + The schema used for validation must be referenced in the XML instance document + via the \c xsi:schemaLocation or \c xsi:noNamespaceSchemaLocation attribute. + */ +QXmlSchemaValidator::QXmlSchemaValidator() + : d(new QXmlSchemaValidatorPrivate(QXmlSchema())) +{ +} + +/*! + Constructs a schema validator that will use \a schema for validation. + If an empty \l {QXmlSchema} schema is passed to the validator, the schema used + for validation must be referenced in the XML instance document + via the \c xsi:schemaLocation or \c xsi:noNamespaceSchemaLocation attribute. + */ +QXmlSchemaValidator::QXmlSchemaValidator(const QXmlSchema &schema) + : d(new QXmlSchemaValidatorPrivate(schema)) +{ +} + +/*! + Destroys this QXmlSchemaValidator. + */ +QXmlSchemaValidator::~QXmlSchemaValidator() +{ + delete d; +} + +/*! + Sets the \a schema that shall be used for further validation. + If the schema is empty, the schema used for validation must be referenced + in the XML instance document via the \c xsi:schemaLocation or + \c xsi:noNamespaceSchemaLocation attribute. + */ +void QXmlSchemaValidator::setSchema(const QXmlSchema &schema) +{ + d->setSchema(schema); +} + +/*! + Validates the XML instance document read from \a data with the + given \a documentUri against the schema. + + Returns \c true if the XML instance document is valid according to the + schema, \c false otherwise. + + Example: + + \snippet doc/src/snippets/qxmlschemavalidator/main.cpp 2 + */ +bool QXmlSchemaValidator::validate(const QByteArray &data, const QUrl &documentUri) const +{ + QByteArray localData(data); + + QBuffer buffer(&localData); + buffer.open(QIODevice::ReadOnly); + + return validate(&buffer, documentUri); +} + +/*! + Validates the XML instance document read from \a source against the schema. + + Returns \c true if the XML instance document is valid according to the + schema, \c false otherwise. + + Example: + + \snippet doc/src/snippets/qxmlschemavalidator/main.cpp 0 + */ +bool QXmlSchemaValidator::validate(const QUrl &source) const +{ + d->m_context->setMessageHandler(messageHandler()); + d->m_context->setUriResolver(uriResolver()); + d->m_context->setNetworkAccessManager(networkAccessManager()); + + const QPatternist::AutoPtr<QNetworkReply> reply(QPatternist::AccelTreeResourceLoader::load(source, d->m_context->networkAccessManager(), + d->m_context, QPatternist::AccelTreeResourceLoader::ContinueOnError)); + if (reply) + return validate(reply.data(), source); + else + return false; +} + +/*! + Validates the XML instance document read from \a source with the + given \a documentUri against the schema. + + Returns \c true if the XML instance document is valid according to the + schema, \c false otherwise. + + Example: + + \snippet doc/src/snippets/qxmlschemavalidator/main.cpp 1 + */ +bool QXmlSchemaValidator::validate(QIODevice *source, const QUrl &documentUri) const +{ + if (!source) { + qWarning("A null QIODevice pointer cannot be passed."); + return false; + } + + if (!source->isReadable()) { + qWarning("The device must be readable."); + return false; + } + + const QUrl normalizedUri = QPatternist::XPathHelper::normalizeQueryURI(documentUri); + + d->m_context->setMessageHandler(messageHandler()); + d->m_context->setUriResolver(uriResolver()); + d->m_context->setNetworkAccessManager(networkAccessManager()); + + QPatternist::NetworkAccessDelegator::Ptr delegator(new QPatternist::NetworkAccessDelegator(d->m_context->networkAccessManager(), + d->m_context->networkAccessManager())); + + QPatternist::AccelTreeResourceLoader loader(d->m_context->namePool(), delegator, QPatternist::AccelTreeBuilder<true>::SourceLocationsFeature); + + QPatternist::Item item; + try { + item = loader.openDocument(source, normalizedUri, d->m_context); + } catch (QPatternist::Exception exception) { + return false; + } + + QXmlNodeModelIndex index = item.asNode(); + const QAbstractXmlNodeModel *model = item.asNode().model(); + + QPatternist::XsdValidatedXmlNodeModel *validatedModel = new QPatternist::XsdValidatedXmlNodeModel(model); + + QPatternist::XsdValidatingInstanceReader reader(validatedModel, normalizedUri, d->m_context); + if (d->m_schema) + reader.addSchema(d->m_schema, d->m_schemaDocumentUri); + try { + reader.read(); + } catch (QPatternist::Exception exception) { + return false; + } + + return true; +} + +/*! + Returns the name pool used by this QXmlSchemaValidator for constructing \l + {QXmlName} {names}. There is no setter for the name pool, because + mixing name pools causes errors due to name confusion. + */ +QXmlNamePool QXmlSchemaValidator::namePool() const +{ + return d->m_namePool; +} + +/*! + Returns the schema that is used for validation. + */ +QXmlSchema QXmlSchemaValidator::schema() const +{ + return d->m_originalSchema; +} + +/*! + Changes the \l {QAbstractMessageHandler}{message handler} for this + QXmlSchemaValidator to \a handler. The schema validator sends all parsing and + validation messages to this message handler. QXmlSchemaValidator does not take + ownership of \a handler. + + Normally, the default message handler is sufficient. It writes + compile and validation messages to \e stderr. The default message + handler includes color codes if \e stderr can render colors. + + When QXmlSchemaValidator calls QAbstractMessageHandler::message(), + the arguments are as follows: + + \table + \header + \o message() argument + \o Semantics + \row + \o QtMsgType type + \o Only QtWarningMsg and QtFatalMsg are used. The former + identifies a warning, while the latter identifies an error. + \row + \o const QString & description + \o An XHTML document which is the actual message. It is translated + into the current language. + \row + \o const QUrl &identifier + \o Identifies the error with a URI, where the fragment is + the error code, and the rest of the URI is the error namespace. + \row + \o const QSourceLocation & sourceLocation + \o Identifies where the error occurred. + \endtable + + */ +void QXmlSchemaValidator::setMessageHandler(QAbstractMessageHandler *handler) +{ + d->m_userMessageHandler = handler; +} + +/*! + Returns the message handler that handles parsing and validation + messages for this QXmlSchemaValidator. + */ +QAbstractMessageHandler *QXmlSchemaValidator::messageHandler() const +{ + if (d->m_userMessageHandler) + return d->m_userMessageHandler; + + return d->m_messageHandler.data()->value; +} + +/*! + Sets the URI resolver to \a resolver. QXmlSchemaValidator does not take + ownership of \a resolver. + + \sa uriResolver() + */ +void QXmlSchemaValidator::setUriResolver(const QAbstractUriResolver *resolver) +{ + d->m_uriResolver = resolver; +} + +/*! + Returns the schema's URI resolver. If no URI resolver has been set, + QtXmlPatterns will use the URIs in instance documents as they are. + + The URI resolver provides a level of abstraction, or \e{polymorphic + URIs}. A resolver can rewrite \e{logical} URIs to physical ones, or + it can translate obsolete or invalid URIs to valid ones. + + When QtXmlPatterns calls QAbstractUriResolver::resolve() the + absolute URI is the URI mandated by the schema specification, and the + relative URI is the URI specified by the user. + + \sa setUriResolver() + */ +const QAbstractUriResolver *QXmlSchemaValidator::uriResolver() const +{ + return d->m_uriResolver; +} + +/*! + Sets the network manager to \a manager. + QXmlSchemaValidator does not take ownership of \a manager. + + \sa networkAccessManager() + */ +void QXmlSchemaValidator::setNetworkAccessManager(QNetworkAccessManager *manager) +{ + d->m_userNetworkAccessManager = manager; +} + +/*! + Returns the network manager, or 0 if it has not been set. + + \sa setNetworkAccessManager() + */ +QNetworkAccessManager *QXmlSchemaValidator::networkAccessManager() const +{ + if (d->m_userNetworkAccessManager) + return d->m_userNetworkAccessManager; + + return d->m_networkAccessManager.data()->value; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/api/qxmlschemavalidator.h b/src/xmlpatterns/api/qxmlschemavalidator.h new file mode 100644 index 0000000..f32ac07 --- /dev/null +++ b/src/xmlpatterns/api/qxmlschemavalidator.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXMLSCHEMAVALIDATOR_H +#define QXMLSCHEMAVALIDATOR_H + +#include <QtCore/QUrl> +#include <QtXmlPatterns/QXmlNamePool> + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(XmlPatterns) + +class QAbstractMessageHandler; +class QAbstractUriResolver; +class QIODevice; +class QNetworkAccessManager; +class QUrl; +class QXmlNamePool; +class QXmlSchema; +class QXmlSchemaValidatorPrivate; + +class Q_XMLPATTERNS_EXPORT QXmlSchemaValidator +{ + public: + QXmlSchemaValidator(); + QXmlSchemaValidator(const QXmlSchema &schema); + ~QXmlSchemaValidator(); + + void setSchema(const QXmlSchema &schema); + + bool validate(const QUrl &source) const; + bool validate(QIODevice *source, const QUrl &documentUri = QUrl()) const; + bool validate(const QByteArray &data, const QUrl &documentUri = QUrl()) const; + + QXmlNamePool namePool() const; + QXmlSchema schema() const; + + void setMessageHandler(QAbstractMessageHandler *handler); + QAbstractMessageHandler *messageHandler() const; + + void setUriResolver(const QAbstractUriResolver *resolver); + const QAbstractUriResolver *uriResolver() const; + + void setNetworkAccessManager(QNetworkAccessManager *networkmanager); + QNetworkAccessManager *networkAccessManager() const; + + private: + QXmlSchemaValidatorPrivate* const d; + + Q_DISABLE_COPY(QXmlSchemaValidator) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qxmlschemavalidator_p.h b/src/xmlpatterns/api/qxmlschemavalidator_p.h new file mode 100644 index 0000000..40dbefc --- /dev/null +++ b/src/xmlpatterns/api/qxmlschemavalidator_p.h @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QXMLSCHEMAVALIDATOR_P_H +#define QXMLSCHEMAVALIDATOR_P_H + +#include "qabstractmessagehandler.h" +#include "qabstracturiresolver.h" +#include "qautoptr_p.h" +#include "qcoloringmessagehandler_p.h" +#include "qxmlschema.h" +#include "qxmlschema_p.h" + +#include "qxsdschemacontext_p.h" +#include "qxsdschema_p.h" + +#include <QtNetwork/QNetworkAccessManager> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QXmlSchemaValidatorPrivate +{ +public: + QXmlSchemaValidatorPrivate(const QXmlSchema &schema) + : m_namePool(schema.namePool()) + , m_userMessageHandler(0) + , m_uriResolver(0) + , m_userNetworkAccessManager(0) + { + setSchema(schema); + + const QXmlSchemaPrivate *p = schema.d; + + // initialize the environment properties with the ones from the schema + + if (p->m_userNetworkAccessManager) // schema has user defined network access manager + m_userNetworkAccessManager = p->m_userNetworkAccessManager; + else + m_networkAccessManager = p->m_networkAccessManager; + + if (p->m_userMessageHandler) // schema has user defined message handler + m_userMessageHandler = p->m_userMessageHandler; + else + m_messageHandler = p->m_messageHandler; + + m_uriResolver = p->m_uriResolver; + } + + void setSchema(const QXmlSchema &schema) + { + // use same name pool as the schema + m_namePool = schema.namePool(); + m_schema = schema.d->m_schemaParserContext->schema(); + m_schemaDocumentUri = schema.documentUri(); + + // create a new schema context + m_context = QPatternist::XsdSchemaContext::Ptr(new QPatternist::XsdSchemaContext(m_namePool.d)); + m_context->m_schemaTypeFactory = schema.d->m_schemaContext->m_schemaTypeFactory; + m_context->m_builtinTypesFacetList = schema.d->m_schemaContext->m_builtinTypesFacetList; + + m_originalSchema = schema; + } + + QXmlNamePool m_namePool; + QAbstractMessageHandler* m_userMessageHandler; + const QAbstractUriResolver* m_uriResolver; + QNetworkAccessManager* m_userNetworkAccessManager; + QPatternist::ReferenceCountedValue<QAbstractMessageHandler>::Ptr m_messageHandler; + QPatternist::ReferenceCountedValue<QNetworkAccessManager>::Ptr m_networkAccessManager; + + QXmlSchema m_originalSchema; + QPatternist::XsdSchemaContext::Ptr m_context; + QPatternist::XsdSchema::Ptr m_schema; + QUrl m_schemaDocumentUri; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/common.pri b/src/xmlpatterns/common.pri index 2573a26..27253d8 100644 --- a/src/xmlpatterns/common.pri +++ b/src/xmlpatterns/common.pri @@ -10,6 +10,7 @@ INCLUDEPATH += $$PWD/acceltree \ $$PWD/iterators \ $$PWD/janitors \ $$PWD/parser \ + $$PWD/schema \ $$PWD/type \ $$PWD/utils diff --git a/src/xmlpatterns/data/data.pri b/src/xmlpatterns/data/data.pri index 99591d4..ccfed42 100644 --- a/src/xmlpatterns/data/data.pri +++ b/src/xmlpatterns/data/data.pri @@ -1,8 +1,8 @@ HEADERS += $$PWD/qabstractdatetime_p.h \ $$PWD/qabstractduration_p.h \ $$PWD/qabstractfloatcasters_p.h \ - $$PWD/qabstractfloat_p.h \ $$PWD/qabstractfloatmathematician_p.h \ + $$PWD/qabstractfloat_p.h \ $$PWD/qanyuri_p.h \ $$PWD/qatomiccaster_p.h \ $$PWD/qatomiccasters_p.h \ @@ -14,8 +14,8 @@ HEADERS += $$PWD/qabstractdatetime_p.h \ $$PWD/qbase64binary_p.h \ $$PWD/qboolean_p.h \ $$PWD/qcommonvalues_p.h \ + $$PWD/qcomparisonfactory_p.h \ $$PWD/qdate_p.h \ - $$PWD/qschemadatetime_p.h \ $$PWD/qdaytimeduration_p.h \ $$PWD/qdecimal_p.h \ $$PWD/qderivedinteger_p.h \ @@ -24,19 +24,21 @@ HEADERS += $$PWD/qabstractdatetime_p.h \ $$PWD/qgday_p.h \ $$PWD/qgmonthday_p.h \ $$PWD/qgmonth_p.h \ - $$PWD/qgyear_p.h \ $$PWD/qgyearmonth_p.h \ + $$PWD/qgyear_p.h \ $$PWD/qhexbinary_p.h \ $$PWD/qinteger_p.h \ $$PWD/qitem_p.h \ $$PWD/qnodebuilder_p.h \ - $$PWD/qschemanumeric_p.h \ $$PWD/qqnamevalue_p.h \ $$PWD/qresourceloader_p.h \ - $$PWD/qsorttuple.cpp \ + $$PWD/qschemadatetime_p.h \ + $$PWD/qschemanumeric_p.h \ $$PWD/qschematime_p.h \ + $$PWD/qsorttuple.cpp \ $$PWD/quntypedatomic_p.h \ $$PWD/qvalidationerror_p.h \ + $$PWD/qvaluefactory_p.h \ $$PWD/qyearmonthduration_p.h SOURCES += $$PWD/qabstractdatetime.cpp \ @@ -53,8 +55,8 @@ SOURCES += $$PWD/qabstractdatetime.cpp \ $$PWD/qbase64binary.cpp \ $$PWD/qboolean.cpp \ $$PWD/qcommonvalues.cpp \ + $$PWD/qcomparisonfactory.cpp \ $$PWD/qdate.cpp \ - $$PWD/qschemadatetime.cpp \ $$PWD/qdaytimeduration.cpp \ $$PWD/qdecimal.cpp \ $$PWD/qduration.cpp \ @@ -68,11 +70,13 @@ SOURCES += $$PWD/qabstractdatetime.cpp \ $$PWD/qitem.cpp \ $$PWD/qnodebuilder.cpp \ $$PWD/qnodemodel.cpp \ - $$PWD/qschemanumeric.cpp \ $$PWD/qqnamevalue.cpp \ $$PWD/qresourceloader.cpp \ - $$PWD/qsorttuple.cpp \ + $$PWD/qschemadatetime.cpp \ + $$PWD/qschemanumeric.cpp \ $$PWD/qschematime.cpp \ + $$PWD/qsorttuple.cpp \ $$PWD/quntypedatomic.cpp \ $$PWD/qvalidationerror.cpp \ + $$PWD/qvaluefactory.cpp \ $$PWD/qyearmonthduration.cpp diff --git a/src/xmlpatterns/data/qboolean.cpp b/src/xmlpatterns/data/qboolean.cpp index 07562fd..bb4ece1 100644 --- a/src/xmlpatterns/data/qboolean.cpp +++ b/src/xmlpatterns/data/qboolean.cpp @@ -76,7 +76,7 @@ bool Boolean::evaluateEBV(const Item &first, { Q_ASSERT(context); context->error(QtXmlPatterns::tr("Effective Boolean Value cannot be calculated for a sequence " - "containing two or more atomic values."), + "containing two or more atomic values."), ReportContext::FORG0006, QSourceLocation()); return false; diff --git a/src/xmlpatterns/data/qcomparisonfactory.cpp b/src/xmlpatterns/data/qcomparisonfactory.cpp new file mode 100644 index 0000000..c22d9e7 --- /dev/null +++ b/src/xmlpatterns/data/qcomparisonfactory.cpp @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qatomiccomparators_p.h" +#include "qatomicstring_p.h" +#include "qcomparisonplatform_p.h" +#include "qvaluefactory_p.h" + +#include "qcomparisonfactory_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +/** + * @short Helper class for ComparisonFactory::fromLexical() which exposes + * CastingPlatform appropriately. + * + * @relates ComparisonFactory + */ +class PerformComparison : public ComparisonPlatform<PerformComparison, true> + , public SourceLocationReflection +{ +public: + PerformComparison(const SourceLocationReflection *const sourceLocationReflection, + const AtomicComparator::Operator op) : m_sourceReflection(sourceLocationReflection) + , m_operator(op) + { + Q_ASSERT(m_sourceReflection); + } + + bool operator()(const AtomicValue::Ptr &operand1, + const AtomicValue::Ptr &operand2, + const SchemaType::Ptr &type, + const ReportContext::Ptr &context) + { + const ItemType::Ptr asItemType((AtomicType::Ptr(type))); + + /* One area where the Query Transform world differs from the Schema + * world is that @c xs:duration is not considedered comparable, because + * it's according to Schema is partially comparable. This means + * ComparisonPlatform::fetchComparator() flags it as impossible, and + * hence we need to override that. + * + * SchemaType::wxsTypeMatches() will return true for sub-types of @c + * xs:duration as well, but that's ok since AbstractDurationComparator + * works for them too. */ + if(BuiltinTypes::xsDuration->wxsTypeMatches(type)) + prepareComparison(AtomicComparator::Ptr(new AbstractDurationComparator())); + else if (BuiltinTypes::xsGYear->wxsTypeMatches(type) || + BuiltinTypes::xsGYearMonth->wxsTypeMatches(type) || + BuiltinTypes::xsGMonth->wxsTypeMatches(type) || + BuiltinTypes::xsGMonthDay->wxsTypeMatches(type) || + BuiltinTypes::xsGDay->wxsTypeMatches(type)) + prepareComparison(AtomicComparator::Ptr(new AbstractDateTimeComparator())); + else + prepareComparison(fetchComparator(asItemType, asItemType, context)); + + return flexibleCompare(operand1, operand2, context); + } + + const SourceLocationReflection *actualReflection() const + { + return m_sourceReflection; + } + + AtomicComparator::Operator operatorID() const + { + return m_operator; + } + +private: + const SourceLocationReflection *const m_sourceReflection; + const AtomicComparator::Operator m_operator; +}; + +bool ComparisonFactory::compare(const AtomicValue::Ptr &operand1, + const AtomicComparator::Operator op, + const AtomicValue::Ptr &operand2, + const SchemaType::Ptr &type, + const ReportContext::Ptr &context, + const SourceLocationReflection *const sourceLocationReflection) +{ + Q_ASSERT(operand1); + Q_ASSERT(operand2); + Q_ASSERT(context); + Q_ASSERT(sourceLocationReflection); + Q_ASSERT(type); + Q_ASSERT_X(type->category() == SchemaType::SimpleTypeAtomic, Q_FUNC_INFO, + "We can only compare atomic values."); + + return PerformComparison(sourceLocationReflection, op)(operand1, operand2, type, context); +} + +bool ComparisonFactory::constructAndCompare(const DerivedString<TypeString>::Ptr &operand1, + const AtomicComparator::Operator op, + const DerivedString<TypeString>::Ptr &operand2, + const SchemaType::Ptr &type, + const ReportContext::Ptr &context, + const SourceLocationReflection *const sourceLocationReflection) +{ + Q_ASSERT(operand1); + Q_ASSERT(operand2); + Q_ASSERT(context); + Q_ASSERT(sourceLocationReflection); + Q_ASSERT(type); + Q_ASSERT_X(type->category() == SchemaType::SimpleTypeAtomic, Q_FUNC_INFO, + "We can only compare atomic values."); + + const AtomicValue::Ptr value1 = ValueFactory::fromLexical(operand1->stringValue(), type, context, sourceLocationReflection); + const AtomicValue::Ptr value2 = ValueFactory::fromLexical(operand2->stringValue(), type, context, sourceLocationReflection); + + return compare(value1, op, value2, type, context, sourceLocationReflection); +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/data/qcomparisonfactory_p.h b/src/xmlpatterns/data/qcomparisonfactory_p.h new file mode 100644 index 0000000..1234548 --- /dev/null +++ b/src/xmlpatterns/data/qcomparisonfactory_p.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_ComparisonFactory_H +#define Patternist_ComparisonFactory_H + +#include "qatomiccomparator_p.h" +#include "qderivedstring_p.h" +#include "qitem_p.h" +#include "qreportcontext_p.h" +#include "qschematype_p.h" + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short Provides compare(), which is a high-level helper function for + * comparing atomic values. + * + * This class wraps the helper class ComparisonPlatform with a more specific, + * high-level API. + * + * @see ComparisonPlatform + * @author Frans Englich <fenglich@trolltech.com> + * @ingroup Patternist_schema + */ + class ComparisonFactory + { + public: + /** + * @short Returns the result of evaluating operator @p op applied to the atomic + * values @p operand1 and @p operand2. + * + * The caller guarantees that both values are of type @p type. + * + * ComparisonFactory does not take ownership of @p sourceLocationReflection. + */ + static bool compare(const AtomicValue::Ptr &operand1, + const AtomicComparator::Operator op, + const AtomicValue::Ptr &operand2, + const SchemaType::Ptr &type, + const ReportContext::Ptr &context, + const SourceLocationReflection *const sourceLocationReflection); + + /** + * @short Returns the result of evaluating operator @p op applied to the atomic + * values @p operand1 and @p operand2. + * + * In opposite to compare() it converts the operands from string type + * to @p type and compares these constructed types. + * + * The caller guarantees that both values are of type @p type. + * + * ComparisonFactory does not take ownership of @p sourceLocationReflection. + */ + static bool constructAndCompare(const DerivedString<TypeString>::Ptr &operand1, + const AtomicComparator::Operator op, + const DerivedString<TypeString>::Ptr &operand2, + const SchemaType::Ptr &type, + const ReportContext::Ptr &context, + const SourceLocationReflection *const sourceLocationReflection); + + private: + Q_DISABLE_COPY(ComparisonFactory) + }; +} + +QT_END_NAMESPACE +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/data/qitem_p.h b/src/xmlpatterns/data/qitem_p.h index 1f50072..60c8510 100644 --- a/src/xmlpatterns/data/qitem_p.h +++ b/src/xmlpatterns/data/qitem_p.h @@ -128,6 +128,11 @@ namespace QPatternist typedef QExplicitlySharedDataPointer<AtomicValue> Ptr; /** + * A list if smart pointers wrapping AtomicValue instances. + */ + typedef QList<AtomicValue::Ptr> List; + + /** * Determines whether this atomic value has an error. This is used * for implementing casting. * diff --git a/src/xmlpatterns/data/qvaluefactory.cpp b/src/xmlpatterns/data/qvaluefactory.cpp new file mode 100644 index 0000000..63307c2 --- /dev/null +++ b/src/xmlpatterns/data/qvaluefactory.cpp @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qatomiccaster_p.h" +#include "qatomicstring_p.h" +#include "qcastingplatform_p.h" +#include "qvaluefactory_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +/** + * @short Helper class for ValueFactory::fromLexical() which exposes + * CastingPlatform appropriately. + * + * @relates ValueFactory + */ +class PerformValueConstruction : public CastingPlatform<PerformValueConstruction, false> + , public SourceLocationReflection +{ +public: + PerformValueConstruction(const SourceLocationReflection *const sourceLocationReflection, + const SchemaType::Ptr &toType) : m_sourceReflection(sourceLocationReflection) + , m_targetType(AtomicType::Ptr(toType)) + { + Q_ASSERT(m_sourceReflection); + } + + AtomicValue::Ptr operator()(const AtomicValue::Ptr &lexicalValue, + const SchemaType::Ptr &type, + const ReportContext::Ptr &context) + { + prepareCasting(context, BuiltinTypes::xsString); + return AtomicValue::Ptr(const_cast<AtomicValue *>(cast(lexicalValue, context).asAtomicValue())); + } + + const SourceLocationReflection *actualReflection() const + { + return m_sourceReflection; + } + + ItemType::Ptr targetType() const + { + return m_targetType; + } + +private: + const SourceLocationReflection *const m_sourceReflection; + const ItemType::Ptr m_targetType; +}; + +AtomicValue::Ptr ValueFactory::fromLexical(const QString &lexicalValue, + const SchemaType::Ptr &type, + const ReportContext::Ptr &context, + const SourceLocationReflection *const sourceLocationReflection) +{ + Q_ASSERT(context); + Q_ASSERT(type); + Q_ASSERT_X(type->category() == SchemaType::SimpleTypeAtomic, Q_FUNC_INFO, + "We can only construct for atomic values."); + + return PerformValueConstruction(sourceLocationReflection, type)(AtomicString::fromValue(lexicalValue), + type, + context); +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/data/qvaluefactory_p.h b/src/xmlpatterns/data/qvaluefactory_p.h new file mode 100644 index 0000000..acc5733 --- /dev/null +++ b/src/xmlpatterns/data/qvaluefactory_p.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_ValueFactory_H +#define Patternist_ValueFactory_H + +#include "qitem_p.h" +#include "qreportcontext_p.h" +#include "qschematype_p.h" + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short Provides fromLexical(), which allows instantiation of atomic + * values from arbitrary types. + * + * This class wraps the helper class CastingPlatform with a more specific, + * high-level API. + * + * @see CastingPlatform + * @author Frans Englich <fenglich@trolltech.com> + * @ingroup Patternist_schema + */ + class ValueFactory + { + public: + /** + * @short Returns an AtomicValue of type @p type from the lexical space + * @p lexicalValue, and raise an error through @p context if that's + * impossible. + * + * ValueFactory does not take ownership of @p sourceLocationReflection. + */ + static AtomicValue::Ptr fromLexical(const QString &lexicalValue, + const SchemaType::Ptr &type, + const ReportContext::Ptr &context, + const SourceLocationReflection *const sourceLocationReflection); + + private: + Q_DISABLE_COPY(ValueFactory) + }; +} + +QT_END_NAMESPACE +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/environment/createReportContext.xsl b/src/xmlpatterns/environment/createReportContext.xsl index 7ca96bf..5b754d2 100644 --- a/src/xmlpatterns/environment/createReportContext.xsl +++ b/src/xmlpatterns/environment/createReportContext.xsl @@ -242,6 +242,11 @@ namespace QPatternist */]]></xsl:text> enum ErrorCode { + /** + * XML Schema error code. + */ + XSDError, + <!-- The order of the calls is significant. The templates takes into account to avoid the last comma(extractXSLT20 does this). --> <xsl:call-template name="extractXQuery10"/> diff --git a/src/xmlpatterns/environment/qreportcontext.cpp b/src/xmlpatterns/environment/qreportcontext.cpp index 34ef6ce..64afcdb 100644 --- a/src/xmlpatterns/environment/qreportcontext.cpp +++ b/src/xmlpatterns/environment/qreportcontext.cpp @@ -448,6 +448,7 @@ QString ReportContext::codeToString(const ReportContext::ErrorCode code) case XTTE1545: result = "XTTE1545"; break; case XTTE1550: result = "XTTE1550"; break; case XTTE1555: result = "XTTE1555"; break; + case XSDError: result = "XSDError"; break; } Q_ASSERT_X(result, Q_FUNC_INFO, "Unknown enum value."); diff --git a/src/xmlpatterns/environment/qreportcontext_p.h b/src/xmlpatterns/environment/qreportcontext_p.h index ee78972..dbdf824 100644 --- a/src/xmlpatterns/environment/qreportcontext_p.h +++ b/src/xmlpatterns/environment/qreportcontext_p.h @@ -151,6 +151,10 @@ namespace QPatternist */ enum ErrorCode { + /** + * XML Schema error code. + */ + XSDError, /** * It is a static error if analysis of an expression relies on some diff --git a/src/xmlpatterns/expr/qcastingplatform.cpp b/src/xmlpatterns/expr/qcastingplatform.cpp index bc902f9..933d188 100644 --- a/src/xmlpatterns/expr/qcastingplatform.cpp +++ b/src/xmlpatterns/expr/qcastingplatform.cpp @@ -83,7 +83,7 @@ Item CastingPlatform<TSubClass, issueError>::cast(const Item &sourceValue, else { bool castImpossible = false; - const AtomicCaster::Ptr caster(locateCaster(sourceValue.type(), context, castImpossible)); + const AtomicCaster::Ptr caster(locateCaster(sourceValue.type(), context, castImpossible, static_cast<const TSubClass *>(this), targetType())); if(!issueError && castImpossible) { @@ -112,7 +112,7 @@ bool CastingPlatform<TSubClass, issueError>::prepareCasting(const ReportContext: or numeric at compile time. We'll do lookup at runtime instead. */ bool castImpossible = false; - m_caster = locateCaster(sourceType, context, castImpossible); + m_caster = locateCaster(sourceType, context, castImpossible, static_cast<const TSubClass *>(this), targetType()); return !castImpossible; } @@ -120,20 +120,22 @@ bool CastingPlatform<TSubClass, issueError>::prepareCasting(const ReportContext: template <typename TSubClass, const bool issueError> AtomicCaster::Ptr CastingPlatform<TSubClass, issueError>::locateCaster(const ItemType::Ptr &sourceType, const ReportContext::Ptr &context, - bool &castImpossible) const + bool &castImpossible, + const SourceLocationReflection *const location, + const ItemType::Ptr &targetType) { Q_ASSERT(sourceType); - Q_ASSERT(targetType()); + Q_ASSERT(targetType); const AtomicCasterLocator::Ptr locator(static_cast<AtomicType *>( - targetType().data())->casterLocator()); + targetType.data())->casterLocator()); if(!locator) { if(issueError) { context->error(QtXmlPatterns::tr("No casting is possible with %1 as the target type.") - .arg(formatType(context->namePool(), targetType())), - ReportContext::XPTY0004, static_cast<const TSubClass *>(this)); + .arg(formatType(context->namePool(), targetType)), + ReportContext::XPTY0004, location); } else castImpossible = true; @@ -141,15 +143,15 @@ AtomicCaster::Ptr CastingPlatform<TSubClass, issueError>::locateCaster(const Ite return AtomicCaster::Ptr(); } - const AtomicCaster::Ptr caster(static_cast<const AtomicType *>(sourceType.data())->accept(locator, static_cast<const TSubClass *>(this))); + const AtomicCaster::Ptr caster(static_cast<const AtomicType *>(sourceType.data())->accept(locator, location)); if(!caster) { if(issueError) { context->error(QtXmlPatterns::tr("It is not possible to cast from %1 to %2.") .arg(formatType(context->namePool(), sourceType)) - .arg(formatType(context->namePool(), targetType())), - ReportContext::XPTY0004, static_cast<const TSubClass *>(this)); + .arg(formatType(context->namePool(), targetType)), + ReportContext::XPTY0004, location); } else castImpossible = true; diff --git a/src/xmlpatterns/expr/qcastingplatform_p.h b/src/xmlpatterns/expr/qcastingplatform_p.h index 3aded3d..91f4a8c 100644 --- a/src/xmlpatterns/expr/qcastingplatform_p.h +++ b/src/xmlpatterns/expr/qcastingplatform_p.h @@ -52,16 +52,17 @@ #ifndef Patternist_CastingPlatform_H #define Patternist_CastingPlatform_H +#include "qatomiccasterlocator_p.h" #include "qatomiccaster_p.h" -#include "qqnamevalue_p.h" #include "qatomicstring_p.h" -#include "qvalidationerror_p.h" -#include "qatomiccasterlocator_p.h" #include "qatomictype_p.h" #include "qbuiltintypes_p.h" #include "qcommonsequencetypes_p.h" -#include "qschematypefactory_p.h" #include "qpatternistlocale_p.h" +#include "qqnamevalue_p.h" +#include "qschematypefactory_p.h" +#include "qstaticcontext_p.h" +#include "qvalidationerror_p.h" QT_BEGIN_HEADER @@ -101,6 +102,7 @@ namespace QPatternist * function targetType() must be implemented such that CastingPlatform knows * what type it shall cast to. * + * @see ValueFactory * @author Frans Englich <fenglich@trolltech.com> * @ingroup Patternist_expressions */ @@ -167,9 +169,16 @@ namespace QPatternist * * @p castImpossible is not initialized. Initialize it to @c false. */ - AtomicCaster::Ptr locateCaster(const ItemType::Ptr &sourceType, - const ReportContext::Ptr &context, - bool &castImpossible) const; + static AtomicCaster::Ptr locateCaster(const ItemType::Ptr &sourceType, + const ReportContext::Ptr &context, + bool &castImpossible, + const SourceLocationReflection *const location, + const ItemType::Ptr &targetType); + private: + inline Item castWithCaster(const Item &sourceValue, + const AtomicCaster::Ptr &caster, + const DynamicContext::Ptr &context) const; + inline ItemType::Ptr targetType() const { diff --git a/src/xmlpatterns/expr/qexpressionfactory.cpp b/src/xmlpatterns/expr/qexpressionfactory.cpp index e243037..0ddf3b1 100644 --- a/src/xmlpatterns/expr/qexpressionfactory.cpp +++ b/src/xmlpatterns/expr/qexpressionfactory.cpp @@ -81,9 +81,13 @@ Expression::Ptr ExpressionFactory::createExpression(const QString &expr, const QUrl &queryURI, const QXmlName &initialTemplateName) { - if(lang == QXmlQuery::XQuery10) + if(lang == QXmlQuery::XSLT20) { - return createExpression(Tokenizer::Ptr(new XQueryTokenizer(expr, queryURI)), + QByteArray query(expr.toUtf8()); + QBuffer buffer(&query); + buffer.open(QIODevice::ReadOnly); + + return createExpression(&buffer, context, lang, requiredType, @@ -92,12 +96,7 @@ Expression::Ptr ExpressionFactory::createExpression(const QString &expr, } else { - Q_ASSERT(lang == QXmlQuery::XSLT20); - QByteArray query(expr.toUtf8()); - QBuffer buffer(&query); - buffer.open(QIODevice::ReadOnly); - - return createExpression(&buffer, + return createExpression(Tokenizer::Ptr(new XQueryTokenizer(expr, queryURI)), context, lang, requiredType, @@ -118,16 +117,10 @@ Expression::Ptr ExpressionFactory::createExpression(QIODevice *const device, Tokenizer::Ptr tokenizer; - if(lang == QXmlQuery::XQuery10) - { - - tokenizer = Tokenizer::Ptr(new XQueryTokenizer(QString::fromUtf8(device->readAll()), queryURI)); - } - else - { - Q_ASSERT(lang == QXmlQuery::XSLT20); + if(lang == QXmlQuery::XSLT20) tokenizer = Tokenizer::Ptr(new XSLTTokenizer(device, queryURI, context, context->namePool())); - } + else + tokenizer = Tokenizer::Ptr(new XQueryTokenizer(QString::fromUtf8(device->readAll()), queryURI)); return createExpression(tokenizer, context, lang, requiredType, queryURI, initialTemplateName); } diff --git a/src/xmlpatterns/functions/qpatternplatform.cpp b/src/xmlpatterns/functions/qpatternplatform.cpp index 74414f4..5339f28 100644 --- a/src/xmlpatterns/functions/qpatternplatform.cpp +++ b/src/xmlpatterns/functions/qpatternplatform.cpp @@ -168,8 +168,15 @@ void PatternPlatform::applyFlags(const Flags flags, QRegExp &patternP) // TODO Apply the other flags, like 'x'. } +QRegExp PatternPlatform::parsePattern(const QString &pattern, + const ReportContext::Ptr &context) const +{ + return parsePattern(pattern, context, this); +} + QRegExp PatternPlatform::parsePattern(const QString &patternP, - const DynamicContext::Ptr &context) const + const ReportContext::Ptr &context, + const SourceLocationReflection *const location) { if(patternP == QLatin1String("(.)\\3") || patternP == QLatin1String("\\3") || @@ -177,7 +184,7 @@ QRegExp PatternPlatform::parsePattern(const QString &patternP, { context->error(QLatin1String("We don't want to hang infinitely on K2-MatchesFunc-9, " "10 and 11. See Trolltech task 148505."), - ReportContext::FOER0000, this); + ReportContext::FOER0000, location); return QRegExp(); } @@ -189,14 +196,8 @@ QRegExp PatternPlatform::parsePattern(const QString &patternP, * QChar::category(). */ rewrittenPattern.replace(QLatin1String("[\\i-[:]]"), QLatin1String("[a-zA-Z_]")); rewrittenPattern.replace(QLatin1String("[\\c-[:]]"), QLatin1String("[a-zA-Z0-9_\\-\\.]")); - rewrittenPattern.replace(QLatin1String("\\i"), QLatin1String("[a-zA-Z:_]")); - rewrittenPattern.replace(QLatin1String("\\c"), QLatin1String("[a-zA-Z0-9:_\\-\\.]")); - rewrittenPattern.replace(QLatin1String("\\p{L}"), QLatin1String("[a-zA-Z]")); - rewrittenPattern.replace(QLatin1String("\\p{Lu}"), QLatin1String("[A-Z]")); - rewrittenPattern.replace(QLatin1String("\\p{Ll}"), QLatin1String("[a-z]")); - rewrittenPattern.replace(QLatin1String("\\p{Nd}"), QLatin1String("[0-9]")); - QRegExp retval(rewrittenPattern); + QRegExp retval(rewrittenPattern, Qt::CaseSensitive, QRegExp::W3CXmlSchema11); if(retval.isValid()) return retval; @@ -204,7 +205,7 @@ QRegExp PatternPlatform::parsePattern(const QString &patternP, { context->error(QtXmlPatterns::tr("%1 is an invalid regular expression pattern: %2") .arg(formatExpression(patternP), retval.errorString()), - ReportContext::FORX0002, this); + ReportContext::FORX0002, location); return QRegExp(); } } diff --git a/src/xmlpatterns/functions/qpatternplatform_p.h b/src/xmlpatterns/functions/qpatternplatform_p.h index 3f4b18e..76f5332 100644 --- a/src/xmlpatterns/functions/qpatternplatform_p.h +++ b/src/xmlpatterns/functions/qpatternplatform_p.h @@ -122,6 +122,14 @@ namespace QPatternist */ inline int captureCount() const; + /** + * @short Parses pattern + */ + static QRegExp parsePattern(const QString &pattern, + const ReportContext::Ptr &context, + const SourceLocationReflection *const location); + + protected: /** * @short This constructor is protected, because this class is supposed to be sub-classed. @@ -146,14 +154,18 @@ namespace QPatternist }; typedef QFlags<PreCompiledPart> PreCompiledParts; + /** + * @short Calls the public parsePattern() function and passes in @c + * this as the location. + */ + inline QRegExp parsePattern(const QString &pattern, + const ReportContext::Ptr &context) const; + Q_DISABLE_COPY(PatternPlatform) Flags parseFlags(const QString &flags, const DynamicContext::Ptr &context) const; - QRegExp parsePattern(const QString &pattern, - const DynamicContext::Ptr &context) const; - static void applyFlags(const Flags flags, QRegExp &pattern); /** diff --git a/src/xmlpatterns/functions/qsequencegeneratingfns.cpp b/src/xmlpatterns/functions/qsequencegeneratingfns.cpp index 81724f8..e3f30c5 100644 --- a/src/xmlpatterns/functions/qsequencegeneratingfns.cpp +++ b/src/xmlpatterns/functions/qsequencegeneratingfns.cpp @@ -69,19 +69,6 @@ Item IdFN::mapToItem(const QString &id, } /** - * @short Helper class for StringSplitter - * - * Needed by the QAbstractXmlForwardIterator sub-class. - * - * @relates StringSplitter - */ -template<> -bool qIsForwardIteratorEnd(const QString &unit) -{ - return unit.isNull(); -} - -/** * @short Helper class for IdFN. * * StringSplitter takes an Iterator which delivers strings of this kind: diff --git a/src/xmlpatterns/parser/qquerytransformparser.cpp b/src/xmlpatterns/parser/qquerytransformparser.cpp index cc6c82e..d80c09f 100644 --- a/src/xmlpatterns/parser/qquerytransformparser.cpp +++ b/src/xmlpatterns/parser/qquerytransformparser.cpp @@ -300,11 +300,18 @@ static inline QSourceLocation fromYYLTYPE(const YYLTYPE &sourceLocator, } /** + * @internal + * @relates QXmlQuery + */ +typedef QFlags<QXmlQuery::QueryLanguage> QueryLanguages; + +/** * @short Flags invalid expressions and declarations in the currently * parsed language. * - * Since this grammar is used for several languages: XQuery 1.0, XSL-T 2.0 and - * XPath 2.0 inside XSL-T, it is the union of all the constructs in these + * Since this grammar is used for several languages: XQuery 1.0, XSL-T 2.0, and + * XPath 2.0 inside XSL-T, and field and selector patterns in W3C XML Schema's + * identity constraints, it is the union of all the constructs in these * languages. However, when dealing with each language individually, we * regularly need to disallow some expressions, such as direct element * constructors when parsing XSL-T, or the typeswitch when parsing XPath. @@ -315,19 +322,46 @@ static inline QSourceLocation fromYYLTYPE(const YYLTYPE &sourceLocator, * instance the @c let clause, should not be flagged as an error, because it's * used for internal purposes. * - * Hence, this function is called from each expression and declaration which is - * unavailable in XPath. + * Hence, this function is called from each expression and declaration with @p + * allowedLanguages stating what languages it is allowed in. * * If @p isInternal is @c true, no error is raised. Otherwise, if the current - * language is not XQuery, an error is raised. + * language is not in @p allowedLanguages, an error is raised. */ -static void disallowedConstruct(const ParserContext *const parseInfo, - const YYLTYPE &sourceLocator, - const bool isInternal = false) +static void allowedIn(const QueryLanguages allowedLanguages, + const ParserContext *const parseInfo, + const YYLTYPE &sourceLocator, + const bool isInternal = false) { - if(!isInternal && parseInfo->languageAccent != QXmlQuery::XQuery10) + /* We treat XPath 2.0 as a subset of XSL-T 2.0, so if XPath 2.0 is allowed + * and XSL-T is the language, it's ok. */ + if(!isInternal && + (!allowedLanguages.testFlag(parseInfo->languageAccent) && !(allowedLanguages.testFlag(QXmlQuery::XPath20) && parseInfo->languageAccent == QXmlQuery::XSLT20))) { - parseInfo->staticContext->error(QtXmlPatterns::tr("A construct was encountered which only is allowed in XQuery."), + + QString langName; + + switch(parseInfo->languageAccent) + { + case QXmlQuery::XPath20: + langName = QLatin1String("XPath 2.0"); + break; + case QXmlQuery::XSLT20: + langName = QLatin1String("XSL-T 2.0"); + break; + case QXmlQuery::XQuery10: + langName = QLatin1String("XQuery 1.0"); + break; + case QXmlQuery::XmlSchema11IdentityConstraintSelector: + langName = QtXmlPatterns::tr("W3C XML Schema identity constraint selector"); + break; + case QXmlQuery::XmlSchema11IdentityConstraintField: + langName = QtXmlPatterns::tr("W3C XML Schema identity constraint field"); + break; + } + + parseInfo->staticContext->error(QtXmlPatterns::tr("A construct was encountered " + "which is disallowed in the current language(%1).").arg(langName), ReportContext::XPST0003, fromYYLTYPE(sourceLocator, parseInfo)); @@ -1366,7 +1400,7 @@ typedef struct YYLTYPE /* Copy the second part of user declarations. */ /* Line 221 of yacc.c. */ -#line 1289 "qquerytransformparser.cpp" +#line 1323 "qquerytransformparser.cpp" #ifdef short # undef short @@ -1850,54 +1884,54 @@ static const yytype_int16 yyrhs[] = /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { - 0, 1341, 1341, 1342, 1344, 1345, 1376, 1377, 1393, 1491, - 1493, 1499, 1501, 1508, 1514, 1520, 1527, 1530, 1534, 1538, - 1558, 1572, 1576, 1570, 1639, 1643, 1660, 1663, 1665, 1670, - 1671, 1675, 1676, 1680, 1684, 1688, 1690, 1691, 1693, 1695, - 1741, 1755, 1760, 1765, 1766, 1768, 1783, 1798, 1808, 1823, - 1827, 1832, 1846, 1850, 1855, 1869, 1874, 1879, 1884, 1889, - 1905, 1928, 1936, 1937, 1938, 1940, 1957, 1958, 1960, 1961, - 1963, 1964, 1966, 2021, 2025, 2031, 2034, 2039, 2053, 2057, - 2063, 2062, 2171, 2174, 2180, 2201, 2207, 2211, 2213, 2218, - 2228, 2229, 2234, 2235, 2244, 2314, 2325, 2326, 2330, 2335, - 2404, 2405, 2409, 2414, 2458, 2459, 2464, 2471, 2477, 2478, - 2479, 2480, 2481, 2482, 2488, 2493, 2499, 2502, 2507, 2513, - 2519, 2523, 2548, 2549, 2553, 2557, 2551, 2598, 2601, 2596, - 2617, 2618, 2619, 2622, 2626, 2634, 2633, 2647, 2646, 2655, - 2656, 2657, 2659, 2667, 2678, 2681, 2683, 2688, 2695, 2702, - 2708, 2728, 2733, 2739, 2742, 2744, 2745, 2752, 2758, 2762, - 2767, 2768, 2771, 2775, 2770, 2784, 2788, 2783, 2796, 2799, - 2803, 2798, 2812, 2816, 2811, 2824, 2826, 2854, 2853, 2865, - 2873, 2864, 2884, 2885, 2888, 2892, 2897, 2902, 2901, 2917, - 2922, 2923, 2928, 2929, 2934, 2935, 2936, 2937, 2939, 2940, - 2945, 2946, 2951, 2952, 2954, 2955, 2960, 2961, 2962, 2963, - 2965, 2966, 2971, 2972, 2977, 2978, 2980, 2984, 2989, 2990, - 2996, 2997, 3002, 3003, 3008, 3009, 3014, 3015, 3020, 3024, - 3029, 3030, 3031, 3033, 3038, 3039, 3040, 3041, 3042, 3043, - 3045, 3050, 3051, 3052, 3053, 3054, 3055, 3057, 3062, 3063, - 3064, 3066, 3080, 3081, 3082, 3084, 3100, 3104, 3109, 3110, - 3112, 3117, 3118, 3120, 3126, 3130, 3136, 3139, 3140, 3144, - 3153, 3158, 3162, 3163, 3168, 3167, 3182, 3189, 3188, 3203, - 3211, 3211, 3220, 3222, 3225, 3230, 3232, 3236, 3302, 3305, - 3311, 3314, 3323, 3327, 3331, 3336, 3337, 3342, 3343, 3346, - 3345, 3375, 3377, 3378, 3380, 3394, 3395, 3396, 3397, 3398, - 3399, 3400, 3401, 3402, 3403, 3404, 3405, 3408, 3407, 3417, - 3428, 3433, 3435, 3440, 3441, 3443, 3447, 3449, 3453, 3462, - 3468, 3469, 3474, 3475, 3476, 3477, 3478, 3479, 3480, 3481, - 3491, 3492, 3497, 3501, 3506, 3511, 3516, 3521, 3525, 3530, - 3535, 3540, 3569, 3573, 3580, 3582, 3586, 3588, 3589, 3590, - 3624, 3633, 3622, 3874, 3878, 3898, 3901, 3907, 3912, 3917, - 3923, 3926, 3936, 3943, 3947, 3953, 3967, 3973, 3990, 3995, - 4008, 4009, 4010, 4011, 4012, 4013, 4014, 4016, 4024, 4023, - 4063, 4066, 4071, 4086, 4091, 4098, 4110, 4114, 4110, 4120, - 4122, 4126, 4128, 4143, 4147, 4156, 4161, 4165, 4171, 4174, - 4179, 4184, 4189, 4190, 4191, 4192, 4194, 4195, 4196, 4197, - 4202, 4238, 4239, 4240, 4241, 4242, 4243, 4244, 4246, 4251, - 4256, 4262, 4263, 4265, 4270, 4275, 4280, 4285, 4301, 4302, - 4304, 4309, 4314, 4318, 4330, 4343, 4353, 4358, 4363, 4368, - 4382, 4396, 4397, 4399, 4409, 4411, 4416, 4423, 4430, 4432, - 4434, 4435, 4437, 4441, 4446, 4447, 4449, 4455, 4457, 4459, - 4460, 4462, 4474 + 0, 1375, 1375, 1376, 1378, 1379, 1410, 1411, 1427, 1525, + 1527, 1533, 1535, 1542, 1548, 1554, 1561, 1564, 1568, 1572, + 1592, 1606, 1610, 1604, 1673, 1677, 1694, 1697, 1699, 1704, + 1705, 1709, 1710, 1714, 1718, 1722, 1724, 1725, 1727, 1729, + 1775, 1789, 1794, 1799, 1800, 1802, 1817, 1832, 1842, 1857, + 1861, 1866, 1880, 1884, 1889, 1903, 1908, 1913, 1918, 1923, + 1939, 1962, 1970, 1971, 1972, 1974, 1991, 1992, 1994, 1995, + 1997, 1998, 2000, 2055, 2059, 2065, 2068, 2073, 2087, 2091, + 2097, 2096, 2205, 2208, 2214, 2235, 2241, 2245, 2247, 2252, + 2262, 2263, 2268, 2269, 2278, 2348, 2359, 2360, 2364, 2369, + 2438, 2439, 2443, 2448, 2492, 2493, 2498, 2505, 2511, 2512, + 2513, 2514, 2515, 2516, 2522, 2527, 2533, 2536, 2541, 2547, + 2553, 2557, 2582, 2583, 2587, 2591, 2585, 2632, 2635, 2630, + 2651, 2652, 2653, 2656, 2660, 2668, 2667, 2681, 2680, 2689, + 2690, 2691, 2693, 2701, 2712, 2715, 2717, 2722, 2729, 2736, + 2742, 2762, 2767, 2773, 2776, 2778, 2779, 2786, 2792, 2796, + 2801, 2802, 2805, 2809, 2804, 2819, 2823, 2818, 2831, 2834, + 2838, 2833, 2848, 2852, 2847, 2860, 2862, 2890, 2889, 2901, + 2909, 2900, 2920, 2921, 2924, 2928, 2933, 2938, 2937, 2953, + 2959, 2960, 2966, 2967, 2973, 2974, 2975, 2976, 2978, 2979, + 2985, 2986, 2992, 2993, 2995, 2996, 3002, 3003, 3004, 3005, + 3007, 3008, 3018, 3019, 3025, 3026, 3028, 3032, 3037, 3038, + 3045, 3046, 3052, 3053, 3059, 3060, 3066, 3067, 3073, 3077, + 3082, 3083, 3084, 3086, 3092, 3093, 3094, 3095, 3096, 3097, + 3099, 3104, 3105, 3106, 3107, 3108, 3109, 3111, 3116, 3117, + 3118, 3120, 3134, 3135, 3136, 3138, 3155, 3159, 3164, 3165, + 3167, 3172, 3173, 3175, 3181, 3185, 3191, 3194, 3195, 3199, + 3208, 3213, 3217, 3218, 3223, 3222, 3237, 3245, 3244, 3260, + 3268, 3268, 3277, 3279, 3282, 3287, 3289, 3293, 3359, 3362, + 3368, 3371, 3380, 3384, 3388, 3393, 3394, 3399, 3400, 3403, + 3402, 3432, 3434, 3435, 3437, 3481, 3482, 3483, 3484, 3485, + 3486, 3487, 3488, 3489, 3490, 3491, 3492, 3495, 3494, 3505, + 3516, 3521, 3523, 3528, 3529, 3534, 3538, 3540, 3544, 3553, + 3560, 3561, 3567, 3568, 3569, 3570, 3571, 3572, 3573, 3574, + 3584, 3585, 3590, 3595, 3601, 3607, 3612, 3617, 3622, 3628, + 3633, 3638, 3668, 3672, 3679, 3681, 3685, 3690, 3691, 3692, + 3726, 3735, 3724, 3976, 3980, 4000, 4003, 4009, 4014, 4019, + 4025, 4028, 4038, 4045, 4049, 4055, 4069, 4075, 4092, 4097, + 4110, 4111, 4112, 4113, 4114, 4115, 4116, 4118, 4126, 4125, + 4165, 4168, 4173, 4188, 4193, 4200, 4212, 4216, 4212, 4222, + 4224, 4228, 4230, 4245, 4249, 4258, 4263, 4267, 4273, 4276, + 4281, 4286, 4291, 4292, 4293, 4294, 4296, 4297, 4298, 4299, + 4304, 4340, 4341, 4342, 4343, 4344, 4345, 4346, 4348, 4353, + 4358, 4364, 4365, 4367, 4372, 4377, 4382, 4387, 4403, 4404, + 4406, 4411, 4416, 4420, 4432, 4445, 4455, 4460, 4465, 4470, + 4484, 4498, 4499, 4501, 4511, 4513, 4518, 4525, 4532, 4534, + 4536, 4537, 4539, 4543, 4548, 4549, 4551, 4557, 4559, 4561, + 4565, 4570, 4582 }; #endif @@ -3726,7 +3760,7 @@ yyreduce: { case 5: /* Line 1269 of yacc.c. */ -#line 1346 "querytransformparser.ypp" +#line 1380 "querytransformparser.ypp" { /* Suppress more compiler warnings about unused defines. */ @@ -3760,7 +3794,7 @@ yyreduce: case 7: /* Line 1269 of yacc.c. */ -#line 1378 "querytransformparser.ypp" +#line 1412 "querytransformparser.ypp" { const QRegExp encNameRegExp(QLatin1String("[A-Za-z][A-Za-z0-9._\\-]*")); @@ -3779,7 +3813,7 @@ yyreduce: case 8: /* Line 1269 of yacc.c. */ -#line 1394 "querytransformparser.ypp" +#line 1428 "querytransformparser.ypp" { /* In XSL-T, we can have dangling variable references, so resolve them * before we proceed with other steps, such as checking circularity. */ @@ -3880,7 +3914,7 @@ yyreduce: case 10: /* Line 1269 of yacc.c. */ -#line 1494 "querytransformparser.ypp" +#line 1528 "querytransformparser.ypp" { // TODO add to namespace context parseInfo->moduleNamespace = parseInfo->staticContext->namePool()->allocateNamespace((yyvsp[(3) - (6)].sval)); @@ -3889,9 +3923,9 @@ yyreduce: case 12: /* Line 1269 of yacc.c. */ -#line 1502 "querytransformparser.ypp" +#line 1536 "querytransformparser.ypp" { - disallowedConstruct(parseInfo, (yyloc)); + allowedIn(QXmlQuery::XQuery10, parseInfo, (yyloc)); if(parseInfo->hasSecondPrologPart) parseInfo->staticContext->error(QtXmlPatterns::tr("A default namespace declaration must occur before function, " "variable, and option declarations."), ReportContext::XPST0003, fromYYLTYPE((yyloc), parseInfo)); @@ -3900,7 +3934,7 @@ yyreduce: case 13: /* Line 1269 of yacc.c. */ -#line 1509 "querytransformparser.ypp" +#line 1543 "querytransformparser.ypp" { if(parseInfo->hasSecondPrologPart) parseInfo->staticContext->error(QtXmlPatterns::tr("A default namespace declaration must occur before function, " @@ -3910,7 +3944,7 @@ yyreduce: case 14: /* Line 1269 of yacc.c. */ -#line 1515 "querytransformparser.ypp" +#line 1549 "querytransformparser.ypp" { if(parseInfo->hasSecondPrologPart) parseInfo->staticContext->error(QtXmlPatterns::tr("Namespace declarations must occur before function, " @@ -3920,9 +3954,9 @@ yyreduce: case 15: /* Line 1269 of yacc.c. */ -#line 1521 "querytransformparser.ypp" +#line 1555 "querytransformparser.ypp" { - disallowedConstruct(parseInfo, (yyloc)); + allowedIn(QXmlQuery::XQuery10, parseInfo, (yyloc)); if(parseInfo->hasSecondPrologPart) parseInfo->staticContext->error(QtXmlPatterns::tr("Module imports must occur before function, " "variable, and option declarations."), ReportContext::XPST0003, fromYYLTYPE((yyloc), parseInfo)); @@ -3931,7 +3965,7 @@ yyreduce: case 17: /* Line 1269 of yacc.c. */ -#line 1531 "querytransformparser.ypp" +#line 1565 "querytransformparser.ypp" { parseInfo->hasSecondPrologPart = true; } @@ -3939,7 +3973,7 @@ yyreduce: case 18: /* Line 1269 of yacc.c. */ -#line 1535 "querytransformparser.ypp" +#line 1569 "querytransformparser.ypp" { parseInfo->hasSecondPrologPart = true; } @@ -3947,16 +3981,16 @@ yyreduce: case 19: /* Line 1269 of yacc.c. */ -#line 1539 "querytransformparser.ypp" +#line 1573 "querytransformparser.ypp" { - disallowedConstruct(parseInfo, (yyloc)); + allowedIn(QXmlQuery::XQuery10, parseInfo, (yyloc)); parseInfo->hasSecondPrologPart = true; } break; case 20: /* Line 1269 of yacc.c. */ -#line 1562 "querytransformparser.ypp" +#line 1596 "querytransformparser.ypp" { Template::Ptr temp(create(new Template(parseInfo->currentImportPrecedence, (yyvsp[(5) - (7)].sequenceType)), (yyloc), parseInfo)); @@ -3969,7 +4003,7 @@ yyreduce: case 21: /* Line 1269 of yacc.c. */ -#line 1572 "querytransformparser.ypp" +#line 1606 "querytransformparser.ypp" { parseInfo->isParsingPattern = true; } @@ -3977,7 +4011,7 @@ yyreduce: case 22: /* Line 1269 of yacc.c. */ -#line 1576 "querytransformparser.ypp" +#line 1610 "querytransformparser.ypp" { parseInfo->isParsingPattern = false; } @@ -3985,7 +4019,7 @@ yyreduce: case 23: /* Line 1269 of yacc.c. */ -#line 1585 "querytransformparser.ypp" +#line 1619 "querytransformparser.ypp" { /* In this grammar branch, we're guaranteed to be a template rule, but * may also be a named template. */ @@ -4042,7 +4076,7 @@ yyreduce: case 24: /* Line 1269 of yacc.c. */ -#line 1639 "querytransformparser.ypp" +#line 1673 "querytransformparser.ypp" { (yyval.enums.Double) = std::numeric_limits<xsDouble>::quiet_NaN(); } @@ -4050,7 +4084,7 @@ yyreduce: case 25: /* Line 1269 of yacc.c. */ -#line 1644 "querytransformparser.ypp" +#line 1678 "querytransformparser.ypp" { const AtomicValue::Ptr val(Decimal::fromLexical((yyvsp[(2) - (2)].sval))); if(val->hasError()) @@ -4069,7 +4103,7 @@ yyreduce: case 26: /* Line 1269 of yacc.c. */ -#line 1660 "querytransformparser.ypp" +#line 1694 "querytransformparser.ypp" { (yyval.qName) = QXmlName(); } @@ -4077,7 +4111,7 @@ yyreduce: case 28: /* Line 1269 of yacc.c. */ -#line 1666 "querytransformparser.ypp" +#line 1700 "querytransformparser.ypp" { (yyval.qName) = (yyvsp[(2) - (2)].qName); } @@ -4085,42 +4119,42 @@ yyreduce: case 30: /* Line 1269 of yacc.c. */ -#line 1672 "querytransformparser.ypp" +#line 1706 "querytransformparser.ypp" { - disallowedConstruct(parseInfo, (yyloc)); + allowedIn(QXmlQuery::XQuery10, parseInfo, (yyloc)); } break; case 32: /* Line 1269 of yacc.c. */ -#line 1677 "querytransformparser.ypp" +#line 1711 "querytransformparser.ypp" { - disallowedConstruct(parseInfo, (yyloc)); + allowedIn(QXmlQuery::XQuery10, parseInfo, (yyloc)); } break; case 33: /* Line 1269 of yacc.c. */ -#line 1681 "querytransformparser.ypp" +#line 1715 "querytransformparser.ypp" { - disallowedConstruct(parseInfo, (yyloc)); + allowedIn(QXmlQuery::XQuery10, parseInfo, (yyloc)); } break; case 34: /* Line 1269 of yacc.c. */ -#line 1685 "querytransformparser.ypp" +#line 1719 "querytransformparser.ypp" { - disallowedConstruct(parseInfo, (yyloc)); + allowedIn(QXmlQuery::XQuery10, parseInfo, (yyloc)); } break; case 39: /* Line 1269 of yacc.c. */ -#line 1696 "querytransformparser.ypp" +#line 1730 "querytransformparser.ypp" { if(!(yyvsp[(6) - (7)].enums.Bool)) - disallowedConstruct(parseInfo, (yyloc)); + allowedIn(QXmlQuery::XQuery10, parseInfo, (yyloc)); if((yyvsp[(3) - (7)].sval) == QLatin1String("xmlns")) { @@ -4166,7 +4200,7 @@ yyreduce: case 40: /* Line 1269 of yacc.c. */ -#line 1742 "querytransformparser.ypp" +#line 1776 "querytransformparser.ypp" { if(parseInfo->hasDeclaration(ParserContext::BoundarySpaceDecl)) { @@ -4183,7 +4217,7 @@ yyreduce: case 41: /* Line 1269 of yacc.c. */ -#line 1756 "querytransformparser.ypp" +#line 1790 "querytransformparser.ypp" { (yyval.enums.boundarySpacePolicy) = StaticContext::BSPStrip; } @@ -4191,7 +4225,7 @@ yyreduce: case 42: /* Line 1269 of yacc.c. */ -#line 1761 "querytransformparser.ypp" +#line 1795 "querytransformparser.ypp" { (yyval.enums.boundarySpacePolicy) = StaticContext::BSPPreserve; } @@ -4199,7 +4233,7 @@ yyreduce: case 45: /* Line 1269 of yacc.c. */ -#line 1770 "querytransformparser.ypp" +#line 1804 "querytransformparser.ypp" { if(parseInfo->hasDeclaration(ParserContext::DeclareDefaultElementNamespace)) { @@ -4216,7 +4250,7 @@ yyreduce: case 46: /* Line 1269 of yacc.c. */ -#line 1785 "querytransformparser.ypp" +#line 1819 "querytransformparser.ypp" { if(parseInfo->hasDeclaration(ParserContext::DeclareDefaultFunctionNamespace)) { @@ -4233,7 +4267,7 @@ yyreduce: case 47: /* Line 1269 of yacc.c. */ -#line 1799 "querytransformparser.ypp" +#line 1833 "querytransformparser.ypp" { if((yyvsp[(3) - (5)].qName).prefix() == StandardPrefixes::empty) { @@ -4246,9 +4280,9 @@ yyreduce: case 48: /* Line 1269 of yacc.c. */ -#line 1809 "querytransformparser.ypp" +#line 1843 "querytransformparser.ypp" { - disallowedConstruct(parseInfo, (yyloc)); + allowedIn(QXmlQuery::XQuery10, parseInfo, (yyloc)); if(parseInfo->hasDeclaration(ParserContext::OrderingModeDecl)) { parseInfo->staticContext->error(prologMessage("declare ordering"), @@ -4264,7 +4298,7 @@ yyreduce: case 49: /* Line 1269 of yacc.c. */ -#line 1824 "querytransformparser.ypp" +#line 1858 "querytransformparser.ypp" { (yyval.enums.orderingMode) = StaticContext::Ordered; } @@ -4272,7 +4306,7 @@ yyreduce: case 50: /* Line 1269 of yacc.c. */ -#line 1828 "querytransformparser.ypp" +#line 1862 "querytransformparser.ypp" { (yyval.enums.orderingMode) = StaticContext::Unordered; } @@ -4280,7 +4314,7 @@ yyreduce: case 51: /* Line 1269 of yacc.c. */ -#line 1833 "querytransformparser.ypp" +#line 1867 "querytransformparser.ypp" { if(parseInfo->hasDeclaration(ParserContext::EmptyOrderDecl)) { @@ -4297,7 +4331,7 @@ yyreduce: case 52: /* Line 1269 of yacc.c. */ -#line 1847 "querytransformparser.ypp" +#line 1881 "querytransformparser.ypp" { (yyval.enums.orderingEmptySequence) = StaticContext::Least; } @@ -4305,7 +4339,7 @@ yyreduce: case 53: /* Line 1269 of yacc.c. */ -#line 1851 "querytransformparser.ypp" +#line 1885 "querytransformparser.ypp" { (yyval.enums.orderingEmptySequence) = StaticContext::Greatest; } @@ -4313,7 +4347,7 @@ yyreduce: case 54: /* Line 1269 of yacc.c. */ -#line 1857 "querytransformparser.ypp" +#line 1891 "querytransformparser.ypp" { if(parseInfo->hasDeclaration(ParserContext::CopyNamespacesDecl)) { @@ -4329,7 +4363,7 @@ yyreduce: case 55: /* Line 1269 of yacc.c. */ -#line 1870 "querytransformparser.ypp" +#line 1904 "querytransformparser.ypp" { parseInfo->preserveNamespacesMode = true; } @@ -4337,7 +4371,7 @@ yyreduce: case 56: /* Line 1269 of yacc.c. */ -#line 1875 "querytransformparser.ypp" +#line 1909 "querytransformparser.ypp" { parseInfo->preserveNamespacesMode = false; } @@ -4345,7 +4379,7 @@ yyreduce: case 57: /* Line 1269 of yacc.c. */ -#line 1880 "querytransformparser.ypp" +#line 1914 "querytransformparser.ypp" { parseInfo->inheritNamespacesMode = true; } @@ -4353,7 +4387,7 @@ yyreduce: case 58: /* Line 1269 of yacc.c. */ -#line 1885 "querytransformparser.ypp" +#line 1919 "querytransformparser.ypp" { parseInfo->inheritNamespacesMode = false; } @@ -4361,7 +4395,7 @@ yyreduce: case 59: /* Line 1269 of yacc.c. */ -#line 1890 "querytransformparser.ypp" +#line 1924 "querytransformparser.ypp" { if(parseInfo->hasDeclaration(ParserContext::DefaultCollationDecl)) { @@ -4380,9 +4414,9 @@ yyreduce: case 60: /* Line 1269 of yacc.c. */ -#line 1906 "querytransformparser.ypp" +#line 1940 "querytransformparser.ypp" { - disallowedConstruct(parseInfo, (yyloc), (yyvsp[(3) - (5)].enums.Bool)); + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XSLT20), parseInfo, (yyloc), (yyvsp[(3) - (5)].enums.Bool)); if(parseInfo->hasDeclaration(ParserContext::BaseURIDecl)) { parseInfo->staticContext->error(prologMessage("declare base-uri"), @@ -4406,7 +4440,7 @@ yyreduce: case 61: /* Line 1269 of yacc.c. */ -#line 1929 "querytransformparser.ypp" +#line 1963 "querytransformparser.ypp" { parseInfo->staticContext->error(QtXmlPatterns::tr("The Schema Import feature is not supported, " "and therefore %1 declarations cannot occur.") @@ -4417,7 +4451,7 @@ yyreduce: case 65: /* Line 1269 of yacc.c. */ -#line 1941 "querytransformparser.ypp" +#line 1975 "querytransformparser.ypp" { if((yyvsp[(4) - (6)].sval).isEmpty()) { @@ -4437,9 +4471,9 @@ yyreduce: case 72: /* Line 1269 of yacc.c. */ -#line 1968 "querytransformparser.ypp" +#line 2002 "querytransformparser.ypp" { - disallowedConstruct(parseInfo, (yyloc), (yyvsp[(3) - (9)].enums.Bool)); + allowedIn(QXmlQuery::XQuery10, parseInfo, (yyloc), (yyvsp[(3) - (9)].enums.Bool)); if(variableByName((yyvsp[(5) - (9)].qName), parseInfo)) { parseInfo->staticContext->error(QtXmlPatterns::tr("A variable by name %1 has already " @@ -4494,7 +4528,7 @@ yyreduce: case 73: /* Line 1269 of yacc.c. */ -#line 2022 "querytransformparser.ypp" +#line 2056 "querytransformparser.ypp" { (yyval.expr).reset(); } @@ -4502,7 +4536,7 @@ yyreduce: case 74: /* Line 1269 of yacc.c. */ -#line 2026 "querytransformparser.ypp" +#line 2060 "querytransformparser.ypp" { (yyval.expr) = (yyvsp[(2) - (2)].expr); } @@ -4510,7 +4544,7 @@ yyreduce: case 75: /* Line 1269 of yacc.c. */ -#line 2031 "querytransformparser.ypp" +#line 2065 "querytransformparser.ypp" { (yyval.expr).reset(); } @@ -4518,7 +4552,7 @@ yyreduce: case 76: /* Line 1269 of yacc.c. */ -#line 2035 "querytransformparser.ypp" +#line 2069 "querytransformparser.ypp" { (yyval.expr) = (yyvsp[(2) - (2)].expr); } @@ -4526,7 +4560,7 @@ yyreduce: case 77: /* Line 1269 of yacc.c. */ -#line 2040 "querytransformparser.ypp" +#line 2074 "querytransformparser.ypp" { if(parseInfo->hasDeclaration(ParserContext::ConstructionDecl)) { @@ -4543,7 +4577,7 @@ yyreduce: case 78: /* Line 1269 of yacc.c. */ -#line 2054 "querytransformparser.ypp" +#line 2088 "querytransformparser.ypp" { (yyval.enums.constructionMode) = StaticContext::CMStrip; } @@ -4551,7 +4585,7 @@ yyreduce: case 79: /* Line 1269 of yacc.c. */ -#line 2058 "querytransformparser.ypp" +#line 2092 "querytransformparser.ypp" { (yyval.enums.constructionMode) = StaticContext::CMPreserve; } @@ -4559,7 +4593,7 @@ yyreduce: case 80: /* Line 1269 of yacc.c. */ -#line 2063 "querytransformparser.ypp" +#line 2097 "querytransformparser.ypp" { (yyval.enums.slot) = parseInfo->currentExpressionSlot() - (yyvsp[(6) - (7)].functionArguments).count(); } @@ -4567,10 +4601,10 @@ yyreduce: case 81: /* Line 1269 of yacc.c. */ -#line 2067 "querytransformparser.ypp" +#line 2101 "querytransformparser.ypp" { if(!(yyvsp[(3) - (11)].enums.Bool)) - disallowedConstruct(parseInfo, (yyloc), (yyvsp[(3) - (11)].enums.Bool)); + allowedIn(QXmlQuery::XQuery10, parseInfo, (yyloc), (yyvsp[(3) - (11)].enums.Bool)); /* If FunctionBody is null, it is 'external', otherwise the value is the body. */ const QXmlName::NamespaceCode ns((yyvsp[(4) - (11)].qName).namespaceURI()); @@ -4674,7 +4708,7 @@ yyreduce: case 82: /* Line 1269 of yacc.c. */ -#line 2171 "querytransformparser.ypp" +#line 2205 "querytransformparser.ypp" { (yyval.functionArguments) = FunctionArgument::List(); } @@ -4682,7 +4716,7 @@ yyreduce: case 83: /* Line 1269 of yacc.c. */ -#line 2175 "querytransformparser.ypp" +#line 2209 "querytransformparser.ypp" { FunctionArgument::List l; l.append((yyvsp[(1) - (1)].functionArgument)); @@ -4692,7 +4726,7 @@ yyreduce: case 84: /* Line 1269 of yacc.c. */ -#line 2181 "querytransformparser.ypp" +#line 2215 "querytransformparser.ypp" { FunctionArgument::List::const_iterator it((yyvsp[(1) - (3)].functionArguments).constBegin()); const FunctionArgument::List::const_iterator end((yyvsp[(1) - (3)].functionArguments).constEnd()); @@ -4716,7 +4750,7 @@ yyreduce: case 85: /* Line 1269 of yacc.c. */ -#line 2202 "querytransformparser.ypp" +#line 2236 "querytransformparser.ypp" { pushVariable((yyvsp[(2) - (3)].qName), (yyvsp[(3) - (3)].sequenceType), Expression::Ptr(), VariableDeclaration::FunctionArgument, (yyloc), parseInfo); (yyval.functionArgument) = FunctionArgument::Ptr(new FunctionArgument((yyvsp[(2) - (3)].qName), (yyvsp[(3) - (3)].sequenceType))); @@ -4725,7 +4759,7 @@ yyreduce: case 86: /* Line 1269 of yacc.c. */ -#line 2208 "querytransformparser.ypp" +#line 2242 "querytransformparser.ypp" { (yyval.expr).reset(); } @@ -4733,7 +4767,7 @@ yyreduce: case 88: /* Line 1269 of yacc.c. */ -#line 2214 "querytransformparser.ypp" +#line 2248 "querytransformparser.ypp" { (yyval.expr) = (yyvsp[(2) - (3)].expr); } @@ -4741,7 +4775,7 @@ yyreduce: case 91: /* Line 1269 of yacc.c. */ -#line 2230 "querytransformparser.ypp" +#line 2264 "querytransformparser.ypp" { (yyval.expr) = create(new CombineNodes((yyvsp[(1) - (3)].expr), CombineNodes::Union, (yyvsp[(3) - (3)].expr)), (yyloc), parseInfo); } @@ -4749,7 +4783,7 @@ yyreduce: case 93: /* Line 1269 of yacc.c. */ -#line 2236 "querytransformparser.ypp" +#line 2270 "querytransformparser.ypp" { /* We write this into a node test. The spec says, 5.5.3 The Meaning of a Pattern: * "Similarly, / matches a document node, and only a document node, @@ -4762,7 +4796,7 @@ yyreduce: case 94: /* Line 1269 of yacc.c. */ -#line 2245 "querytransformparser.ypp" +#line 2279 "querytransformparser.ypp" { /* /axis::node-test * => @@ -4836,7 +4870,7 @@ yyreduce: case 95: /* Line 1269 of yacc.c. */ -#line 2315 "querytransformparser.ypp" +#line 2349 "querytransformparser.ypp" { /* //axis::node-test * => @@ -4851,7 +4885,7 @@ yyreduce: case 97: /* Line 1269 of yacc.c. */ -#line 2327 "querytransformparser.ypp" +#line 2361 "querytransformparser.ypp" { createIdPatternPath((yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr), QXmlNodeModelIndex::AxisParent, (yylsp[(2) - (3)]), parseInfo); } @@ -4859,7 +4893,7 @@ yyreduce: case 98: /* Line 1269 of yacc.c. */ -#line 2331 "querytransformparser.ypp" +#line 2365 "querytransformparser.ypp" { createIdPatternPath((yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr), QXmlNodeModelIndex::AxisAncestor, (yylsp[(2) - (3)]), parseInfo); } @@ -4867,7 +4901,7 @@ yyreduce: case 99: /* Line 1269 of yacc.c. */ -#line 2336 "querytransformparser.ypp" +#line 2370 "querytransformparser.ypp" { const Expression::List ands((yyvsp[(1) - (1)].expr)->operands()); const FunctionSignature::Ptr signature((yyvsp[(1) - (1)].expr)->as<FunctionCall>()->signature()); @@ -4939,7 +4973,7 @@ yyreduce: case 101: /* Line 1269 of yacc.c. */ -#line 2406 "querytransformparser.ypp" +#line 2440 "querytransformparser.ypp" { (yyval.expr) = createPatternPath((yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr), QXmlNodeModelIndex::AxisParent, (yylsp[(2) - (3)]), parseInfo); } @@ -4947,7 +4981,7 @@ yyreduce: case 102: /* Line 1269 of yacc.c. */ -#line 2410 "querytransformparser.ypp" +#line 2444 "querytransformparser.ypp" { (yyval.expr) = createPatternPath((yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr), QXmlNodeModelIndex::AxisAncestor, (yylsp[(2) - (3)]), parseInfo); } @@ -4955,7 +4989,7 @@ yyreduce: case 103: /* Line 1269 of yacc.c. */ -#line 2415 "querytransformparser.ypp" +#line 2449 "querytransformparser.ypp" { const Expression::Ptr expr(findAxisStep((yyvsp[(1) - (1)].expr))); @@ -5002,7 +5036,7 @@ yyreduce: case 105: /* Line 1269 of yacc.c. */ -#line 2460 "querytransformparser.ypp" +#line 2494 "querytransformparser.ypp" { (yyval.expr) = create(new ExpressionSequence((yyvsp[(1) - (1)].expressionList)), (yyloc), parseInfo); } @@ -5010,7 +5044,7 @@ yyreduce: case 106: /* Line 1269 of yacc.c. */ -#line 2465 "querytransformparser.ypp" +#line 2499 "querytransformparser.ypp" { Expression::List l; l.append((yyvsp[(1) - (3)].expr)); @@ -5021,7 +5055,7 @@ yyreduce: case 107: /* Line 1269 of yacc.c. */ -#line 2472 "querytransformparser.ypp" +#line 2506 "querytransformparser.ypp" { (yyvsp[(1) - (3)].expressionList).append((yyvsp[(3) - (3)].expr)); (yyval.expressionList) = (yyvsp[(1) - (3)].expressionList); @@ -5030,7 +5064,7 @@ yyreduce: case 113: /* Line 1269 of yacc.c. */ -#line 2483 "querytransformparser.ypp" +#line 2517 "querytransformparser.ypp" { (yyval.expr) = createDirAttributeValue((yyvsp[(3) - (4)].expressionList), parseInfo, (yyloc)); } @@ -5038,7 +5072,7 @@ yyreduce: case 114: /* Line 1269 of yacc.c. */ -#line 2488 "querytransformparser.ypp" +#line 2522 "querytransformparser.ypp" { QVector<QXmlName> result; result.append(QXmlName(StandardNamespaces::InternalXSLT, StandardLocalNames::Default)); @@ -5048,7 +5082,7 @@ yyreduce: case 115: /* Line 1269 of yacc.c. */ -#line 2494 "querytransformparser.ypp" +#line 2528 "querytransformparser.ypp" { (yyval.qNameVector) = (yyvsp[(2) - (2)].qNameVector); } @@ -5056,7 +5090,7 @@ yyreduce: case 116: /* Line 1269 of yacc.c. */ -#line 2499 "querytransformparser.ypp" +#line 2533 "querytransformparser.ypp" { (yyval.qName) = QXmlName(StandardNamespaces::InternalXSLT, StandardLocalNames::Default); } @@ -5064,7 +5098,7 @@ yyreduce: case 117: /* Line 1269 of yacc.c. */ -#line 2503 "querytransformparser.ypp" +#line 2537 "querytransformparser.ypp" { (yyval.qName) = (yyvsp[(2) - (2)].qName); } @@ -5072,7 +5106,7 @@ yyreduce: case 118: /* Line 1269 of yacc.c. */ -#line 2508 "querytransformparser.ypp" +#line 2542 "querytransformparser.ypp" { QVector<QXmlName> result; result.append((yyvsp[(1) - (1)].qName)); @@ -5082,7 +5116,7 @@ yyreduce: case 119: /* Line 1269 of yacc.c. */ -#line 2514 "querytransformparser.ypp" +#line 2548 "querytransformparser.ypp" { (yyvsp[(1) - (3)].qNameVector).append((yyvsp[(3) - (3)].qName)); (yyval.qNameVector) = (yyvsp[(1) - (3)].qNameVector); @@ -5091,7 +5125,7 @@ yyreduce: case 120: /* Line 1269 of yacc.c. */ -#line 2520 "querytransformparser.ypp" +#line 2554 "querytransformparser.ypp" { (yyval.qName) = (yyvsp[(1) - (1)].qName); } @@ -5099,7 +5133,7 @@ yyreduce: case 121: /* Line 1269 of yacc.c. */ -#line 2524 "querytransformparser.ypp" +#line 2558 "querytransformparser.ypp" { if((yyvsp[(1) - (1)].sval) == QLatin1String("#current")) (yyval.qName) = QXmlName(StandardNamespaces::InternalXSLT, StandardLocalNames::current); @@ -5126,7 +5160,7 @@ yyreduce: case 124: /* Line 1269 of yacc.c. */ -#line 2553 "querytransformparser.ypp" +#line 2587 "querytransformparser.ypp" { /* We're pushing the range variable here, not the positional. */ (yyval.expr) = pushVariable((yyvsp[(3) - (7)].qName), quantificationType((yyvsp[(4) - (7)].sequenceType)), (yyvsp[(7) - (7)].expr), VariableDeclaration::RangeVariable, (yyloc), parseInfo); @@ -5135,7 +5169,7 @@ yyreduce: case 125: /* Line 1269 of yacc.c. */ -#line 2557 "querytransformparser.ypp" +#line 2591 "querytransformparser.ypp" { /* It is ok this appears after PositionalVar, because currentRangeSlot() * uses a different "channel" than currentPositionSlot(), so they can't trash @@ -5146,7 +5180,7 @@ yyreduce: case 126: /* Line 1269 of yacc.c. */ -#line 2564 "querytransformparser.ypp" +#line 2598 "querytransformparser.ypp" { Q_ASSERT((yyvsp[(7) - (10)].expr)); Q_ASSERT((yyvsp[(10) - (10)].expr)); @@ -5182,7 +5216,7 @@ yyreduce: case 127: /* Line 1269 of yacc.c. */ -#line 2598 "querytransformparser.ypp" +#line 2632 "querytransformparser.ypp" { pushVariable((yyvsp[(3) - (7)].qName), quantificationType((yyvsp[(4) - (7)].sequenceType)), (yyvsp[(7) - (7)].expr), VariableDeclaration::RangeVariable, (yyloc), parseInfo); } @@ -5190,7 +5224,7 @@ yyreduce: case 128: /* Line 1269 of yacc.c. */ -#line 2601 "querytransformparser.ypp" +#line 2635 "querytransformparser.ypp" { /* It is ok this appears after PositionalVar, because currentRangeSlot() * uses a different "channel" than currentPositionSlot(), so they can't trash @@ -5201,7 +5235,7 @@ yyreduce: case 129: /* Line 1269 of yacc.c. */ -#line 2608 "querytransformparser.ypp" +#line 2642 "querytransformparser.ypp" { (yyval.expr) = create(new ForClause((yyvsp[(9) - (10)].enums.slot), (yyvsp[(7) - (10)].expr), (yyvsp[(10) - (10)].expr), (yyvsp[(5) - (10)].enums.slot)), (yyloc), parseInfo); @@ -5214,7 +5248,7 @@ yyreduce: case 133: /* Line 1269 of yacc.c. */ -#line 2622 "querytransformparser.ypp" +#line 2656 "querytransformparser.ypp" { (yyval.enums.slot) = -1; } @@ -5222,7 +5256,7 @@ yyreduce: case 134: /* Line 1269 of yacc.c. */ -#line 2627 "querytransformparser.ypp" +#line 2661 "querytransformparser.ypp" { pushVariable((yyvsp[(3) - (3)].qName), CommonSequenceTypes::ExactlyOneInteger, Expression::Ptr(), VariableDeclaration::PositionalVariable, (yyloc), parseInfo); @@ -5232,7 +5266,7 @@ yyreduce: case 135: /* Line 1269 of yacc.c. */ -#line 2634 "querytransformparser.ypp" +#line 2668 "querytransformparser.ypp" { (yyval.expr) = pushVariable((yyvsp[(4) - (7)].qName), quantificationType((yyvsp[(5) - (7)].sequenceType)), (yyvsp[(7) - (7)].expr), VariableDeclaration::ExpressionVariable, (yyloc), parseInfo); } @@ -5240,9 +5274,9 @@ yyreduce: case 136: /* Line 1269 of yacc.c. */ -#line 2638 "querytransformparser.ypp" +#line 2672 "querytransformparser.ypp" { - disallowedConstruct(parseInfo, (yyloc), (yyvsp[(2) - (9)].enums.Bool)); + allowedIn(QXmlQuery::XQuery10, parseInfo, (yyloc), (yyvsp[(2) - (9)].enums.Bool)); Q_ASSERT(parseInfo->variables.top()->name == (yyvsp[(4) - (9)].qName)); (yyval.expr) = create(new LetClause((yyvsp[(8) - (9)].expr), (yyvsp[(9) - (9)].expr), parseInfo->variables.top()), (yyloc), parseInfo); @@ -5252,13 +5286,13 @@ yyreduce: case 137: /* Line 1269 of yacc.c. */ -#line 2647 "querytransformparser.ypp" +#line 2681 "querytransformparser.ypp" { (yyval.expr) = pushVariable((yyvsp[(3) - (6)].qName), quantificationType((yyvsp[(4) - (6)].sequenceType)), (yyvsp[(6) - (6)].expr), VariableDeclaration::ExpressionVariable, (yyloc), parseInfo);} break; case 138: /* Line 1269 of yacc.c. */ -#line 2649 "querytransformparser.ypp" +#line 2683 "querytransformparser.ypp" { Q_ASSERT(parseInfo->variables.top()->name == (yyvsp[(3) - (8)].qName)); (yyval.expr) = create(new LetClause((yyvsp[(7) - (8)].expr), (yyvsp[(8) - (8)].expr), parseInfo->variables.top()), (yyloc), parseInfo); @@ -5268,7 +5302,7 @@ yyreduce: case 142: /* Line 1269 of yacc.c. */ -#line 2660 "querytransformparser.ypp" +#line 2694 "querytransformparser.ypp" { if((yyvsp[(1) - (3)].orderSpecs).isEmpty()) (yyval.expr) = (yyvsp[(3) - (3)].expr); @@ -5279,7 +5313,7 @@ yyreduce: case 143: /* Line 1269 of yacc.c. */ -#line 2668 "querytransformparser.ypp" +#line 2702 "querytransformparser.ypp" { if((yyvsp[(3) - (5)].orderSpecs).isEmpty()) (yyval.expr) = create(new IfThenClause((yyvsp[(2) - (5)].expr), (yyvsp[(5) - (5)].expr), create(new EmptySequence, (yyloc), parseInfo)), (yyloc), parseInfo); @@ -5292,7 +5326,7 @@ yyreduce: case 144: /* Line 1269 of yacc.c. */ -#line 2678 "querytransformparser.ypp" +#line 2712 "querytransformparser.ypp" { (yyval.orderSpecs) = OrderSpecTransfer::List(); } @@ -5300,7 +5334,7 @@ yyreduce: case 146: /* Line 1269 of yacc.c. */ -#line 2684 "querytransformparser.ypp" +#line 2718 "querytransformparser.ypp" { (yyval.orderSpecs) = (yyvsp[(2) - (2)].orderSpecs); } @@ -5308,7 +5342,7 @@ yyreduce: case 147: /* Line 1269 of yacc.c. */ -#line 2689 "querytransformparser.ypp" +#line 2723 "querytransformparser.ypp" { OrderSpecTransfer::List list; list += (yyvsp[(1) - (3)].orderSpecs); @@ -5319,7 +5353,7 @@ yyreduce: case 148: /* Line 1269 of yacc.c. */ -#line 2696 "querytransformparser.ypp" +#line 2730 "querytransformparser.ypp" { OrderSpecTransfer::List list; list.append((yyvsp[(1) - (1)].orderSpec)); @@ -5329,7 +5363,7 @@ yyreduce: case 149: /* Line 1269 of yacc.c. */ -#line 2703 "querytransformparser.ypp" +#line 2737 "querytransformparser.ypp" { (yyval.orderSpec) = OrderSpecTransfer((yyvsp[(1) - (4)].expr), OrderBy::OrderSpec((yyvsp[(2) - (4)].enums.sortDirection), (yyvsp[(3) - (4)].enums.orderingEmptySequence))); } @@ -5337,7 +5371,7 @@ yyreduce: case 150: /* Line 1269 of yacc.c. */ -#line 2708 "querytransformparser.ypp" +#line 2742 "querytransformparser.ypp" { /* Where does the specification state the default value is ascending? * @@ -5361,7 +5395,7 @@ yyreduce: case 151: /* Line 1269 of yacc.c. */ -#line 2729 "querytransformparser.ypp" +#line 2763 "querytransformparser.ypp" { (yyval.enums.sortDirection) = OrderBy::OrderSpec::Ascending; } @@ -5369,7 +5403,7 @@ yyreduce: case 152: /* Line 1269 of yacc.c. */ -#line 2734 "querytransformparser.ypp" +#line 2768 "querytransformparser.ypp" { (yyval.enums.sortDirection) = OrderBy::OrderSpec::Descending; } @@ -5377,7 +5411,7 @@ yyreduce: case 153: /* Line 1269 of yacc.c. */ -#line 2739 "querytransformparser.ypp" +#line 2773 "querytransformparser.ypp" { (yyval.enums.orderingEmptySequence) = parseInfo->staticContext->orderingEmptySequence(); } @@ -5385,7 +5419,7 @@ yyreduce: case 156: /* Line 1269 of yacc.c. */ -#line 2746 "querytransformparser.ypp" +#line 2780 "querytransformparser.ypp" { if(parseInfo->isXSLT()) resolveAndCheckCollation<ReportContext::XTDE1035>((yyvsp[(2) - (2)].sval), parseInfo, (yyloc)); @@ -5396,7 +5430,7 @@ yyreduce: case 157: /* Line 1269 of yacc.c. */ -#line 2753 "querytransformparser.ypp" +#line 2787 "querytransformparser.ypp" { /* We do nothing. We don't use collations, and we have this non-terminal * in order to accept expressions. */ @@ -5405,7 +5439,7 @@ yyreduce: case 158: /* Line 1269 of yacc.c. */ -#line 2759 "querytransformparser.ypp" +#line 2793 "querytransformparser.ypp" { parseInfo->orderStability.push(OrderBy::StableOrder); } @@ -5413,7 +5447,7 @@ yyreduce: case 159: /* Line 1269 of yacc.c. */ -#line 2763 "querytransformparser.ypp" +#line 2797 "querytransformparser.ypp" { parseInfo->orderStability.push(OrderBy::UnstableOrder); } @@ -5421,7 +5455,7 @@ yyreduce: case 162: /* Line 1269 of yacc.c. */ -#line 2771 "querytransformparser.ypp" +#line 2805 "querytransformparser.ypp" { pushVariable((yyvsp[(3) - (6)].qName), quantificationType((yyvsp[(4) - (6)].sequenceType)), (yyvsp[(6) - (6)].expr), VariableDeclaration::RangeVariable, (yyloc), parseInfo); @@ -5430,14 +5464,15 @@ yyreduce: case 163: /* Line 1269 of yacc.c. */ -#line 2775 "querytransformparser.ypp" +#line 2809 "querytransformparser.ypp" {(yyval.enums.slot) = parseInfo->staticContext->currentRangeSlot();} break; case 164: /* Line 1269 of yacc.c. */ -#line 2777 "querytransformparser.ypp" +#line 2811 "querytransformparser.ypp" { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, (yyloc)); (yyval.expr) = create(new QuantifiedExpression((yyvsp[(8) - (9)].enums.slot), QuantifiedExpression::Some, (yyvsp[(6) - (9)].expr), (yyvsp[(9) - (9)].expr)), (yyloc), parseInfo); parseInfo->finalizePushedVariable(); @@ -5446,7 +5481,7 @@ yyreduce: case 165: /* Line 1269 of yacc.c. */ -#line 2784 "querytransformparser.ypp" +#line 2819 "querytransformparser.ypp" { (yyval.expr) = pushVariable((yyvsp[(3) - (6)].qName), quantificationType((yyvsp[(4) - (6)].sequenceType)), (yyvsp[(6) - (6)].expr), VariableDeclaration::RangeVariable, (yyloc), parseInfo); @@ -5455,13 +5490,13 @@ yyreduce: case 166: /* Line 1269 of yacc.c. */ -#line 2788 "querytransformparser.ypp" +#line 2823 "querytransformparser.ypp" {(yyval.enums.slot) = parseInfo->staticContext->currentRangeSlot();} break; case 167: /* Line 1269 of yacc.c. */ -#line 2790 "querytransformparser.ypp" +#line 2825 "querytransformparser.ypp" { (yyval.expr) = create(new QuantifiedExpression((yyvsp[(8) - (9)].enums.slot), QuantifiedExpression::Some, (yyvsp[(7) - (9)].expr), (yyvsp[(9) - (9)].expr)), (yyloc), parseInfo); @@ -5471,7 +5506,7 @@ yyreduce: case 169: /* Line 1269 of yacc.c. */ -#line 2799 "querytransformparser.ypp" +#line 2834 "querytransformparser.ypp" { pushVariable((yyvsp[(3) - (6)].qName), quantificationType((yyvsp[(4) - (6)].sequenceType)), (yyvsp[(6) - (6)].expr), VariableDeclaration::RangeVariable, (yyloc), parseInfo); @@ -5480,14 +5515,15 @@ yyreduce: case 170: /* Line 1269 of yacc.c. */ -#line 2803 "querytransformparser.ypp" +#line 2838 "querytransformparser.ypp" {(yyval.enums.slot) = parseInfo->staticContext->currentRangeSlot();} break; case 171: /* Line 1269 of yacc.c. */ -#line 2805 "querytransformparser.ypp" +#line 2840 "querytransformparser.ypp" { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, (yyloc)); (yyval.expr) = create(new QuantifiedExpression((yyvsp[(8) - (9)].enums.slot), QuantifiedExpression::Every, (yyvsp[(6) - (9)].expr), (yyvsp[(9) - (9)].expr)), (yyloc), parseInfo); parseInfo->finalizePushedVariable(); @@ -5496,7 +5532,7 @@ yyreduce: case 172: /* Line 1269 of yacc.c. */ -#line 2812 "querytransformparser.ypp" +#line 2848 "querytransformparser.ypp" { (yyval.expr) = pushVariable((yyvsp[(3) - (6)].qName), quantificationType((yyvsp[(4) - (6)].sequenceType)), (yyvsp[(6) - (6)].expr), VariableDeclaration::RangeVariable, (yyloc), parseInfo); @@ -5505,13 +5541,13 @@ yyreduce: case 173: /* Line 1269 of yacc.c. */ -#line 2816 "querytransformparser.ypp" +#line 2852 "querytransformparser.ypp" {(yyval.enums.slot) = parseInfo->staticContext->currentRangeSlot();} break; case 174: /* Line 1269 of yacc.c. */ -#line 2818 "querytransformparser.ypp" +#line 2854 "querytransformparser.ypp" { (yyval.expr) = create(new QuantifiedExpression((yyvsp[(8) - (9)].enums.slot), QuantifiedExpression::Every, (yyvsp[(7) - (9)].expr), (yyvsp[(9) - (9)].expr)), (yyloc), parseInfo); @@ -5521,7 +5557,7 @@ yyreduce: case 176: /* Line 1269 of yacc.c. */ -#line 2827 "querytransformparser.ypp" +#line 2863 "querytransformparser.ypp" { (yyval.expr) = (yyvsp[(2) - (2)].expr); } @@ -5529,7 +5565,7 @@ yyreduce: case 177: /* Line 1269 of yacc.c. */ -#line 2854 "querytransformparser.ypp" +#line 2890 "querytransformparser.ypp" { parseInfo->typeswitchSource.push((yyvsp[(3) - (4)].expr)); } @@ -5537,9 +5573,9 @@ yyreduce: case 178: /* Line 1269 of yacc.c. */ -#line 2858 "querytransformparser.ypp" +#line 2894 "querytransformparser.ypp" { - disallowedConstruct(parseInfo, (yyloc)); + allowedIn(QXmlQuery::XQuery10, parseInfo, (yyloc)); parseInfo->typeswitchSource.pop(); (yyval.expr) = (yyvsp[(6) - (6)].expr); } @@ -5547,7 +5583,7 @@ yyreduce: case 179: /* Line 1269 of yacc.c. */ -#line 2865 "querytransformparser.ypp" +#line 2901 "querytransformparser.ypp" { if(!(yyvsp[(2) - (3)].qName).isNull()) { @@ -5559,7 +5595,7 @@ yyreduce: case 180: /* Line 1269 of yacc.c. */ -#line 2873 "querytransformparser.ypp" +#line 2909 "querytransformparser.ypp" { /* The variable shouldn't be in-scope for other case branches. */ if(!(yyvsp[(2) - (6)].qName).isNull()) @@ -5569,7 +5605,7 @@ yyreduce: case 181: /* Line 1269 of yacc.c. */ -#line 2879 "querytransformparser.ypp" +#line 2915 "querytransformparser.ypp" { const Expression::Ptr instanceOf(create(new InstanceOf(parseInfo->typeswitchSource.top(), (yyvsp[(3) - (8)].sequenceType)), (yyloc), parseInfo)); (yyval.expr) = create(new IfThenClause(instanceOf, (yyvsp[(6) - (8)].expr), (yyvsp[(8) - (8)].expr)), (yyloc), parseInfo); @@ -5578,7 +5614,7 @@ yyreduce: case 184: /* Line 1269 of yacc.c. */ -#line 2888 "querytransformparser.ypp" +#line 2924 "querytransformparser.ypp" { (yyval.qName) = QXmlName(); } @@ -5586,7 +5622,7 @@ yyreduce: case 185: /* Line 1269 of yacc.c. */ -#line 2893 "querytransformparser.ypp" +#line 2929 "querytransformparser.ypp" { (yyval.qName) = (yyvsp[(2) - (3)].qName); } @@ -5594,7 +5630,7 @@ yyreduce: case 186: /* Line 1269 of yacc.c. */ -#line 2898 "querytransformparser.ypp" +#line 2934 "querytransformparser.ypp" { (yyval.expr) = (yyvsp[(3) - (3)].expr); } @@ -5602,7 +5638,7 @@ yyreduce: case 187: /* Line 1269 of yacc.c. */ -#line 2902 "querytransformparser.ypp" +#line 2938 "querytransformparser.ypp" { if(!(yyvsp[(3) - (3)].qName).isNull()) { @@ -5615,7 +5651,7 @@ yyreduce: case 188: /* Line 1269 of yacc.c. */ -#line 2911 "querytransformparser.ypp" +#line 2947 "querytransformparser.ypp" { if(!(yyvsp[(3) - (6)].qName).isNull()) parseInfo->finalizePushedVariable(); @@ -5625,107 +5661,119 @@ yyreduce: case 189: /* Line 1269 of yacc.c. */ -#line 2918 "querytransformparser.ypp" +#line 2954 "querytransformparser.ypp" { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, (yyloc)); (yyval.expr) = create(new IfThenClause((yyvsp[(3) - (8)].expr), (yyvsp[(6) - (8)].expr), (yyvsp[(8) - (8)].expr)), (yyloc), parseInfo); } break; case 191: /* Line 1269 of yacc.c. */ -#line 2924 "querytransformparser.ypp" +#line 2961 "querytransformparser.ypp" { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, (yyloc)); (yyval.expr) = create(new OrExpression((yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)), (yyloc), parseInfo); } break; case 193: /* Line 1269 of yacc.c. */ -#line 2930 "querytransformparser.ypp" +#line 2968 "querytransformparser.ypp" { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, (yyloc)); (yyval.expr) = create(new AndExpression((yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)), (yyloc), parseInfo); } break; case 199: /* Line 1269 of yacc.c. */ -#line 2941 "querytransformparser.ypp" +#line 2980 "querytransformparser.ypp" { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, (yyloc)); (yyval.expr) = create(new RangeExpression((yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)), (yyloc), parseInfo); } break; case 201: /* Line 1269 of yacc.c. */ -#line 2947 "querytransformparser.ypp" +#line 2987 "querytransformparser.ypp" { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, (yyloc)); (yyval.expr) = create(new ArithmeticExpression((yyvsp[(1) - (3)].expr), (yyvsp[(2) - (3)].enums.mathOperator), (yyvsp[(3) - (3)].expr)), (yyloc), parseInfo); } break; case 202: /* Line 1269 of yacc.c. */ -#line 2951 "querytransformparser.ypp" +#line 2992 "querytransformparser.ypp" {(yyval.enums.mathOperator) = AtomicMathematician::Add;} break; case 203: /* Line 1269 of yacc.c. */ -#line 2952 "querytransformparser.ypp" +#line 2993 "querytransformparser.ypp" {(yyval.enums.mathOperator) = AtomicMathematician::Substract;} break; case 205: /* Line 1269 of yacc.c. */ -#line 2956 "querytransformparser.ypp" +#line 2997 "querytransformparser.ypp" { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, (yyloc)); (yyval.expr) = create(new ArithmeticExpression((yyvsp[(1) - (3)].expr), (yyvsp[(2) - (3)].enums.mathOperator), (yyvsp[(3) - (3)].expr)), (yyloc), parseInfo); } break; case 206: /* Line 1269 of yacc.c. */ -#line 2960 "querytransformparser.ypp" +#line 3002 "querytransformparser.ypp" {(yyval.enums.mathOperator) = AtomicMathematician::Multiply;} break; case 207: /* Line 1269 of yacc.c. */ -#line 2961 "querytransformparser.ypp" +#line 3003 "querytransformparser.ypp" {(yyval.enums.mathOperator) = AtomicMathematician::Div;} break; case 208: /* Line 1269 of yacc.c. */ -#line 2962 "querytransformparser.ypp" +#line 3004 "querytransformparser.ypp" {(yyval.enums.mathOperator) = AtomicMathematician::IDiv;} break; case 209: /* Line 1269 of yacc.c. */ -#line 2963 "querytransformparser.ypp" +#line 3005 "querytransformparser.ypp" {(yyval.enums.mathOperator) = AtomicMathematician::Mod;} break; case 211: /* Line 1269 of yacc.c. */ -#line 2967 "querytransformparser.ypp" +#line 3009 "querytransformparser.ypp" { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 + | QXmlQuery::XPath20 + | QXmlQuery::XmlSchema11IdentityConstraintField + | QXmlQuery::XmlSchema11IdentityConstraintSelector), + parseInfo, (yyloc)); (yyval.expr) = create(new CombineNodes((yyvsp[(1) - (3)].expr), CombineNodes::Union, (yyvsp[(3) - (3)].expr)), (yyloc), parseInfo); } break; case 213: /* Line 1269 of yacc.c. */ -#line 2973 "querytransformparser.ypp" +#line 3020 "querytransformparser.ypp" { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, (yyloc)); (yyval.expr) = create(new CombineNodes((yyvsp[(1) - (3)].expr), (yyvsp[(2) - (3)].enums.combinedNodeOp), (yyvsp[(3) - (3)].expr)), (yyloc), parseInfo); } break; case 216: /* Line 1269 of yacc.c. */ -#line 2981 "querytransformparser.ypp" +#line 3029 "querytransformparser.ypp" { (yyval.enums.combinedNodeOp) = CombineNodes::Intersect; } @@ -5733,7 +5781,7 @@ yyreduce: case 217: /* Line 1269 of yacc.c. */ -#line 2985 "querytransformparser.ypp" +#line 3033 "querytransformparser.ypp" { (yyval.enums.combinedNodeOp) = CombineNodes::Except; } @@ -5741,48 +5789,53 @@ yyreduce: case 219: /* Line 1269 of yacc.c. */ -#line 2991 "querytransformparser.ypp" +#line 3039 "querytransformparser.ypp" { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, (yyloc)); (yyval.expr) = create(new InstanceOf((yyvsp[(1) - (4)].expr), - SequenceType::Ptr((yyvsp[(4) - (4)].sequenceType))), (yyloc), parseInfo); + SequenceType::Ptr((yyvsp[(4) - (4)].sequenceType))), (yyloc), parseInfo); } break; case 221: /* Line 1269 of yacc.c. */ -#line 2998 "querytransformparser.ypp" +#line 3047 "querytransformparser.ypp" { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, (yyloc)); (yyval.expr) = create(new TreatAs((yyvsp[(1) - (4)].expr), (yyvsp[(4) - (4)].sequenceType)), (yyloc), parseInfo); } break; case 223: /* Line 1269 of yacc.c. */ -#line 3004 "querytransformparser.ypp" +#line 3054 "querytransformparser.ypp" { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, (yyloc)); (yyval.expr) = create(new CastableAs((yyvsp[(1) - (4)].expr), (yyvsp[(4) - (4)].sequenceType)), (yyloc), parseInfo); } break; case 225: /* Line 1269 of yacc.c. */ -#line 3010 "querytransformparser.ypp" +#line 3061 "querytransformparser.ypp" { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, (yyloc)); (yyval.expr) = create(new CastAs((yyvsp[(1) - (4)].expr), (yyvsp[(4) - (4)].sequenceType)), (yyloc), parseInfo); } break; case 227: /* Line 1269 of yacc.c. */ -#line 3016 "querytransformparser.ypp" +#line 3068 "querytransformparser.ypp" { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, (yyloc)); (yyval.expr) = create(new UnaryExpression((yyvsp[(1) - (2)].enums.mathOperator), (yyvsp[(2) - (2)].expr), parseInfo->staticContext), (yyloc), parseInfo); } break; case 228: /* Line 1269 of yacc.c. */ -#line 3021 "querytransformparser.ypp" +#line 3074 "querytransformparser.ypp" { (yyval.enums.mathOperator) = AtomicMathematician::Add; } @@ -5790,7 +5843,7 @@ yyreduce: case 229: /* Line 1269 of yacc.c. */ -#line 3025 "querytransformparser.ypp" +#line 3078 "querytransformparser.ypp" { (yyval.enums.mathOperator) = AtomicMathematician::Substract; } @@ -5798,51 +5851,52 @@ yyreduce: case 233: /* Line 1269 of yacc.c. */ -#line 3034 "querytransformparser.ypp" +#line 3087 "querytransformparser.ypp" { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, (yyloc)); (yyval.expr) = create(new GeneralComparison((yyvsp[(1) - (3)].expr), (yyvsp[(2) - (3)].enums.valueOperator), (yyvsp[(3) - (3)].expr), parseInfo->isBackwardsCompat.top()), (yyloc), parseInfo); } break; case 234: /* Line 1269 of yacc.c. */ -#line 3038 "querytransformparser.ypp" +#line 3092 "querytransformparser.ypp" {(yyval.enums.valueOperator) = AtomicComparator::OperatorEqual;} break; case 235: /* Line 1269 of yacc.c. */ -#line 3039 "querytransformparser.ypp" +#line 3093 "querytransformparser.ypp" {(yyval.enums.valueOperator) = AtomicComparator::OperatorNotEqual;} break; case 236: /* Line 1269 of yacc.c. */ -#line 3040 "querytransformparser.ypp" +#line 3094 "querytransformparser.ypp" {(yyval.enums.valueOperator) = AtomicComparator::OperatorGreaterOrEqual;} break; case 237: /* Line 1269 of yacc.c. */ -#line 3041 "querytransformparser.ypp" +#line 3095 "querytransformparser.ypp" {(yyval.enums.valueOperator) = AtomicComparator::OperatorGreaterThan;} break; case 238: /* Line 1269 of yacc.c. */ -#line 3042 "querytransformparser.ypp" +#line 3096 "querytransformparser.ypp" {(yyval.enums.valueOperator) = AtomicComparator::OperatorLessOrEqual;} break; case 239: /* Line 1269 of yacc.c. */ -#line 3043 "querytransformparser.ypp" +#line 3097 "querytransformparser.ypp" {(yyval.enums.valueOperator) = AtomicComparator::OperatorLessThan;} break; case 240: /* Line 1269 of yacc.c. */ -#line 3046 "querytransformparser.ypp" +#line 3100 "querytransformparser.ypp" { (yyval.expr) = create(new ValueComparison((yyvsp[(1) - (3)].expr), (yyvsp[(2) - (3)].enums.valueOperator), (yyvsp[(3) - (3)].expr)), (yyloc), parseInfo); } @@ -5850,43 +5904,43 @@ yyreduce: case 241: /* Line 1269 of yacc.c. */ -#line 3050 "querytransformparser.ypp" +#line 3104 "querytransformparser.ypp" {(yyval.enums.valueOperator) = AtomicComparator::OperatorEqual;} break; case 242: /* Line 1269 of yacc.c. */ -#line 3051 "querytransformparser.ypp" +#line 3105 "querytransformparser.ypp" {(yyval.enums.valueOperator) = AtomicComparator::OperatorNotEqual;} break; case 243: /* Line 1269 of yacc.c. */ -#line 3052 "querytransformparser.ypp" +#line 3106 "querytransformparser.ypp" {(yyval.enums.valueOperator) = AtomicComparator::OperatorGreaterOrEqual;} break; case 244: /* Line 1269 of yacc.c. */ -#line 3053 "querytransformparser.ypp" +#line 3107 "querytransformparser.ypp" {(yyval.enums.valueOperator) = AtomicComparator::OperatorGreaterThan;} break; case 245: /* Line 1269 of yacc.c. */ -#line 3054 "querytransformparser.ypp" +#line 3108 "querytransformparser.ypp" {(yyval.enums.valueOperator) = AtomicComparator::OperatorLessOrEqual;} break; case 246: /* Line 1269 of yacc.c. */ -#line 3055 "querytransformparser.ypp" +#line 3109 "querytransformparser.ypp" {(yyval.enums.valueOperator) = AtomicComparator::OperatorLessThan;} break; case 247: /* Line 1269 of yacc.c. */ -#line 3058 "querytransformparser.ypp" +#line 3112 "querytransformparser.ypp" { (yyval.expr) = create(new NodeComparison((yyvsp[(1) - (3)].expr), (yyvsp[(2) - (3)].enums.nodeOperator), (yyvsp[(3) - (3)].expr)), (yyloc), parseInfo); } @@ -5894,27 +5948,27 @@ yyreduce: case 248: /* Line 1269 of yacc.c. */ -#line 3062 "querytransformparser.ypp" +#line 3116 "querytransformparser.ypp" {(yyval.enums.nodeOperator) = QXmlNodeModelIndex::Is;} break; case 249: /* Line 1269 of yacc.c. */ -#line 3063 "querytransformparser.ypp" +#line 3117 "querytransformparser.ypp" {(yyval.enums.nodeOperator) = QXmlNodeModelIndex::Precedes;} break; case 250: /* Line 1269 of yacc.c. */ -#line 3064 "querytransformparser.ypp" +#line 3118 "querytransformparser.ypp" {(yyval.enums.nodeOperator) = QXmlNodeModelIndex::Follows;} break; case 251: /* Line 1269 of yacc.c. */ -#line 3067 "querytransformparser.ypp" +#line 3121 "querytransformparser.ypp" { - disallowedConstruct(parseInfo, (yyloc)); + allowedIn(QXmlQuery::XQuery10, parseInfo, (yyloc)); parseInfo->staticContext->error(QtXmlPatterns::tr("The Schema Validation Feature is not supported. " "Hence, %1-expressions may not be used.") .arg(formatKeyword("validate")), @@ -5927,26 +5981,27 @@ yyreduce: case 252: /* Line 1269 of yacc.c. */ -#line 3080 "querytransformparser.ypp" +#line 3134 "querytransformparser.ypp" {(yyval.enums.validationMode) = Validate::Strict;} break; case 253: /* Line 1269 of yacc.c. */ -#line 3081 "querytransformparser.ypp" +#line 3135 "querytransformparser.ypp" {(yyval.enums.validationMode) = Validate::Strict;} break; case 254: /* Line 1269 of yacc.c. */ -#line 3082 "querytransformparser.ypp" +#line 3136 "querytransformparser.ypp" {(yyval.enums.validationMode) = Validate::Lax;} break; case 255: /* Line 1269 of yacc.c. */ -#line 3085 "querytransformparser.ypp" +#line 3139 "querytransformparser.ypp" { + allowedIn(QXmlQuery::XQuery10, parseInfo, (yyloc)); /* We don't support any pragmas, so we only do the * necessary validation and use the fallback expression. */ @@ -5964,7 +6019,7 @@ yyreduce: case 256: /* Line 1269 of yacc.c. */ -#line 3101 "querytransformparser.ypp" +#line 3156 "querytransformparser.ypp" { (yyval.expr).reset(); } @@ -5972,7 +6027,7 @@ yyreduce: case 257: /* Line 1269 of yacc.c. */ -#line 3105 "querytransformparser.ypp" +#line 3160 "querytransformparser.ypp" { (yyval.expr) = (yyvsp[(2) - (3)].expr); } @@ -5980,15 +6035,15 @@ yyreduce: case 260: /* Line 1269 of yacc.c. */ -#line 3113 "querytransformparser.ypp" +#line 3168 "querytransformparser.ypp" { - disallowedConstruct(parseInfo, (yyloc)); + allowedIn(QXmlQuery::XQuery10, parseInfo, (yyloc)); } break; case 263: /* Line 1269 of yacc.c. */ -#line 3121 "querytransformparser.ypp" +#line 3176 "querytransformparser.ypp" { /* This is "/step". That is, fn:root(self::node()) treat as document-node()/RelativePathExpr. */ (yyval.expr) = create(new Path(createRootExpression(parseInfo, (yyloc)), (yyvsp[(2) - (2)].expr)), (yyloc), parseInfo); @@ -5997,7 +6052,7 @@ yyreduce: case 264: /* Line 1269 of yacc.c. */ -#line 3127 "querytransformparser.ypp" +#line 3182 "querytransformparser.ypp" { (yyval.expr) = createSlashSlashPath(createRootExpression(parseInfo, (yyloc)), (yyvsp[(2) - (2)].expr), (yyloc), parseInfo); } @@ -6005,7 +6060,7 @@ yyreduce: case 265: /* Line 1269 of yacc.c. */ -#line 3131 "querytransformparser.ypp" +#line 3186 "querytransformparser.ypp" { /* This is "/". That is, fn:root(self::node()) treat as document-node(). */ (yyval.expr) = createRootExpression(parseInfo, (yyloc)); @@ -6014,7 +6069,7 @@ yyreduce: case 268: /* Line 1269 of yacc.c. */ -#line 3141 "querytransformparser.ypp" +#line 3196 "querytransformparser.ypp" { (yyval.expr) = create(new Path((yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr), (yyvsp[(2) - (3)].enums.pathKind)), (yyloc), parseInfo); } @@ -6022,7 +6077,7 @@ yyreduce: case 269: /* Line 1269 of yacc.c. */ -#line 3145 "querytransformparser.ypp" +#line 3200 "querytransformparser.ypp" { const Expression::Ptr orderBy(createReturnOrderBy((yyvsp[(4) - (7)].orderSpecs), (yyvsp[(6) - (7)].expr), parseInfo->orderStability.pop(), (yyloc), parseInfo)); @@ -6035,7 +6090,7 @@ yyreduce: case 270: /* Line 1269 of yacc.c. */ -#line 3154 "querytransformparser.ypp" +#line 3209 "querytransformparser.ypp" { (yyval.expr) = createSlashSlashPath((yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr), (yyloc), parseInfo); } @@ -6043,7 +6098,7 @@ yyreduce: case 271: /* Line 1269 of yacc.c. */ -#line 3159 "querytransformparser.ypp" +#line 3214 "querytransformparser.ypp" { (yyval.expr) = NodeSortExpression::wrapAround((yyvsp[(1) - (1)].expr), parseInfo->staticContext); } @@ -6051,7 +6106,7 @@ yyreduce: case 273: /* Line 1269 of yacc.c. */ -#line 3164 "querytransformparser.ypp" +#line 3219 "querytransformparser.ypp" { (yyval.expr) = create(new CurrentItemStore((yyvsp[(2) - (2)].expr)), (yyloc), parseInfo); } @@ -6059,7 +6114,7 @@ yyreduce: case 274: /* Line 1269 of yacc.c. */ -#line 3168 "querytransformparser.ypp" +#line 3223 "querytransformparser.ypp" { const xsDouble version = (yyvsp[(1) - (1)].sval).toDouble(); @@ -6071,7 +6126,7 @@ yyreduce: case 275: /* Line 1269 of yacc.c. */ -#line 3176 "querytransformparser.ypp" +#line 3231 "querytransformparser.ypp" { if((yyvsp[(2) - (3)].enums.Double) < 2) (yyval.expr) = createCompatStore((yyvsp[(3) - (3)].expr), (yyloc), parseInfo); @@ -6082,8 +6137,9 @@ yyreduce: case 276: /* Line 1269 of yacc.c. */ -#line 3183 "querytransformparser.ypp" +#line 3238 "querytransformparser.ypp" { + allowedIn(QXmlQuery::XSLT20, parseInfo, (yyloc)); Q_ASSERT(!(yyvsp[(2) - (5)].sval).isEmpty()); (yyval.expr) = create(new StaticBaseURIStore((yyvsp[(2) - (5)].sval), (yyvsp[(4) - (5)].expr)), (yyloc), parseInfo); } @@ -6091,8 +6147,9 @@ yyreduce: case 277: /* Line 1269 of yacc.c. */ -#line 3189 "querytransformparser.ypp" +#line 3245 "querytransformparser.ypp" { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XSLT20), parseInfo, (yyloc)); parseInfo->resolvers.push(parseInfo->staticContext->namespaceBindings()); const NamespaceResolver::Ptr resolver(new DelegatingNamespaceResolver(parseInfo->staticContext->namespaceBindings())); resolver->addBinding(QXmlName(parseInfo->staticContext->namePool()->allocateNamespace((yyvsp[(5) - (6)].sval)), @@ -6104,7 +6161,7 @@ yyreduce: case 278: /* Line 1269 of yacc.c. */ -#line 3199 "querytransformparser.ypp" +#line 3256 "querytransformparser.ypp" { parseInfo->staticContext->setNamespaceBindings(parseInfo->resolvers.pop()); (yyval.expr) = (yyvsp[(8) - (9)].expr); @@ -6113,7 +6170,7 @@ yyreduce: case 279: /* Line 1269 of yacc.c. */ -#line 3204 "querytransformparser.ypp" +#line 3261 "querytransformparser.ypp" { (yyval.expr) = create(new CallTemplate((yyvsp[(2) - (5)].qName), parseInfo->templateWithParams), (yyloc), parseInfo); parseInfo->templateWithParametersHandled(); @@ -6123,7 +6180,7 @@ yyreduce: case 280: /* Line 1269 of yacc.c. */ -#line 3211 "querytransformparser.ypp" +#line 3268 "querytransformparser.ypp" { parseInfo->startParsingWithParam(); } @@ -6131,7 +6188,7 @@ yyreduce: case 281: /* Line 1269 of yacc.c. */ -#line 3215 "querytransformparser.ypp" +#line 3272 "querytransformparser.ypp" { parseInfo->endParsingWithParam(); } @@ -6139,42 +6196,42 @@ yyreduce: case 282: /* Line 1269 of yacc.c. */ -#line 3220 "querytransformparser.ypp" +#line 3277 "querytransformparser.ypp" { } break; case 283: /* Line 1269 of yacc.c. */ -#line 3223 "querytransformparser.ypp" +#line 3280 "querytransformparser.ypp" { } break; case 284: /* Line 1269 of yacc.c. */ -#line 3226 "querytransformparser.ypp" +#line 3283 "querytransformparser.ypp" { } break; case 285: /* Line 1269 of yacc.c. */ -#line 3230 "querytransformparser.ypp" +#line 3287 "querytransformparser.ypp" { } break; case 286: /* Line 1269 of yacc.c. */ -#line 3233 "querytransformparser.ypp" +#line 3290 "querytransformparser.ypp" { } break; case 287: /* Line 1269 of yacc.c. */ -#line 3237 "querytransformparser.ypp" +#line 3294 "querytransformparser.ypp" { /* Note, this grammar rule is invoked for @c xsl:param @em and @c * xsl:with-param. */ @@ -6242,7 +6299,7 @@ yyreduce: case 288: /* Line 1269 of yacc.c. */ -#line 3302 "querytransformparser.ypp" +#line 3359 "querytransformparser.ypp" { (yyval.enums.Bool) = false; } @@ -6250,7 +6307,7 @@ yyreduce: case 289: /* Line 1269 of yacc.c. */ -#line 3306 "querytransformparser.ypp" +#line 3363 "querytransformparser.ypp" { (yyval.enums.Bool) = true; } @@ -6258,7 +6315,7 @@ yyreduce: case 290: /* Line 1269 of yacc.c. */ -#line 3311 "querytransformparser.ypp" +#line 3368 "querytransformparser.ypp" { (yyval.expr) = Expression::Ptr(); } @@ -6266,7 +6323,7 @@ yyreduce: case 291: /* Line 1269 of yacc.c. */ -#line 3315 "querytransformparser.ypp" +#line 3372 "querytransformparser.ypp" { (yyval.expr) = (yyvsp[(2) - (2)].expr); } @@ -6274,7 +6331,7 @@ yyreduce: case 292: /* Line 1269 of yacc.c. */ -#line 3324 "querytransformparser.ypp" +#line 3381 "querytransformparser.ypp" { (yyval.enums.pathKind) = Path::RegularPath; } @@ -6282,7 +6339,7 @@ yyreduce: case 293: /* Line 1269 of yacc.c. */ -#line 3328 "querytransformparser.ypp" +#line 3385 "querytransformparser.ypp" { (yyval.enums.pathKind) = Path::XSLTForEach; } @@ -6290,7 +6347,7 @@ yyreduce: case 294: /* Line 1269 of yacc.c. */ -#line 3332 "querytransformparser.ypp" +#line 3389 "querytransformparser.ypp" { (yyval.enums.pathKind) = Path::ForApplyTemplate; } @@ -6298,7 +6355,7 @@ yyreduce: case 296: /* Line 1269 of yacc.c. */ -#line 3338 "querytransformparser.ypp" +#line 3395 "querytransformparser.ypp" { (yyval.expr) = create(GenericPredicate::create((yyvsp[(1) - (4)].expr), (yyvsp[(3) - (4)].expr), parseInfo->staticContext, fromYYLTYPE((yyloc), parseInfo)), (yyloc), parseInfo); } @@ -6306,7 +6363,7 @@ yyreduce: case 299: /* Line 1269 of yacc.c. */ -#line 3346 "querytransformparser.ypp" +#line 3403 "querytransformparser.ypp" { if((yyvsp[(1) - (1)].enums.axis) == QXmlNodeModelIndex::AxisAttribute) parseInfo->nodeTestSource = BuiltinTypes::attribute; @@ -6315,7 +6372,7 @@ yyreduce: case 300: /* Line 1269 of yacc.c. */ -#line 3351 "querytransformparser.ypp" +#line 3408 "querytransformparser.ypp" { if((yyvsp[(3) - (3)].itemType)) { @@ -6344,7 +6401,7 @@ yyreduce: case 304: /* Line 1269 of yacc.c. */ -#line 3381 "querytransformparser.ypp" +#line 3438 "querytransformparser.ypp" { if((yyvsp[(1) - (2)].enums.axis) == QXmlNodeModelIndex::AxisNamespace) { @@ -6356,84 +6413,114 @@ yyreduce: } else (yyval.enums.axis) = (yyvsp[(1) - (2)].enums.axis); + + switch((yyvsp[(1) - (2)].enums.axis)) + { + case QXmlNodeModelIndex::AxisAttribute: + { + allowedIn(QueryLanguages( QXmlQuery::XPath20 + | QXmlQuery::XQuery10 + | QXmlQuery::XmlSchema11IdentityConstraintField + | QXmlQuery::XSLT20), + parseInfo, (yyloc)); + break; + } + case QXmlNodeModelIndex::AxisChild: + { + allowedIn(QueryLanguages( QXmlQuery::XPath20 + | QXmlQuery::XQuery10 + | QXmlQuery::XmlSchema11IdentityConstraintField + | QXmlQuery::XmlSchema11IdentityConstraintSelector + | QXmlQuery::XSLT20), + parseInfo, (yyloc)); + break; + } + default: + { + allowedIn(QueryLanguages( QXmlQuery::XPath20 + | QXmlQuery::XQuery10 + | QXmlQuery::XSLT20), + parseInfo, (yyloc)); + } + } } break; case 305: /* Line 1269 of yacc.c. */ -#line 3394 "querytransformparser.ypp" +#line 3481 "querytransformparser.ypp" {(yyval.enums.axis) = QXmlNodeModelIndex::AxisAncestorOrSelf ;} break; case 306: /* Line 1269 of yacc.c. */ -#line 3395 "querytransformparser.ypp" +#line 3482 "querytransformparser.ypp" {(yyval.enums.axis) = QXmlNodeModelIndex::AxisAncestor ;} break; case 307: /* Line 1269 of yacc.c. */ -#line 3396 "querytransformparser.ypp" +#line 3483 "querytransformparser.ypp" {(yyval.enums.axis) = QXmlNodeModelIndex::AxisAttribute ;} break; case 308: /* Line 1269 of yacc.c. */ -#line 3397 "querytransformparser.ypp" +#line 3484 "querytransformparser.ypp" {(yyval.enums.axis) = QXmlNodeModelIndex::AxisChild ;} break; case 309: /* Line 1269 of yacc.c. */ -#line 3398 "querytransformparser.ypp" +#line 3485 "querytransformparser.ypp" {(yyval.enums.axis) = QXmlNodeModelIndex::AxisDescendantOrSelf;} break; case 310: /* Line 1269 of yacc.c. */ -#line 3399 "querytransformparser.ypp" +#line 3486 "querytransformparser.ypp" {(yyval.enums.axis) = QXmlNodeModelIndex::AxisDescendant ;} break; case 311: /* Line 1269 of yacc.c. */ -#line 3400 "querytransformparser.ypp" +#line 3487 "querytransformparser.ypp" {(yyval.enums.axis) = QXmlNodeModelIndex::AxisFollowing ;} break; case 312: /* Line 1269 of yacc.c. */ -#line 3401 "querytransformparser.ypp" +#line 3488 "querytransformparser.ypp" {(yyval.enums.axis) = QXmlNodeModelIndex::AxisPreceding ;} break; case 313: /* Line 1269 of yacc.c. */ -#line 3402 "querytransformparser.ypp" +#line 3489 "querytransformparser.ypp" {(yyval.enums.axis) = QXmlNodeModelIndex::AxisFollowingSibling;} break; case 314: /* Line 1269 of yacc.c. */ -#line 3403 "querytransformparser.ypp" +#line 3490 "querytransformparser.ypp" {(yyval.enums.axis) = QXmlNodeModelIndex::AxisPrecedingSibling;} break; case 315: /* Line 1269 of yacc.c. */ -#line 3404 "querytransformparser.ypp" +#line 3491 "querytransformparser.ypp" {(yyval.enums.axis) = QXmlNodeModelIndex::AxisParent ;} break; case 316: /* Line 1269 of yacc.c. */ -#line 3405 "querytransformparser.ypp" +#line 3492 "querytransformparser.ypp" {(yyval.enums.axis) = QXmlNodeModelIndex::AxisSelf ;} break; case 317: /* Line 1269 of yacc.c. */ -#line 3408 "querytransformparser.ypp" +#line 3495 "querytransformparser.ypp" { parseInfo->nodeTestSource = BuiltinTypes::attribute; } @@ -6441,8 +6528,9 @@ yyreduce: case 318: /* Line 1269 of yacc.c. */ -#line 3412 "querytransformparser.ypp" +#line 3499 "querytransformparser.ypp" { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XSLT20 | QXmlQuery::XmlSchema11IdentityConstraintField), parseInfo, (yyloc)); (yyval.expr) = create(new AxisStep(QXmlNodeModelIndex::AxisAttribute, (yyvsp[(3) - (3)].itemType)), (yyloc), parseInfo); parseInfo->restoreNodeTestSource(); @@ -6451,7 +6539,7 @@ yyreduce: case 319: /* Line 1269 of yacc.c. */ -#line 3418 "querytransformparser.ypp" +#line 3506 "querytransformparser.ypp" { ItemType::Ptr nodeTest; @@ -6466,7 +6554,7 @@ yyreduce: case 320: /* Line 1269 of yacc.c. */ -#line 3429 "querytransformparser.ypp" +#line 3517 "querytransformparser.ypp" { (yyval.expr) = create(new AxisStep(QXmlNodeModelIndex::AxisAttribute, (yyvsp[(1) - (1)].itemType)), (yyloc), parseInfo); } @@ -6474,15 +6562,23 @@ yyreduce: case 322: /* Line 1269 of yacc.c. */ -#line 3436 "querytransformparser.ypp" +#line 3524 "querytransformparser.ypp" { (yyval.expr) = create(new AxisStep(QXmlNodeModelIndex::AxisParent, BuiltinTypes::node), (yyloc), parseInfo); } break; + case 324: +/* Line 1269 of yacc.c. */ +#line 3530 "querytransformparser.ypp" + { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, (yyloc)); + } + break; + case 325: /* Line 1269 of yacc.c. */ -#line 3444 "querytransformparser.ypp" +#line 3535 "querytransformparser.ypp" { (yyval.itemType) = QNameTest::create(parseInfo->nodeTestSource, (yyvsp[(1) - (1)].qName)); } @@ -6490,7 +6586,7 @@ yyreduce: case 327: /* Line 1269 of yacc.c. */ -#line 3450 "querytransformparser.ypp" +#line 3541 "querytransformparser.ypp" { (yyval.itemType) = parseInfo->nodeTestSource; } @@ -6498,7 +6594,7 @@ yyreduce: case 328: /* Line 1269 of yacc.c. */ -#line 3454 "querytransformparser.ypp" +#line 3545 "querytransformparser.ypp" { const NamePool::Ptr np(parseInfo->staticContext->namePool()); const ReflectYYLTYPE ryy((yyloc), parseInfo); @@ -6511,8 +6607,9 @@ yyreduce: case 329: /* Line 1269 of yacc.c. */ -#line 3463 "querytransformparser.ypp" +#line 3554 "querytransformparser.ypp" { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, (yyloc)); const QXmlName::LocalNameCode c = parseInfo->staticContext->namePool()->allocateLocalName((yyvsp[(1) - (1)].sval)); (yyval.itemType) = LocalNameTest::create(parseInfo->nodeTestSource, c); } @@ -6520,15 +6617,16 @@ yyreduce: case 331: /* Line 1269 of yacc.c. */ -#line 3470 "querytransformparser.ypp" +#line 3562 "querytransformparser.ypp" { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, (yyloc)); (yyval.expr) = create(GenericPredicate::create((yyvsp[(1) - (4)].expr), (yyvsp[(3) - (4)].expr), parseInfo->staticContext, fromYYLTYPE((yylsp[(4) - (4)]), parseInfo)), (yyloc), parseInfo); } break; case 339: /* Line 1269 of yacc.c. */ -#line 3482 "querytransformparser.ypp" +#line 3575 "querytransformparser.ypp" { (yyval.expr) = create(new ApplyTemplate(parseInfo->modeFor((yyvsp[(2) - (5)].qName)), parseInfo->templateWithParams, @@ -6541,7 +6639,7 @@ yyreduce: case 341: /* Line 1269 of yacc.c. */ -#line 3493 "querytransformparser.ypp" +#line 3586 "querytransformparser.ypp" { (yyval.expr) = create(new Literal(AtomicString::fromValue((yyvsp[(1) - (1)].sval))), (yyloc), parseInfo); } @@ -6549,31 +6647,34 @@ yyreduce: case 342: /* Line 1269 of yacc.c. */ -#line 3498 "querytransformparser.ypp" +#line 3591 "querytransformparser.ypp" { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, (yyloc)); (yyval.expr) = createNumericLiteral<Double>((yyvsp[(1) - (1)].sval), (yyloc), parseInfo); } break; case 343: /* Line 1269 of yacc.c. */ -#line 3502 "querytransformparser.ypp" +#line 3596 "querytransformparser.ypp" { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, (yyloc)); (yyval.expr) = createNumericLiteral<Numeric>((yyvsp[(1) - (1)].sval), (yyloc), parseInfo); } break; case 344: /* Line 1269 of yacc.c. */ -#line 3507 "querytransformparser.ypp" +#line 3602 "querytransformparser.ypp" { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, (yyloc)); (yyval.expr) = resolveVariable((yyvsp[(2) - (2)].qName), (yyloc), parseInfo, false); } break; case 345: /* Line 1269 of yacc.c. */ -#line 3512 "querytransformparser.ypp" +#line 3608 "querytransformparser.ypp" { /* See: http://www.w3.org/TR/xpath20/#id-variables */ (yyval.qName) = parseInfo->staticContext->namePool()->allocateQName(QString(), (yyvsp[(1) - (1)].sval)); @@ -6582,7 +6683,7 @@ yyreduce: case 346: /* Line 1269 of yacc.c. */ -#line 3517 "querytransformparser.ypp" +#line 3613 "querytransformparser.ypp" { (yyval.qName) = (yyvsp[(1) - (1)].qName); } @@ -6590,23 +6691,25 @@ yyreduce: case 347: /* Line 1269 of yacc.c. */ -#line 3522 "querytransformparser.ypp" +#line 3618 "querytransformparser.ypp" { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, (yyloc)); (yyval.expr) = (yyvsp[(2) - (3)].expr); } break; case 348: /* Line 1269 of yacc.c. */ -#line 3526 "querytransformparser.ypp" +#line 3623 "querytransformparser.ypp" { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, (yyloc)); (yyval.expr) = create(new EmptySequence, (yyloc), parseInfo); } break; case 349: /* Line 1269 of yacc.c. */ -#line 3531 "querytransformparser.ypp" +#line 3629 "querytransformparser.ypp" { (yyval.expr) = create(new ContextItem(), (yyloc), parseInfo); } @@ -6614,7 +6717,7 @@ yyreduce: case 350: /* Line 1269 of yacc.c. */ -#line 3536 "querytransformparser.ypp" +#line 3634 "querytransformparser.ypp" { (yyval.expr) = (yyvsp[(2) - (2)].expr); } @@ -6622,8 +6725,9 @@ yyreduce: case 351: /* Line 1269 of yacc.c. */ -#line 3541 "querytransformparser.ypp" +#line 3639 "querytransformparser.ypp" { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, (yyloc)); if(XPathHelper::isReservedNamespace((yyvsp[(1) - (4)].qName).namespaceURI()) || (yyvsp[(1) - (4)].qName).namespaceURI() == StandardNamespaces::InternalXSLT) { /* We got a call to a builtin function. */ const ReflectYYLTYPE ryy((yyloc), parseInfo); @@ -6653,7 +6757,7 @@ yyreduce: case 352: /* Line 1269 of yacc.c. */ -#line 3569 "querytransformparser.ypp" +#line 3668 "querytransformparser.ypp" { (yyval.expressionList) = Expression::List(); } @@ -6661,7 +6765,7 @@ yyreduce: case 353: /* Line 1269 of yacc.c. */ -#line 3574 "querytransformparser.ypp" +#line 3673 "querytransformparser.ypp" { Expression::List list; list.append((yyvsp[(1) - (1)].expr)); @@ -6671,15 +6775,15 @@ yyreduce: case 355: /* Line 1269 of yacc.c. */ -#line 3583 "querytransformparser.ypp" +#line 3682 "querytransformparser.ypp" { - disallowedConstruct(parseInfo, (yyloc)); + allowedIn(QXmlQuery::XQuery10, parseInfo, (yyloc)); } break; case 360: /* Line 1269 of yacc.c. */ -#line 3624 "querytransformparser.ypp" +#line 3726 "querytransformparser.ypp" { (yyval.enums.tokenizerPosition) = parseInfo->tokenizer->commenceScanOnly(); parseInfo->scanOnlyStack.push(true); @@ -6688,7 +6792,7 @@ yyreduce: case 361: /* Line 1269 of yacc.c. */ -#line 3633 "querytransformparser.ypp" +#line 3735 "querytransformparser.ypp" { ++parseInfo->elementConstructorDepth; Expression::List constructors; @@ -6836,7 +6940,7 @@ yyreduce: case 362: /* Line 1269 of yacc.c. */ -#line 3779 "querytransformparser.ypp" +#line 3881 "querytransformparser.ypp" { /* We add the content constructor after the attribute constructors. This might result * in nested ExpressionSequences, but it will be optimized away later on. */ @@ -6935,7 +7039,7 @@ yyreduce: case 363: /* Line 1269 of yacc.c. */ -#line 3875 "querytransformparser.ypp" +#line 3977 "querytransformparser.ypp" { (yyval.expr) = create(new EmptySequence(), (yyloc), parseInfo); } @@ -6943,7 +7047,7 @@ yyreduce: case 364: /* Line 1269 of yacc.c. */ -#line 3879 "querytransformparser.ypp" +#line 3981 "querytransformparser.ypp" { if(!(yyvsp[(4) - (5)].qName).isLexicallyEqual(parseInfo->tagStack.top())) { @@ -6965,7 +7069,7 @@ yyreduce: case 365: /* Line 1269 of yacc.c. */ -#line 3898 "querytransformparser.ypp" +#line 4000 "querytransformparser.ypp" { (yyval.attributeHolders) = AttributeHolderVector(); } @@ -6973,7 +7077,7 @@ yyreduce: case 366: /* Line 1269 of yacc.c. */ -#line 3902 "querytransformparser.ypp" +#line 4004 "querytransformparser.ypp" { (yyvsp[(1) - (2)].attributeHolders).append((yyvsp[(2) - (2)].attributeHolder)); (yyval.attributeHolders) = (yyvsp[(1) - (2)].attributeHolders); @@ -6982,7 +7086,7 @@ yyreduce: case 367: /* Line 1269 of yacc.c. */ -#line 3908 "querytransformparser.ypp" +#line 4010 "querytransformparser.ypp" { (yyval.attributeHolder) = qMakePair((yyvsp[(1) - (3)].sval), (yyvsp[(3) - (3)].expr)); } @@ -6990,7 +7094,7 @@ yyreduce: case 368: /* Line 1269 of yacc.c. */ -#line 3913 "querytransformparser.ypp" +#line 4015 "querytransformparser.ypp" { (yyval.expr) = createDirAttributeValue((yyvsp[(2) - (3)].expressionList), parseInfo, (yyloc)); } @@ -6998,7 +7102,7 @@ yyreduce: case 369: /* Line 1269 of yacc.c. */ -#line 3918 "querytransformparser.ypp" +#line 4020 "querytransformparser.ypp" { (yyval.expr) = createDirAttributeValue((yyvsp[(2) - (3)].expressionList), parseInfo, (yyloc)); } @@ -7006,7 +7110,7 @@ yyreduce: case 370: /* Line 1269 of yacc.c. */ -#line 3923 "querytransformparser.ypp" +#line 4025 "querytransformparser.ypp" { (yyval.expressionList) = Expression::List(); } @@ -7014,7 +7118,7 @@ yyreduce: case 371: /* Line 1269 of yacc.c. */ -#line 3927 "querytransformparser.ypp" +#line 4029 "querytransformparser.ypp" { Expression::Ptr content((yyvsp[(1) - (2)].expr)); @@ -7028,7 +7132,7 @@ yyreduce: case 372: /* Line 1269 of yacc.c. */ -#line 3937 "querytransformparser.ypp" +#line 4039 "querytransformparser.ypp" { (yyvsp[(2) - (2)].expressionList).prepend(create(new Literal(AtomicString::fromValue((yyvsp[(1) - (2)].sval))), (yyloc), parseInfo)); (yyval.expressionList) = (yyvsp[(2) - (2)].expressionList); @@ -7037,7 +7141,7 @@ yyreduce: case 373: /* Line 1269 of yacc.c. */ -#line 3943 "querytransformparser.ypp" +#line 4045 "querytransformparser.ypp" { (yyval.expressionList) = Expression::List(); parseInfo->isPreviousEnclosedExpr = false; @@ -7046,7 +7150,7 @@ yyreduce: case 374: /* Line 1269 of yacc.c. */ -#line 3948 "querytransformparser.ypp" +#line 4050 "querytransformparser.ypp" { (yyvsp[(1) - (2)].expressionList).append((yyvsp[(2) - (2)].expr)); (yyval.expressionList) = (yyvsp[(1) - (2)].expressionList); @@ -7056,7 +7160,7 @@ yyreduce: case 375: /* Line 1269 of yacc.c. */ -#line 3954 "querytransformparser.ypp" +#line 4056 "querytransformparser.ypp" { if(parseInfo->staticContext->boundarySpacePolicy() == StaticContext::BSPStrip && XPathHelper::isWhitespaceOnly((yyvsp[(2) - (2)].sval))) @@ -7074,7 +7178,7 @@ yyreduce: case 376: /* Line 1269 of yacc.c. */ -#line 3968 "querytransformparser.ypp" +#line 4070 "querytransformparser.ypp" { (yyvsp[(1) - (2)].expressionList).append(create(new TextNodeConstructor(create(new Literal(AtomicString::fromValue((yyvsp[(2) - (2)].sval))), (yyloc), parseInfo)), (yyloc), parseInfo)); (yyval.expressionList) = (yyvsp[(1) - (2)].expressionList); @@ -7084,7 +7188,7 @@ yyreduce: case 377: /* Line 1269 of yacc.c. */ -#line 3974 "querytransformparser.ypp" +#line 4076 "querytransformparser.ypp" { /* We insert a text node constructor that send an empty text node between * the two enclosed expressions, in order to ensure that no space is inserted. @@ -7104,7 +7208,7 @@ yyreduce: case 378: /* Line 1269 of yacc.c. */ -#line 3991 "querytransformparser.ypp" +#line 4093 "querytransformparser.ypp" { (yyval.expr) = create(new CommentConstructor(create(new Literal(AtomicString::fromValue((yyvsp[(2) - (2)].sval))), (yyloc), parseInfo)), (yyloc), parseInfo); } @@ -7112,7 +7216,7 @@ yyreduce: case 379: /* Line 1269 of yacc.c. */ -#line 3996 "querytransformparser.ypp" +#line 4098 "querytransformparser.ypp" { const ReflectYYLTYPE ryy((yyloc), parseInfo); NCNameConstructor::validateTargetName<StaticContext::Ptr, @@ -7128,9 +7232,9 @@ yyreduce: case 387: /* Line 1269 of yacc.c. */ -#line 4017 "querytransformparser.ypp" +#line 4119 "querytransformparser.ypp" { - disallowedConstruct(parseInfo, (yyloc), (yyvsp[(2) - (3)].enums.Bool)); + allowedIn(QXmlQuery::XQuery10, parseInfo, (yyloc), (yyvsp[(2) - (3)].enums.Bool)); (yyval.expr) = create(new DocumentConstructor((yyvsp[(3) - (3)].expr)), (yyloc), parseInfo); } @@ -7138,7 +7242,7 @@ yyreduce: case 388: /* Line 1269 of yacc.c. */ -#line 4024 "querytransformparser.ypp" +#line 4126 "querytransformparser.ypp" { /* This value is incremented before the action below is executed. */ ++parseInfo->elementConstructorDepth; @@ -7147,10 +7251,10 @@ yyreduce: case 389: /* Line 1269 of yacc.c. */ -#line 4029 "querytransformparser.ypp" +#line 4131 "querytransformparser.ypp" { Q_ASSERT(5); - disallowedConstruct(parseInfo, (yyloc), (yyvsp[(2) - (5)].enums.Bool)); + allowedIn(QXmlQuery::XQuery10, parseInfo, (yyloc), (yyvsp[(2) - (5)].enums.Bool)); Expression::Ptr effExpr; @@ -7184,7 +7288,7 @@ yyreduce: case 390: /* Line 1269 of yacc.c. */ -#line 4063 "querytransformparser.ypp" +#line 4165 "querytransformparser.ypp" { (yyval.enums.Bool) = false; } @@ -7192,7 +7296,7 @@ yyreduce: case 391: /* Line 1269 of yacc.c. */ -#line 4067 "querytransformparser.ypp" +#line 4169 "querytransformparser.ypp" { (yyval.enums.Bool) = true; } @@ -7200,9 +7304,9 @@ yyreduce: case 392: /* Line 1269 of yacc.c. */ -#line 4075 "querytransformparser.ypp" +#line 4177 "querytransformparser.ypp" { - disallowedConstruct(parseInfo, (yyloc), (yyvsp[(2) - (4)].enums.Bool)); + allowedIn(QXmlQuery::XQuery10, parseInfo, (yyloc), (yyvsp[(2) - (4)].enums.Bool)); const Expression::Ptr name(create(new AttributeNameValidator((yyvsp[(3) - (4)].expr)), (yyloc), parseInfo)); @@ -7215,7 +7319,7 @@ yyreduce: case 393: /* Line 1269 of yacc.c. */ -#line 4087 "querytransformparser.ypp" +#line 4189 "querytransformparser.ypp" { (yyval.expr) = create(new TextNodeConstructor(createSimpleContent((yyvsp[(3) - (3)].expr), (yyloc), parseInfo)), (yyloc), parseInfo); } @@ -7223,9 +7327,9 @@ yyreduce: case 394: /* Line 1269 of yacc.c. */ -#line 4092 "querytransformparser.ypp" +#line 4194 "querytransformparser.ypp" { - disallowedConstruct(parseInfo, (yyloc), (yyvsp[(2) - (3)].enums.Bool)); + allowedIn(QXmlQuery::XQuery10, parseInfo, (yyloc), (yyvsp[(2) - (3)].enums.Bool)); (yyval.expr) = create(new CommentConstructor(createSimpleContent((yyvsp[(3) - (3)].expr), (yyloc), parseInfo)), (yyloc), parseInfo); } @@ -7233,9 +7337,9 @@ yyreduce: case 395: /* Line 1269 of yacc.c. */ -#line 4099 "querytransformparser.ypp" +#line 4201 "querytransformparser.ypp" { - disallowedConstruct(parseInfo, (yyloc), (yyvsp[(2) - (3)].expr)); + allowedIn(QXmlQuery::XQuery10, parseInfo, (yyloc), (yyvsp[(2) - (3)].expr)); if((yyvsp[(3) - (3)].expr)) { @@ -7248,7 +7352,7 @@ yyreduce: case 396: /* Line 1269 of yacc.c. */ -#line 4110 "querytransformparser.ypp" +#line 4212 "querytransformparser.ypp" { parseInfo->nodeTestSource = BuiltinTypes::attribute; } @@ -7256,7 +7360,7 @@ yyreduce: case 397: /* Line 1269 of yacc.c. */ -#line 4114 "querytransformparser.ypp" +#line 4216 "querytransformparser.ypp" { parseInfo->restoreNodeTestSource(); } @@ -7264,7 +7368,7 @@ yyreduce: case 398: /* Line 1269 of yacc.c. */ -#line 4117 "querytransformparser.ypp" +#line 4219 "querytransformparser.ypp" { (yyval.expr) = create(new Literal(toItem(QNameValue::fromValue(parseInfo->staticContext->namePool(), (yyvsp[(2) - (3)].qName)))), (yyloc), parseInfo); } @@ -7272,7 +7376,7 @@ yyreduce: case 400: /* Line 1269 of yacc.c. */ -#line 4123 "querytransformparser.ypp" +#line 4225 "querytransformparser.ypp" { (yyval.expr) = create(new Literal(toItem(QNameValue::fromValue(parseInfo->staticContext->namePool(), (yyvsp[(1) - (1)].qName)))), (yyloc), parseInfo); } @@ -7280,7 +7384,7 @@ yyreduce: case 402: /* Line 1269 of yacc.c. */ -#line 4129 "querytransformparser.ypp" +#line 4231 "querytransformparser.ypp" { if(BuiltinTypes::xsQName->xdtTypeMatches((yyvsp[(1) - (1)].expr)->staticType()->itemType())) (yyval.expr) = (yyvsp[(1) - (1)].expr); @@ -7295,7 +7399,7 @@ yyreduce: case 403: /* Line 1269 of yacc.c. */ -#line 4144 "querytransformparser.ypp" +#line 4246 "querytransformparser.ypp" { (yyval.expr) = create(new NCNameConstructor(create(new Literal(AtomicString::fromValue((yyvsp[(1) - (1)].sval))), (yyloc), parseInfo)), (yyloc), parseInfo); } @@ -7303,7 +7407,7 @@ yyreduce: case 404: /* Line 1269 of yacc.c. */ -#line 4148 "querytransformparser.ypp" +#line 4250 "querytransformparser.ypp" { (yyval.expr) = create(new NCNameConstructor((yyvsp[(1) - (1)].expr)), (yyloc), parseInfo); } @@ -7311,7 +7415,7 @@ yyreduce: case 405: /* Line 1269 of yacc.c. */ -#line 4157 "querytransformparser.ypp" +#line 4259 "querytransformparser.ypp" { (yyval.expr) = create(new ComputedNamespaceConstructor((yyvsp[(2) - (3)].expr), (yyvsp[(3) - (3)].expr)), (yyloc), parseInfo); } @@ -7319,7 +7423,7 @@ yyreduce: case 406: /* Line 1269 of yacc.c. */ -#line 4162 "querytransformparser.ypp" +#line 4264 "querytransformparser.ypp" { (yyval.sequenceType) = makeGenericSequenceType((yyvsp[(1) - (1)].itemType), Cardinality::exactlyOne()); } @@ -7327,7 +7431,7 @@ yyreduce: case 407: /* Line 1269 of yacc.c. */ -#line 4166 "querytransformparser.ypp" +#line 4268 "querytransformparser.ypp" { (yyval.sequenceType) = makeGenericSequenceType((yyvsp[(1) - (2)].itemType), Cardinality::zeroOrOne()); } @@ -7335,7 +7439,7 @@ yyreduce: case 408: /* Line 1269 of yacc.c. */ -#line 4171 "querytransformparser.ypp" +#line 4273 "querytransformparser.ypp" { (yyval.sequenceType) = CommonSequenceTypes::ZeroOrMoreItems; } @@ -7343,7 +7447,7 @@ yyreduce: case 409: /* Line 1269 of yacc.c. */ -#line 4175 "querytransformparser.ypp" +#line 4277 "querytransformparser.ypp" { (yyval.sequenceType) = (yyvsp[(2) - (2)].sequenceType); } @@ -7351,7 +7455,7 @@ yyreduce: case 410: /* Line 1269 of yacc.c. */ -#line 4180 "querytransformparser.ypp" +#line 4282 "querytransformparser.ypp" { (yyval.sequenceType) = makeGenericSequenceType((yyvsp[(1) - (2)].itemType), (yyvsp[(2) - (2)].cardinality)); } @@ -7359,7 +7463,7 @@ yyreduce: case 411: /* Line 1269 of yacc.c. */ -#line 4185 "querytransformparser.ypp" +#line 4287 "querytransformparser.ypp" { (yyval.sequenceType) = CommonSequenceTypes::Empty; } @@ -7367,31 +7471,31 @@ yyreduce: case 412: /* Line 1269 of yacc.c. */ -#line 4189 "querytransformparser.ypp" +#line 4291 "querytransformparser.ypp" {(yyval.cardinality) = Cardinality::exactlyOne();} break; case 413: /* Line 1269 of yacc.c. */ -#line 4190 "querytransformparser.ypp" +#line 4292 "querytransformparser.ypp" {(yyval.cardinality) = Cardinality::oneOrMore();} break; case 414: /* Line 1269 of yacc.c. */ -#line 4191 "querytransformparser.ypp" +#line 4293 "querytransformparser.ypp" {(yyval.cardinality) = Cardinality::zeroOrMore();} break; case 415: /* Line 1269 of yacc.c. */ -#line 4192 "querytransformparser.ypp" +#line 4294 "querytransformparser.ypp" {(yyval.cardinality) = Cardinality::zeroOrOne();} break; case 419: /* Line 1269 of yacc.c. */ -#line 4198 "querytransformparser.ypp" +#line 4300 "querytransformparser.ypp" { (yyval.itemType) = BuiltinTypes::item; } @@ -7399,7 +7503,7 @@ yyreduce: case 420: /* Line 1269 of yacc.c. */ -#line 4203 "querytransformparser.ypp" +#line 4305 "querytransformparser.ypp" { const SchemaType::Ptr t(parseInfo->staticContext->schemaDefinitions()->createSchemaType((yyvsp[(1) - (1)].qName))); @@ -7435,7 +7539,7 @@ yyreduce: case 428: /* Line 1269 of yacc.c. */ -#line 4247 "querytransformparser.ypp" +#line 4349 "querytransformparser.ypp" { (yyval.itemType) = BuiltinTypes::node; } @@ -7443,7 +7547,7 @@ yyreduce: case 429: /* Line 1269 of yacc.c. */ -#line 4252 "querytransformparser.ypp" +#line 4354 "querytransformparser.ypp" { (yyval.itemType) = BuiltinTypes::document; } @@ -7451,7 +7555,7 @@ yyreduce: case 430: /* Line 1269 of yacc.c. */ -#line 4257 "querytransformparser.ypp" +#line 4359 "querytransformparser.ypp" { // TODO support for document element testing (yyval.itemType) = BuiltinTypes::document; @@ -7460,7 +7564,7 @@ yyreduce: case 433: /* Line 1269 of yacc.c. */ -#line 4266 "querytransformparser.ypp" +#line 4368 "querytransformparser.ypp" { (yyval.itemType) = BuiltinTypes::text; } @@ -7468,7 +7572,7 @@ yyreduce: case 434: /* Line 1269 of yacc.c. */ -#line 4271 "querytransformparser.ypp" +#line 4373 "querytransformparser.ypp" { (yyval.itemType) = BuiltinTypes::comment; } @@ -7476,7 +7580,7 @@ yyreduce: case 435: /* Line 1269 of yacc.c. */ -#line 4276 "querytransformparser.ypp" +#line 4378 "querytransformparser.ypp" { (yyval.itemType) = BuiltinTypes::pi; } @@ -7484,7 +7588,7 @@ yyreduce: case 436: /* Line 1269 of yacc.c. */ -#line 4281 "querytransformparser.ypp" +#line 4383 "querytransformparser.ypp" { (yyval.itemType) = LocalNameTest::create(BuiltinTypes::pi, parseInfo->staticContext->namePool()->allocateLocalName((yyvsp[(3) - (4)].sval))); } @@ -7492,7 +7596,7 @@ yyreduce: case 437: /* Line 1269 of yacc.c. */ -#line 4286 "querytransformparser.ypp" +#line 4388 "querytransformparser.ypp" { if(QXmlUtils::isNCName((yyvsp[(3) - (4)].sval))) { @@ -7511,7 +7615,7 @@ yyreduce: case 440: /* Line 1269 of yacc.c. */ -#line 4305 "querytransformparser.ypp" +#line 4407 "querytransformparser.ypp" { (yyval.itemType) = BuiltinTypes::attribute; } @@ -7519,7 +7623,7 @@ yyreduce: case 441: /* Line 1269 of yacc.c. */ -#line 4310 "querytransformparser.ypp" +#line 4412 "querytransformparser.ypp" { (yyval.itemType) = BuiltinTypes::attribute; } @@ -7527,7 +7631,7 @@ yyreduce: case 442: /* Line 1269 of yacc.c. */ -#line 4315 "querytransformparser.ypp" +#line 4417 "querytransformparser.ypp" { (yyval.itemType) = QNameTest::create(BuiltinTypes::attribute, (yyvsp[(3) - (4)].qName)); } @@ -7535,7 +7639,7 @@ yyreduce: case 443: /* Line 1269 of yacc.c. */ -#line 4319 "querytransformparser.ypp" +#line 4421 "querytransformparser.ypp" { const SchemaType::Ptr t(parseInfo->staticContext->schemaDefinitions()->createSchemaType((yyvsp[(5) - (6)].qName))); @@ -7551,7 +7655,7 @@ yyreduce: case 444: /* Line 1269 of yacc.c. */ -#line 4331 "querytransformparser.ypp" +#line 4433 "querytransformparser.ypp" { const SchemaType::Ptr t(parseInfo->staticContext->schemaDefinitions()->createSchemaType((yyvsp[(5) - (6)].qName))); @@ -7567,7 +7671,7 @@ yyreduce: case 445: /* Line 1269 of yacc.c. */ -#line 4344 "querytransformparser.ypp" +#line 4446 "querytransformparser.ypp" { parseInfo->staticContext->error(QtXmlPatterns::tr("%1 is not in the in-scope attribute " "declarations. Note that the schema import " @@ -7580,7 +7684,7 @@ yyreduce: case 446: /* Line 1269 of yacc.c. */ -#line 4354 "querytransformparser.ypp" +#line 4456 "querytransformparser.ypp" { (yyval.itemType) = BuiltinTypes::element; } @@ -7588,7 +7692,7 @@ yyreduce: case 447: /* Line 1269 of yacc.c. */ -#line 4359 "querytransformparser.ypp" +#line 4461 "querytransformparser.ypp" { (yyval.itemType) = BuiltinTypes::element; } @@ -7596,7 +7700,7 @@ yyreduce: case 448: /* Line 1269 of yacc.c. */ -#line 4364 "querytransformparser.ypp" +#line 4466 "querytransformparser.ypp" { (yyval.itemType) = QNameTest::create(BuiltinTypes::element, (yyvsp[(3) - (4)].qName)); } @@ -7604,7 +7708,7 @@ yyreduce: case 449: /* Line 1269 of yacc.c. */ -#line 4369 "querytransformparser.ypp" +#line 4471 "querytransformparser.ypp" { const SchemaType::Ptr t(parseInfo->staticContext->schemaDefinitions()->createSchemaType((yyvsp[(5) - (7)].qName))); @@ -7621,7 +7725,7 @@ yyreduce: case 450: /* Line 1269 of yacc.c. */ -#line 4383 "querytransformparser.ypp" +#line 4485 "querytransformparser.ypp" { const SchemaType::Ptr t(parseInfo->staticContext->schemaDefinitions()->createSchemaType((yyvsp[(5) - (7)].qName))); @@ -7638,7 +7742,7 @@ yyreduce: case 453: /* Line 1269 of yacc.c. */ -#line 4400 "querytransformparser.ypp" +#line 4502 "querytransformparser.ypp" { parseInfo->staticContext->error(QtXmlPatterns::tr("%1 is not in the in-scope attribute " "declarations. Note that the schema import " @@ -7651,7 +7755,7 @@ yyreduce: case 455: /* Line 1269 of yacc.c. */ -#line 4412 "querytransformparser.ypp" +#line 4514 "querytransformparser.ypp" { (yyval.qName) = parseInfo->staticContext->namePool()->allocateQName(StandardNamespaces::empty, (yyvsp[(1) - (1)].sval)); } @@ -7659,7 +7763,7 @@ yyreduce: case 457: /* Line 1269 of yacc.c. */ -#line 4424 "querytransformparser.ypp" +#line 4526 "querytransformparser.ypp" { if(parseInfo->nodeTestSource == BuiltinTypes::element) (yyval.qName) = parseInfo->staticContext->namePool()->allocateQName(parseInfo->staticContext->namespaceBindings()->lookupNamespaceURI(StandardPrefixes::empty), (yyvsp[(1) - (1)].sval)); @@ -7670,7 +7774,7 @@ yyreduce: case 462: /* Line 1269 of yacc.c. */ -#line 4438 "querytransformparser.ypp" +#line 4540 "querytransformparser.ypp" { (yyval.qName) = parseInfo->staticContext->namePool()->allocateQName(parseInfo->staticContext->defaultFunctionNamespace(), (yyvsp[(1) - (1)].sval)); } @@ -7678,7 +7782,7 @@ yyreduce: case 463: /* Line 1269 of yacc.c. */ -#line 4442 "querytransformparser.ypp" +#line 4544 "querytransformparser.ypp" { (yyval.qName) = parseInfo->staticContext->namePool()->allocateQName(StandardNamespaces::InternalXSLT, (yyvsp[(2) - (2)].sval)); } @@ -7686,7 +7790,7 @@ yyreduce: case 466: /* Line 1269 of yacc.c. */ -#line 4450 "querytransformparser.ypp" +#line 4552 "querytransformparser.ypp" { parseInfo->staticContext->error(QtXmlPatterns::tr("The name of an extension expression must be in " "a namespace."), @@ -7694,9 +7798,25 @@ yyreduce: } break; + case 469: +/* Line 1269 of yacc.c. */ +#line 4562 "querytransformparser.ypp" + { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, (yyloc)); + } + break; + + case 470: +/* Line 1269 of yacc.c. */ +#line 4566 "querytransformparser.ypp" + { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, (yyloc)); + } + break; + case 471: /* Line 1269 of yacc.c. */ -#line 4463 "querytransformparser.ypp" +#line 4571 "querytransformparser.ypp" { const ReflectYYLTYPE ryy((yyloc), parseInfo); @@ -7712,7 +7832,7 @@ yyreduce: case 472: /* Line 1269 of yacc.c. */ -#line 4475 "querytransformparser.ypp" +#line 4583 "querytransformparser.ypp" { (yyval.qName) = parseInfo->staticContext->namePool()->fromClarkName((yyvsp[(1) - (1)].sval)); } @@ -7720,7 +7840,7 @@ yyreduce: /* Line 1269 of yacc.c. */ -#line 7643 "qquerytransformparser.cpp" +#line 7763 "qquerytransformparser.cpp" default: break; } YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); @@ -7938,7 +8058,7 @@ yyreturn: /* Line 1486 of yacc.c. */ -#line 4479 "querytransformparser.ypp" +#line 4587 "querytransformparser.ypp" QString Tokenizer::tokenToString(const Token &token) diff --git a/src/xmlpatterns/parser/qquerytransformparser_p.h b/src/xmlpatterns/parser/qquerytransformparser_p.h index b33ca55..bb01788 100644 --- a/src/xmlpatterns/parser/qquerytransformparser_p.h +++ b/src/xmlpatterns/parser/qquerytransformparser_p.h @@ -49,6 +49,57 @@ // // We mean it. +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + /* A Bison parser, made by GNU Bison 2.3a. */ /* Skeleton interface for Bison's Yacc-like parsers in C @@ -104,6 +155,25 @@ # undef SELF #endif +/* These tokens are defined to nothing on Windows because they're + * used in their documentation parser, for use in things like: + * + * int foo(IN char* name, OUT char* path); + * + * Hence this un-break fix. Note that this file was auto generated. */ +#ifdef IN +# undef IN +#endif +#ifdef INSTANCE +# undef INSTANCE +#endif +#ifdef STRICT +# undef STRICT +#endif +#ifdef SELF +# undef SELF +#endif + /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE diff --git a/src/xmlpatterns/parser/querytransformparser.ypp b/src/xmlpatterns/parser/querytransformparser.ypp index f67eb5d..74cee11 100644 --- a/src/xmlpatterns/parser/querytransformparser.ypp +++ b/src/xmlpatterns/parser/querytransformparser.ypp @@ -227,11 +227,18 @@ static inline QSourceLocation fromYYLTYPE(const YYLTYPE &sourceLocator, } /** + * @internal + * @relates QXmlQuery + */ +typedef QFlags<QXmlQuery::QueryLanguage> QueryLanguages; + +/** * @short Flags invalid expressions and declarations in the currently * parsed language. * - * Since this grammar is used for several languages: XQuery 1.0, XSL-T 2.0 and - * XPath 2.0 inside XSL-T, it is the union of all the constructs in these + * Since this grammar is used for several languages: XQuery 1.0, XSL-T 2.0, and + * XPath 2.0 inside XSL-T, and field and selector patterns in W3C XML Schema's + * identity constraints, it is the union of all the constructs in these * languages. However, when dealing with each language individually, we * regularly need to disallow some expressions, such as direct element * constructors when parsing XSL-T, or the typeswitch when parsing XPath. @@ -242,19 +249,46 @@ static inline QSourceLocation fromYYLTYPE(const YYLTYPE &sourceLocator, * instance the @c let clause, should not be flagged as an error, because it's * used for internal purposes. * - * Hence, this function is called from each expression and declaration which is - * unavailable in XPath. + * Hence, this function is called from each expression and declaration with @p + * allowedLanguages stating what languages it is allowed in. * * If @p isInternal is @c true, no error is raised. Otherwise, if the current - * language is not XQuery, an error is raised. + * language is not in @p allowedLanguages, an error is raised. */ -static void disallowedConstruct(const ParserContext *const parseInfo, - const YYLTYPE &sourceLocator, - const bool isInternal = false) +static void allowedIn(const QueryLanguages allowedLanguages, + const ParserContext *const parseInfo, + const YYLTYPE &sourceLocator, + const bool isInternal = false) { - if(!isInternal && parseInfo->languageAccent != QXmlQuery::XQuery10) + /* We treat XPath 2.0 as a subset of XSL-T 2.0, so if XPath 2.0 is allowed + * and XSL-T is the language, it's ok. */ + if(!isInternal && + (!allowedLanguages.testFlag(parseInfo->languageAccent) && !(allowedLanguages.testFlag(QXmlQuery::XPath20) && parseInfo->languageAccent == QXmlQuery::XSLT20))) { - parseInfo->staticContext->error(QtXmlPatterns::tr("A construct was encountered which only is allowed in XQuery."), + + QString langName; + + switch(parseInfo->languageAccent) + { + case QXmlQuery::XPath20: + langName = QLatin1String("XPath 2.0"); + break; + case QXmlQuery::XSLT20: + langName = QLatin1String("XSL-T 2.0"); + break; + case QXmlQuery::XQuery10: + langName = QLatin1String("XQuery 1.0"); + break; + case QXmlQuery::XmlSchema11IdentityConstraintSelector: + langName = QtXmlPatterns::tr("W3C XML Schema identity constraint selector"); + break; + case QXmlQuery::XmlSchema11IdentityConstraintField: + langName = QtXmlPatterns::tr("W3C XML Schema identity constraint field"); + break; + } + + parseInfo->staticContext->error(QtXmlPatterns::tr("A construct was encountered " + "which is disallowed in the current language(%1).").arg(langName), ReportContext::XPST0003, fromYYLTYPE(sourceLocator, parseInfo)); @@ -1560,7 +1594,7 @@ Prolog: /* Empty. */ /* First part. */ | Prolog DefaultNamespaceDecl { - disallowedConstruct(parseInfo, @$); + allowedIn(QXmlQuery::XQuery10, parseInfo, @$); if(parseInfo->hasSecondPrologPart) parseInfo->staticContext->error(QtXmlPatterns::tr("A default namespace declaration must occur before function, " "variable, and option declarations."), ReportContext::XPST0003, fromYYLTYPE(@$, parseInfo)); @@ -1579,7 +1613,7 @@ Prolog: /* Empty. */ } | Prolog Import { - disallowedConstruct(parseInfo, @$); + allowedIn(QXmlQuery::XQuery10, parseInfo, @$); if(parseInfo->hasSecondPrologPart) parseInfo->staticContext->error(QtXmlPatterns::tr("Module imports must occur before function, " "variable, and option declarations."), ReportContext::XPST0003, fromYYLTYPE(@$, parseInfo)); @@ -1597,7 +1631,7 @@ Prolog: /* Empty. */ } | Prolog OptionDecl { - disallowedConstruct(parseInfo, @$); + allowedIn(QXmlQuery::XQuery10, parseInfo, @$); parseInfo->hasSecondPrologPart = true; } @@ -1705,7 +1739,7 @@ OptionalPriority: /* Empty. */ const AtomicValue::Ptr val(Decimal::fromLexical($2)); if(val->hasError()) { - parseInfo->staticContext->error(QtXmlPatterns::tr("The value of attribute %1 must of type %2, which %3 isn't.") + parseInfo->staticContext->error(QtXmlPatterns::tr("The value of attribute %1 must be of type %2, which %3 isn't.") .arg(formatKeyword(QLatin1String("priority")), formatType(parseInfo->staticContext->namePool(), BuiltinTypes::xsDecimal), formatData($2)), @@ -1730,20 +1764,20 @@ TemplateName: NAME ElementName Setter: BoundarySpaceDecl /* [7] */ | DefaultCollationDecl { - disallowedConstruct(parseInfo, @$); + allowedIn(QXmlQuery::XQuery10, parseInfo, @$); } | BaseURIDecl | ConstructionDecl { - disallowedConstruct(parseInfo, @$); + allowedIn(QXmlQuery::XQuery10, parseInfo, @$); } | OrderingModeDecl { - disallowedConstruct(parseInfo, @$); + allowedIn(QXmlQuery::XQuery10, parseInfo, @$); } | EmptyOrderDecl { - disallowedConstruct(parseInfo, @$); + allowedIn(QXmlQuery::XQuery10, parseInfo, @$); } | CopyNamespacesDecl @@ -1755,7 +1789,7 @@ Separator: SEMI_COLON NamespaceDecl: DECLARE NAMESPACE NCNAME G_EQ URILiteral IsInternal Separator /* [10] */ { if(!$6) - disallowedConstruct(parseInfo, @$); + allowedIn(QXmlQuery::XQuery10, parseInfo, @$); if($3 == QLatin1String("xmlns")) { @@ -1867,7 +1901,7 @@ OptionDecl: DECLARE OPTION ElementName StringLiteral Separator OrderingModeDecl: DECLARE ORDERING OrderingMode Separator /* [14] */ { - disallowedConstruct(parseInfo, @$); + allowedIn(QXmlQuery::XQuery10, parseInfo, @$); if(parseInfo->hasDeclaration(ParserContext::OrderingModeDecl)) { parseInfo->staticContext->error(prologMessage("declare ordering"), @@ -1964,7 +1998,7 @@ DefaultCollationDecl: DECLARE DEFAULT COLLATION StringLiteral Separator BaseURIDecl: DECLARE BASEURI IsInternal URILiteral Separator /* [20] */ { - disallowedConstruct(parseInfo, @$, $3); + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XSLT20), parseInfo, @$, $3); if(parseInfo->hasDeclaration(ParserContext::BaseURIDecl)) { parseInfo->staticContext->error(prologMessage("declare base-uri"), @@ -2026,7 +2060,7 @@ FileLocation: URILiteral VarDecl: DECLARE VARIABLE IsInternal DOLLAR VarName TypeDeclaration VariableValue OptionalDefaultValue Separator /* [24] */ { - disallowedConstruct(parseInfo, @$, $3); + allowedIn(QXmlQuery::XQuery10, parseInfo, @$, $3); if(variableByName($5, parseInfo)) { parseInfo->staticContext->error(QtXmlPatterns::tr("A variable by name %1 has already " @@ -2126,7 +2160,7 @@ FunctionDecl: DECLARE FUNCTION IsInternal FunctionName LPAREN ParamList RPAREN TypeDeclaration FunctionBody Separator /* [26] */ { if(!$3) - disallowedConstruct(parseInfo, @$, $3); + allowedIn(QXmlQuery::XQuery10, parseInfo, @$, $3); /* If FunctionBody is null, it is 'external', otherwise the value is the body. */ const QXmlName::NamespaceCode ns($4.namespaceURI()); @@ -2696,7 +2730,7 @@ LetClause: LET IsInternal DOLLAR VarName TypeDeclaration ASSIGN ExprSingle } LetTail /* [36] */ { - disallowedConstruct(parseInfo, @$, $2); + allowedIn(QXmlQuery::XQuery10, parseInfo, @$, $2); Q_ASSERT(parseInfo->variables.top()->name == $4); $$ = create(new LetClause($<expr>8, $9, parseInfo->variables.top()), @$, parseInfo); @@ -2835,6 +2869,7 @@ SomeQuantificationExpr: SOME DOLLAR VarName TypeDeclaration IN ExprSingle {$<enums.slot>$ = parseInfo->staticContext->currentRangeSlot();} SomeQuantificationTail /* [X] */ { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, @$); $$ = create(new QuantifiedExpression($<enums.slot>8, QuantifiedExpression::Some, $<expr>6, $9), @$, parseInfo); parseInfo->finalizePushedVariable(); @@ -2863,6 +2898,7 @@ EveryQuantificationExpr: EVERY DOLLAR VarName TypeDeclaration IN ExprSingle {$<enums.slot>$ = parseInfo->staticContext->currentRangeSlot();} EveryQuantificationTail /* [X] */ { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, @$); $$ = create(new QuantifiedExpression($<enums.slot>8, QuantifiedExpression::Every, $<expr>6, $9), @$, parseInfo); parseInfo->finalizePushedVariable(); @@ -2916,7 +2952,7 @@ TypeswitchExpr: TYPESWITCH LPAREN Expr RPAREN } CaseClause /* [43] */ { - disallowedConstruct(parseInfo, @$); + allowedIn(QXmlQuery::XQuery10, parseInfo, @$); parseInfo->typeswitchSource.pop(); $$ = $6; } @@ -2976,18 +3012,21 @@ CaseDefault: DEFAULT RETURN ExprSingle IfExpr: IF LPAREN Expr RPAREN THEN ExprSingle ELSE ExprSingle /* [45] */ { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, @$); $$ = create(new IfThenClause($3, $6, $8), @$, parseInfo); } OrExpr: AndExpr /* [46] */ | OrExpr OR AndExpr { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, @$); $$ = create(new OrExpression($1, $3), @$, parseInfo); } AndExpr: ComparisonExpr /* [47] */ | AndExpr AND ComparisonExpr { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, @$); $$ = create(new AndExpression($1, $3), @$, parseInfo); } @@ -2999,12 +3038,14 @@ ComparisonExpr: RangeExpr RangeExpr: AdditiveExpr /* [49] */ | AdditiveExpr TO AdditiveExpr { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, @$); $$ = create(new RangeExpression($1, $3), @$, parseInfo); } AdditiveExpr: MultiplicativeExpr /* [50] */ | AdditiveExpr AdditiveOperator MultiplicativeExpr { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, @$); $$ = create(new ArithmeticExpression($1, $2, $3), @$, parseInfo); } @@ -3014,6 +3055,7 @@ AdditiveOperator: PLUS {$$ = AtomicMathematician::Add;} MultiplicativeExpr: UnionExpr /* [51] */ | MultiplicativeExpr MultiplyOperator UnionExpr { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, @$); $$ = create(new ArithmeticExpression($1, $2, $3), @$, parseInfo); } @@ -3025,12 +3067,18 @@ MultiplyOperator: STAR {$$ = AtomicMathematician::Multiply;} UnionExpr: IntersectExceptExpr /* [52] */ | UnionExpr UnionOperator IntersectExceptExpr { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 + | QXmlQuery::XPath20 + | QXmlQuery::XmlSchema11IdentityConstraintField + | QXmlQuery::XmlSchema11IdentityConstraintSelector), + parseInfo, @$); $$ = create(new CombineNodes($1, CombineNodes::Union, $3), @$, parseInfo); } IntersectExceptExpr: InstanceOfExpr /* [53] */ | IntersectExceptExpr IntersectOperator InstanceOfExpr { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, @$); $$ = create(new CombineNodes($1, $2, $3), @$, parseInfo); } @@ -3049,31 +3097,36 @@ IntersectOperator: INTERSECT InstanceOfExpr: TreatExpr /* [54] */ | TreatExpr INSTANCE OF SequenceType { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, @$); $$ = create(new InstanceOf($1, - SequenceType::Ptr($4)), @$, parseInfo); + SequenceType::Ptr($4)), @$, parseInfo); } TreatExpr: CastableExpr /* [55] */ | CastableExpr TREAT AS SequenceType { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, @$); $$ = create(new TreatAs($1, $4), @$, parseInfo); } CastableExpr: CastExpr /* [56] */ | CastExpr CASTABLE AS SingleType { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, @$); $$ = create(new CastableAs($1, $4), @$, parseInfo); } CastExpr: UnaryExpr /* [57] */ | UnaryExpr CAST AS SingleType { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, @$); $$ = create(new CastAs($1, $4), @$, parseInfo); } UnaryExpr: ValueExpr /* [58] */ | UnaryOperator UnaryExpr { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, @$); $$ = create(new UnaryExpression($1, $2, parseInfo->staticContext), @$, parseInfo); } @@ -3092,6 +3145,7 @@ ValueExpr: ValidateExpr GeneralComp: RangeExpr GeneralComparisonOperator RangeExpr /* [60] */ { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, @$); $$ = create(new GeneralComparison($1, $2, $3, parseInfo->isBackwardsCompat.top()), @$, parseInfo); } @@ -3125,7 +3179,7 @@ NodeOperator: IS {$$ = QXmlNodeModelIndex::Is;} ValidateExpr: ValidationMode EnclosedExpr /* [63] */ { - disallowedConstruct(parseInfo, @$); + allowedIn(QXmlQuery::XQuery10, parseInfo, @$); parseInfo->staticContext->error(QtXmlPatterns::tr("The Schema Validation Feature is not supported. " "Hence, %1-expressions may not be used.") .arg(formatKeyword("validate")), @@ -3143,6 +3197,7 @@ ValidationMode: VALIDATE {$$ = Validate::Strict;} ExtensionExpr: Pragmas EnclosedOptionalExpr /* [65] */ { + allowedIn(QXmlQuery::XQuery10, parseInfo, @$); /* We don't support any pragmas, so we only do the * necessary validation and use the fallback expression. */ @@ -3171,7 +3226,7 @@ Pragmas: Pragmas Pragma Pragma: PRAGMA_START PragmaName PragmaContents PRAGMA_END /* [66] */ { - disallowedConstruct(parseInfo, @$); + allowedIn(QXmlQuery::XQuery10, parseInfo, @$); } PragmaContents: /* empty */ /* [67] */ @@ -3241,12 +3296,14 @@ StepExpr: FilteredAxisStep } | BASEURI StringLiteral CURLY_LBRACE Expr CURLY_RBRACE /* [X] */ { + allowedIn(QXmlQuery::XSLT20, parseInfo, @$); Q_ASSERT(!$2.isEmpty()); $$ = create(new StaticBaseURIStore($2, $4), @$, parseInfo); } | DECLARE NAMESPACE NCNAME G_EQ STRING_LITERAL CURLY_LBRACE /* [X] */ { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XSLT20), parseInfo, @$); parseInfo->resolvers.push(parseInfo->staticContext->namespaceBindings()); const NamespaceResolver::Ptr resolver(new DelegatingNamespaceResolver(parseInfo->staticContext->namespaceBindings())); resolver->addBinding(QXmlName(parseInfo->staticContext->namePool()->allocateNamespace($5), @@ -3449,6 +3506,36 @@ Axis: AxisToken COLONCOLON } else $$ = $1; + + switch($1) + { + case QXmlNodeModelIndex::AxisAttribute: + { + allowedIn(QueryLanguages( QXmlQuery::XPath20 + | QXmlQuery::XQuery10 + | QXmlQuery::XmlSchema11IdentityConstraintField + | QXmlQuery::XSLT20), + parseInfo, @$); + break; + } + case QXmlNodeModelIndex::AxisChild: + { + allowedIn(QueryLanguages( QXmlQuery::XPath20 + | QXmlQuery::XQuery10 + | QXmlQuery::XmlSchema11IdentityConstraintField + | QXmlQuery::XmlSchema11IdentityConstraintSelector + | QXmlQuery::XSLT20), + parseInfo, @$); + break; + } + default: + { + allowedIn(QueryLanguages( QXmlQuery::XPath20 + | QXmlQuery::XQuery10 + | QXmlQuery::XSLT20), + parseInfo, @$); + } + } } AxisToken: ANCESTOR_OR_SELF {$$ = QXmlNodeModelIndex::AxisAncestorOrSelf ;} @@ -3470,6 +3557,7 @@ AbbrevForwardStep: AT_SIGN } NodeTest /* [72] */ { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XSLT20 | QXmlQuery::XmlSchema11IdentityConstraintField), parseInfo, @$); $$ = create(new AxisStep(QXmlNodeModelIndex::AxisAttribute, $3), @$, parseInfo); parseInfo->restoreNodeTestSource(); @@ -3499,6 +3587,9 @@ AbbrevReverseStep: DOTDOT NodeTest: NameTest /* [78] */ | KindTest + { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, @$); + } NameTest: ElementName /* [79] */ { @@ -3521,6 +3612,7 @@ WildCard: STAR } | ANY_PREFIX { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, @$); const QXmlName::LocalNameCode c = parseInfo->staticContext->namePool()->allocateLocalName($1); $$ = LocalNameTest::create(parseInfo->nodeTestSource, c); } @@ -3528,6 +3620,7 @@ WildCard: STAR FilterExpr: PrimaryExpr /* [81] */ | FilterExpr LBRACKET Expr RBRACKET { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, @$); $$ = create(GenericPredicate::create($1, $3, parseInfo->staticContext, fromYYLTYPE(@4, parseInfo)), @$, parseInfo); } @@ -3556,15 +3649,18 @@ Literal: NumericLiteral NumericLiteral: XPATH2_NUMBER /* [86] */ { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, @$); $$ = createNumericLiteral<Double>($1, @$, parseInfo); } | NUMBER { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, @$); $$ = createNumericLiteral<Numeric>($1, @$, parseInfo); } VarRef: DOLLAR VarName /* [87] */ { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, @$); $$ = resolveVariable($2, @$, parseInfo, false); } @@ -3580,10 +3676,12 @@ VarName: NCNAME ParenthesizedExpr: LPAREN Expr RPAREN /* [89] */ { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, @$); $$ = $2; } | LPAREN RPAREN { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, @$); $$ = create(new EmptySequence, @$, parseInfo); } @@ -3599,6 +3697,7 @@ OrderingExpr: OrderingMode EnclosedExpr FunctionCallExpr: FunctionName LPAREN FunctionArguments RPAREN /* [93] */ { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, @$); if(XPathHelper::isReservedNamespace($1.namespaceURI()) || $1.namespaceURI() == StandardNamespaces::InternalXSLT) { /* We got a call to a builtin function. */ const ReflectYYLTYPE ryy(@$, parseInfo); @@ -3641,9 +3740,12 @@ FunctionArguments: /* empty */ Constructor: DirectConstructor /* [94] */ { - disallowedConstruct(parseInfo, @$); + allowedIn(QXmlQuery::XQuery10, parseInfo, @$); } | ComputedConstructor +/* The reason we cannot call alloweIn() as the action for ComputedConstructor, + * is that we use the computed constructors for XSL-T, and therefore generate + * INTERNAL tokens. */ DirectConstructor: DirElemConstructor /* [95] */ | DirCommentConstructor @@ -4075,7 +4177,7 @@ ComputedConstructor: CompDocConstructor CompDocConstructor: DOCUMENT IsInternal EnclosedExpr /* [110] */ { - disallowedConstruct(parseInfo, @$, $2); + allowedIn(QXmlQuery::XQuery10, parseInfo, @$, $2); $$ = create(new DocumentConstructor($3), @$, parseInfo); } @@ -4088,7 +4190,7 @@ CompElemConstructor: ELEMENT IsInternal CompElementName EnclosedOptionalExpr /* [111] */ { Q_ASSERT(5); - disallowedConstruct(parseInfo, @$, $2); + allowedIn(QXmlQuery::XQuery10, parseInfo, @$, $2); Expression::Ptr effExpr; @@ -4133,7 +4235,7 @@ CompAttrConstructor: ATTRIBUTE CompAttributeName EnclosedOptionalExpr /* [113] */ { - disallowedConstruct(parseInfo, @$, $2); + allowedIn(QXmlQuery::XQuery10, parseInfo, @$, $2); const Expression::Ptr name(create(new AttributeNameValidator($3), @$, parseInfo)); @@ -4150,14 +4252,14 @@ CompTextConstructor: TEXT IsInternal EnclosedExpr CompCommentConstructor: COMMENT IsInternal EnclosedExpr /* [115] */ { - disallowedConstruct(parseInfo, @$, $2); + allowedIn(QXmlQuery::XQuery10, parseInfo, @$, $2); $$ = create(new CommentConstructor(createSimpleContent($3, @$, parseInfo)), @$, parseInfo); } CompPIConstructor: PROCESSING_INSTRUCTION CompPIName EnclosedOptionalExpr /* [116] */ { - disallowedConstruct(parseInfo, @$, $2); + allowedIn(QXmlQuery::XQuery10, parseInfo, @$, $2); if($3) { @@ -4517,7 +4619,13 @@ PragmaName: NCNAME URILiteral: StringLiteral /* [140] */ StringLiteral: STRING_LITERAL /* [144] */ + { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, @$); + } | XPATH2_STRING_LITERAL + { + allowedIn(QueryLanguages(QXmlQuery::XQuery10 | QXmlQuery::XPath20), parseInfo, @$); + } QName: QNAME /* [154] */ { diff --git a/src/xmlpatterns/schema/.gitignore b/src/xmlpatterns/schema/.gitignore new file mode 100644 index 0000000..2b29f27 --- /dev/null +++ b/src/xmlpatterns/schema/.gitignore @@ -0,0 +1 @@ +tests diff --git a/src/xmlpatterns/schema/builtinschemas.qrc b/src/xmlpatterns/schema/builtinschemas.qrc new file mode 100644 index 0000000..fb43d78 --- /dev/null +++ b/src/xmlpatterns/schema/builtinschemas.qrc @@ -0,0 +1,5 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file alias="http://www.w3.org/XML/1998/namespace">schemas/xml.xsd</file> +</qresource> +</RCC> diff --git a/src/xmlpatterns/schema/doc/All_diagram.dot b/src/xmlpatterns/schema/doc/All_diagram.dot new file mode 100644 index 0000000..3352b723 --- /dev/null +++ b/src/xmlpatterns/schema/doc/All_diagram.dot @@ -0,0 +1,13 @@ +digraph All { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 -> 3 [label="any"] + 1 -> 3 [label="element"] + 2 -> 3 [label="any"] + 2 -> 3 [label="element"] + 3 -> 3 [label="any"] + 3 -> 3 [label="element"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] + 3 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/Alternative_diagram.dot b/src/xmlpatterns/schema/doc/Alternative_diagram.dot new file mode 100644 index 0000000..2119c49 --- /dev/null +++ b/src/xmlpatterns/schema/doc/Alternative_diagram.dot @@ -0,0 +1,11 @@ +digraph Alternative { + mindist = 2.0 + 1 -> 3 [label="complexType"] + 1 -> 2 [label="annotation"] + 1 -> 3 [label="simpleType"] + 2 -> 3 [label="complexType"] + 2 -> 3 [label="simpleType"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] + 3 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/Annotation_diagram.dot b/src/xmlpatterns/schema/doc/Annotation_diagram.dot new file mode 100644 index 0000000..260b6f7 --- /dev/null +++ b/src/xmlpatterns/schema/doc/Annotation_diagram.dot @@ -0,0 +1,9 @@ +digraph Annotation { + mindist = 2.0 + 1 -> 2 [label="appinfo"] + 1 -> 2 [label="documentation"] + 2 -> 2 [label="appinfo"] + 2 -> 2 [label="documentation"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/AnyAttribute_diagram.dot b/src/xmlpatterns/schema/doc/AnyAttribute_diagram.dot new file mode 100644 index 0000000..d252ebd --- /dev/null +++ b/src/xmlpatterns/schema/doc/AnyAttribute_diagram.dot @@ -0,0 +1,6 @@ +digraph AnyAttribute { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/Any_diagram.dot b/src/xmlpatterns/schema/doc/Any_diagram.dot new file mode 100644 index 0000000..f54063f --- /dev/null +++ b/src/xmlpatterns/schema/doc/Any_diagram.dot @@ -0,0 +1,6 @@ +digraph Any { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/Assert_diagram.dot b/src/xmlpatterns/schema/doc/Assert_diagram.dot new file mode 100644 index 0000000..7093bef --- /dev/null +++ b/src/xmlpatterns/schema/doc/Assert_diagram.dot @@ -0,0 +1,6 @@ +digraph Assert { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/Choice_diagram.dot b/src/xmlpatterns/schema/doc/Choice_diagram.dot new file mode 100644 index 0000000..7b32016 --- /dev/null +++ b/src/xmlpatterns/schema/doc/Choice_diagram.dot @@ -0,0 +1,22 @@ +digraph Choice { + mindist = 2.0 + 1 -> 3 [label="choice"] + 1 -> 3 [label="group"] + 1 -> 2 [label="annotation"] + 1 -> 3 [label="sequence"] + 1 -> 3 [label="any"] + 1 -> 3 [label="element"] + 2 -> 3 [label="choice"] + 2 -> 3 [label="group"] + 2 -> 3 [label="sequence"] + 2 -> 3 [label="any"] + 2 -> 3 [label="element"] + 3 -> 3 [label="choice"] + 3 -> 3 [label="group"] + 3 -> 3 [label="sequence"] + 3 -> 3 [label="any"] + 3 -> 3 [label="element"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] + 3 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/ComplexContentExtension_diagram.dot b/src/xmlpatterns/schema/doc/ComplexContentExtension_diagram.dot new file mode 100644 index 0000000..6131612 --- /dev/null +++ b/src/xmlpatterns/schema/doc/ComplexContentExtension_diagram.dot @@ -0,0 +1,47 @@ +digraph ComplexContentExtension { + mindist = 2.0 + 1 -> 4 [label="choice"] + 1 -> 4 [label="group"] + 1 -> 4 [label="all"] + 1 -> 2 [label="annotation"] + 1 -> 4 [label="sequence"] + 1 -> 6 [label="anyAttribute"] + 1 -> 7 [label="assert"] + 1 -> 3 [label="openContent"] + 1 -> 5 [label="attribute"] + 1 -> 5 [label="attributeGroup"] + 2 -> 4 [label="choice"] + 2 -> 4 [label="group"] + 2 -> 4 [label="all"] + 2 -> 4 [label="sequence"] + 2 -> 6 [label="anyAttribute"] + 2 -> 7 [label="assert"] + 2 -> 3 [label="openContent"] + 2 -> 5 [label="attribute"] + 2 -> 5 [label="attributeGroup"] + 3 -> 4 [label="choice"] + 3 -> 4 [label="group"] + 3 -> 4 [label="all"] + 3 -> 4 [label="sequence"] + 3 -> 6 [label="anyAttribute"] + 3 -> 7 [label="assert"] + 3 -> 5 [label="attribute"] + 3 -> 5 [label="attributeGroup"] + 4 -> 6 [label="anyAttribute"] + 4 -> 7 [label="assert"] + 4 -> 5 [label="attribute"] + 4 -> 5 [label="attributeGroup"] + 5 -> 6 [label="anyAttribute"] + 5 -> 7 [label="assert"] + 5 -> 5 [label="attribute"] + 5 -> 5 [label="attributeGroup"] + 6 -> 7 [label="assert"] + 7 -> 7 [label="assert"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] + 3 [shape=doublecircle, style=filled, color=green] + 4 [shape=doublecircle, style=filled, color=green] + 5 [shape=doublecircle, style=filled, color=green] + 6 [shape=doublecircle, style=filled, color=green] + 7 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/ComplexContentRestriction_diagram.dot b/src/xmlpatterns/schema/doc/ComplexContentRestriction_diagram.dot new file mode 100644 index 0000000..bfda892 --- /dev/null +++ b/src/xmlpatterns/schema/doc/ComplexContentRestriction_diagram.dot @@ -0,0 +1,47 @@ +digraph ComplexContentRestriction { + mindist = 2.0 + 1 -> 4 [label="choice"] + 1 -> 4 [label="group"] + 1 -> 4 [label="all"] + 1 -> 2 [label="annotation"] + 1 -> 4 [label="sequence"] + 1 -> 6 [label="anyAttribute"] + 1 -> 7 [label="assert"] + 1 -> 3 [label="openContent"] + 1 -> 5 [label="attribute"] + 1 -> 5 [label="attributeGroup"] + 2 -> 4 [label="choice"] + 2 -> 4 [label="group"] + 2 -> 4 [label="all"] + 2 -> 4 [label="sequence"] + 2 -> 6 [label="anyAttribute"] + 2 -> 7 [label="assert"] + 2 -> 3 [label="openContent"] + 2 -> 5 [label="attribute"] + 2 -> 5 [label="attributeGroup"] + 3 -> 4 [label="choice"] + 3 -> 4 [label="group"] + 3 -> 4 [label="all"] + 3 -> 4 [label="sequence"] + 3 -> 6 [label="anyAttribute"] + 3 -> 7 [label="assert"] + 3 -> 5 [label="attribute"] + 3 -> 5 [label="attributeGroup"] + 4 -> 6 [label="anyAttribute"] + 4 -> 7 [label="assert"] + 4 -> 5 [label="attribute"] + 4 -> 5 [label="attributeGroup"] + 5 -> 6 [label="anyAttribute"] + 5 -> 7 [label="assert"] + 5 -> 5 [label="attribute"] + 5 -> 5 [label="attributeGroup"] + 6 -> 7 [label="assert"] + 7 -> 7 [label="assert"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] + 3 [shape=doublecircle, style=filled, color=green] + 4 [shape=doublecircle, style=filled, color=green] + 5 [shape=doublecircle, style=filled, color=green] + 6 [shape=doublecircle, style=filled, color=green] + 7 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/ComplexContent_diagram.dot b/src/xmlpatterns/schema/doc/ComplexContent_diagram.dot new file mode 100644 index 0000000..949c27e --- /dev/null +++ b/src/xmlpatterns/schema/doc/ComplexContent_diagram.dot @@ -0,0 +1,11 @@ +digraph ComplexContent { + mindist = 2.0 + 1 -> 3 [label="restriction"] + 1 -> 2 [label="annotation"] + 1 -> 3 [label="extension"] + 2 -> 3 [label="restriction"] + 2 -> 3 [label="extension"] + 1 [shape=circle, style=filled, color=blue] + 2 [shape=circle, style=filled, color=red] + 3 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/DefaultOpenContent_diagram.dot b/src/xmlpatterns/schema/doc/DefaultOpenContent_diagram.dot new file mode 100644 index 0000000..61e7d14 --- /dev/null +++ b/src/xmlpatterns/schema/doc/DefaultOpenContent_diagram.dot @@ -0,0 +1,9 @@ +digraph DefaultOpenContent { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 -> 3 [label="any"] + 2 -> 3 [label="any"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=circle, style=filled, color=red] + 3 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/EnumerationFacet_diagram.dot b/src/xmlpatterns/schema/doc/EnumerationFacet_diagram.dot new file mode 100644 index 0000000..91be76b --- /dev/null +++ b/src/xmlpatterns/schema/doc/EnumerationFacet_diagram.dot @@ -0,0 +1,6 @@ +digraph EnumerationFacet { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/Field_diagram.dot b/src/xmlpatterns/schema/doc/Field_diagram.dot new file mode 100644 index 0000000..1c597b3 --- /dev/null +++ b/src/xmlpatterns/schema/doc/Field_diagram.dot @@ -0,0 +1,6 @@ +digraph Field { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/FractionDigitsFacet_diagram.dot b/src/xmlpatterns/schema/doc/FractionDigitsFacet_diagram.dot new file mode 100644 index 0000000..5e098b3 --- /dev/null +++ b/src/xmlpatterns/schema/doc/FractionDigitsFacet_diagram.dot @@ -0,0 +1,6 @@ +digraph FractionDigitsFacet { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/GlobalAttribute_diagram.dot b/src/xmlpatterns/schema/doc/GlobalAttribute_diagram.dot new file mode 100644 index 0000000..25a1a43 --- /dev/null +++ b/src/xmlpatterns/schema/doc/GlobalAttribute_diagram.dot @@ -0,0 +1,9 @@ +digraph GlobalAttribute { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 -> 3 [label="simpleType"] + 2 -> 3 [label="simpleType"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] + 3 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/GlobalComplexType_diagram.dot b/src/xmlpatterns/schema/doc/GlobalComplexType_diagram.dot new file mode 100644 index 0000000..05e40b7 --- /dev/null +++ b/src/xmlpatterns/schema/doc/GlobalComplexType_diagram.dot @@ -0,0 +1,52 @@ +digraph GlobalComplexType { + mindist = 2.0 + 1 -> 5 [label="choice"] + 1 -> 3 [label="complexContent"] + 1 -> 5 [label="group"] + 1 -> 5 [label="all"] + 1 -> 2 [label="annotation"] + 1 -> 5 [label="sequence"] + 1 -> 3 [label="simpleContent"] + 1 -> 7 [label="anyAttribute"] + 1 -> 8 [label="assert"] + 1 -> 4 [label="openContent"] + 1 -> 6 [label="attribute"] + 1 -> 6 [label="attributeGroup"] + 2 -> 5 [label="choice"] + 2 -> 3 [label="complexContent"] + 2 -> 5 [label="group"] + 2 -> 5 [label="all"] + 2 -> 5 [label="sequence"] + 2 -> 3 [label="simpleContent"] + 2 -> 7 [label="anyAttribute"] + 2 -> 8 [label="assert"] + 2 -> 4 [label="openContent"] + 2 -> 6 [label="attribute"] + 2 -> 6 [label="attributeGroup"] + 4 -> 5 [label="choice"] + 4 -> 5 [label="group"] + 4 -> 5 [label="all"] + 4 -> 5 [label="sequence"] + 4 -> 7 [label="anyAttribute"] + 4 -> 8 [label="assert"] + 4 -> 6 [label="attribute"] + 4 -> 6 [label="attributeGroup"] + 5 -> 7 [label="anyAttribute"] + 5 -> 8 [label="assert"] + 5 -> 6 [label="attribute"] + 5 -> 6 [label="attributeGroup"] + 6 -> 7 [label="anyAttribute"] + 6 -> 8 [label="assert"] + 6 -> 6 [label="attribute"] + 6 -> 6 [label="attributeGroup"] + 7 -> 8 [label="assert"] + 8 -> 8 [label="assert"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] + 3 [shape=doublecircle, style=filled, color=green] + 4 [shape=doublecircle, style=filled, color=green] + 5 [shape=doublecircle, style=filled, color=green] + 6 [shape=doublecircle, style=filled, color=green] + 7 [shape=doublecircle, style=filled, color=green] + 8 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/GlobalElement_diagram.dot b/src/xmlpatterns/schema/doc/GlobalElement_diagram.dot new file mode 100644 index 0000000..20447a7 --- /dev/null +++ b/src/xmlpatterns/schema/doc/GlobalElement_diagram.dot @@ -0,0 +1,32 @@ +digraph GlobalElement { + mindist = 2.0 + 1 -> 3 [label="complexType"] + 1 -> 4 [label="alternative"] + 1 -> 2 [label="annotation"] + 1 -> 5 [label="key"] + 1 -> 3 [label="simpleType"] + 1 -> 5 [label="keyref"] + 1 -> 5 [label="unique"] + 2 -> 3 [label="complexType"] + 2 -> 4 [label="alternative"] + 2 -> 5 [label="key"] + 2 -> 3 [label="simpleType"] + 2 -> 5 [label="keyref"] + 2 -> 5 [label="unique"] + 3 -> 4 [label="alternative"] + 3 -> 5 [label="key"] + 3 -> 5 [label="keyref"] + 3 -> 5 [label="unique"] + 4 -> 4 [label="alternative"] + 4 -> 5 [label="key"] + 4 -> 5 [label="keyref"] + 4 -> 5 [label="unique"] + 5 -> 5 [label="key"] + 5 -> 5 [label="keyref"] + 5 -> 5 [label="unique"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] + 3 [shape=doublecircle, style=filled, color=green] + 4 [shape=doublecircle, style=filled, color=green] + 5 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/GlobalSimpleType_diagram.dot b/src/xmlpatterns/schema/doc/GlobalSimpleType_diagram.dot new file mode 100644 index 0000000..ccb7f54 --- /dev/null +++ b/src/xmlpatterns/schema/doc/GlobalSimpleType_diagram.dot @@ -0,0 +1,13 @@ +digraph GlobalSimpleType { + mindist = 2.0 + 1 -> 3 [label="restriction"] + 1 -> 2 [label="annotation"] + 1 -> 3 [label="list"] + 1 -> 3 [label="union"] + 2 -> 3 [label="restriction"] + 2 -> 3 [label="list"] + 2 -> 3 [label="union"] + 1 [shape=circle, style=filled, color=blue] + 2 [shape=circle, style=filled, color=red] + 3 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/Import_diagram.dot b/src/xmlpatterns/schema/doc/Import_diagram.dot new file mode 100644 index 0000000..3484bc3 --- /dev/null +++ b/src/xmlpatterns/schema/doc/Import_diagram.dot @@ -0,0 +1,6 @@ +digraph Import { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/Include_diagram.dot b/src/xmlpatterns/schema/doc/Include_diagram.dot new file mode 100644 index 0000000..357e4c9 --- /dev/null +++ b/src/xmlpatterns/schema/doc/Include_diagram.dot @@ -0,0 +1,6 @@ +digraph Include { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/KeyRef_diagram.dot b/src/xmlpatterns/schema/doc/KeyRef_diagram.dot new file mode 100644 index 0000000..ff425b9 --- /dev/null +++ b/src/xmlpatterns/schema/doc/KeyRef_diagram.dot @@ -0,0 +1,12 @@ +digraph KeyRef { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 -> 3 [label="selector"] + 2 -> 3 [label="selector"] + 3 -> 4 [label="field"] + 4 -> 4 [label="field"] + 1 [shape=circle, style=filled, color=blue] + 2 [shape=circle, style=filled, color=red] + 3 [shape=circle, style=filled, color=red] + 4 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/Key_diagram.dot b/src/xmlpatterns/schema/doc/Key_diagram.dot new file mode 100644 index 0000000..bbc09cd --- /dev/null +++ b/src/xmlpatterns/schema/doc/Key_diagram.dot @@ -0,0 +1,12 @@ +digraph Key { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 -> 3 [label="selector"] + 2 -> 3 [label="selector"] + 3 -> 4 [label="field"] + 4 -> 4 [label="field"] + 1 [shape=circle, style=filled, color=blue] + 2 [shape=circle, style=filled, color=red] + 3 [shape=circle, style=filled, color=red] + 4 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/LengthFacet_diagram.dot b/src/xmlpatterns/schema/doc/LengthFacet_diagram.dot new file mode 100644 index 0000000..1f9205b --- /dev/null +++ b/src/xmlpatterns/schema/doc/LengthFacet_diagram.dot @@ -0,0 +1,6 @@ +digraph LengthFacet { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/List_diagram.dot b/src/xmlpatterns/schema/doc/List_diagram.dot new file mode 100644 index 0000000..44cc698 --- /dev/null +++ b/src/xmlpatterns/schema/doc/List_diagram.dot @@ -0,0 +1,9 @@ +digraph List { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 -> 3 [label="simpleType"] + 2 -> 3 [label="simpleType"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] + 3 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/LocalAll_diagram.dot b/src/xmlpatterns/schema/doc/LocalAll_diagram.dot new file mode 100644 index 0000000..88f1b61 --- /dev/null +++ b/src/xmlpatterns/schema/doc/LocalAll_diagram.dot @@ -0,0 +1,13 @@ +digraph LocalAll { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 -> 3 [label="any"] + 1 -> 3 [label="element"] + 2 -> 3 [label="any"] + 2 -> 3 [label="element"] + 3 -> 3 [label="any"] + 3 -> 3 [label="element"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] + 3 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/LocalAttribute_diagram.dot b/src/xmlpatterns/schema/doc/LocalAttribute_diagram.dot new file mode 100644 index 0000000..b01f0cf --- /dev/null +++ b/src/xmlpatterns/schema/doc/LocalAttribute_diagram.dot @@ -0,0 +1,9 @@ +digraph LocalAttribute { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 -> 3 [label="simpleType"] + 2 -> 3 [label="simpleType"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] + 3 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/LocalChoice_diagram.dot b/src/xmlpatterns/schema/doc/LocalChoice_diagram.dot new file mode 100644 index 0000000..b16c47f --- /dev/null +++ b/src/xmlpatterns/schema/doc/LocalChoice_diagram.dot @@ -0,0 +1,22 @@ +digraph LocalChoice { + mindist = 2.0 + 1 -> 3 [label="choice"] + 1 -> 3 [label="group"] + 1 -> 2 [label="annotation"] + 1 -> 3 [label="sequence"] + 1 -> 3 [label="any"] + 1 -> 3 [label="element"] + 2 -> 3 [label="choice"] + 2 -> 3 [label="group"] + 2 -> 3 [label="sequence"] + 2 -> 3 [label="any"] + 2 -> 3 [label="element"] + 3 -> 3 [label="choice"] + 3 -> 3 [label="group"] + 3 -> 3 [label="sequence"] + 3 -> 3 [label="any"] + 3 -> 3 [label="element"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] + 3 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/LocalComplexType_diagram.dot b/src/xmlpatterns/schema/doc/LocalComplexType_diagram.dot new file mode 100644 index 0000000..92c54b7 --- /dev/null +++ b/src/xmlpatterns/schema/doc/LocalComplexType_diagram.dot @@ -0,0 +1,52 @@ +digraph LocalComplexType { + mindist = 2.0 + 1 -> 5 [label="choice"] + 1 -> 3 [label="complexContent"] + 1 -> 5 [label="group"] + 1 -> 5 [label="all"] + 1 -> 2 [label="annotation"] + 1 -> 5 [label="sequence"] + 1 -> 3 [label="simpleContent"] + 1 -> 7 [label="anyAttribute"] + 1 -> 8 [label="assert"] + 1 -> 4 [label="openContent"] + 1 -> 6 [label="attribute"] + 1 -> 6 [label="attributeGroup"] + 2 -> 5 [label="choice"] + 2 -> 3 [label="complexContent"] + 2 -> 5 [label="group"] + 2 -> 5 [label="all"] + 2 -> 5 [label="sequence"] + 2 -> 3 [label="simpleContent"] + 2 -> 7 [label="anyAttribute"] + 2 -> 8 [label="assert"] + 2 -> 4 [label="openContent"] + 2 -> 6 [label="attribute"] + 2 -> 6 [label="attributeGroup"] + 4 -> 5 [label="choice"] + 4 -> 5 [label="group"] + 4 -> 5 [label="all"] + 4 -> 5 [label="sequence"] + 4 -> 7 [label="anyAttribute"] + 4 -> 8 [label="assert"] + 4 -> 6 [label="attribute"] + 4 -> 6 [label="attributeGroup"] + 5 -> 7 [label="anyAttribute"] + 5 -> 8 [label="assert"] + 5 -> 6 [label="attribute"] + 5 -> 6 [label="attributeGroup"] + 6 -> 7 [label="anyAttribute"] + 6 -> 8 [label="assert"] + 6 -> 6 [label="attribute"] + 6 -> 6 [label="attributeGroup"] + 7 -> 8 [label="assert"] + 8 -> 8 [label="assert"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] + 3 [shape=doublecircle, style=filled, color=green] + 4 [shape=doublecircle, style=filled, color=green] + 5 [shape=doublecircle, style=filled, color=green] + 6 [shape=doublecircle, style=filled, color=green] + 7 [shape=doublecircle, style=filled, color=green] + 8 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/LocalElement_diagram.dot b/src/xmlpatterns/schema/doc/LocalElement_diagram.dot new file mode 100644 index 0000000..397397a --- /dev/null +++ b/src/xmlpatterns/schema/doc/LocalElement_diagram.dot @@ -0,0 +1,32 @@ +digraph LocalElement { + mindist = 2.0 + 1 -> 3 [label="complexType"] + 1 -> 4 [label="alternative"] + 1 -> 2 [label="annotation"] + 1 -> 5 [label="key"] + 1 -> 3 [label="simpleType"] + 1 -> 5 [label="keyref"] + 1 -> 5 [label="unique"] + 2 -> 3 [label="complexType"] + 2 -> 4 [label="alternative"] + 2 -> 5 [label="key"] + 2 -> 3 [label="simpleType"] + 2 -> 5 [label="keyref"] + 2 -> 5 [label="unique"] + 3 -> 4 [label="alternative"] + 3 -> 5 [label="key"] + 3 -> 5 [label="keyref"] + 3 -> 5 [label="unique"] + 4 -> 4 [label="alternative"] + 4 -> 5 [label="key"] + 4 -> 5 [label="keyref"] + 4 -> 5 [label="unique"] + 5 -> 5 [label="key"] + 5 -> 5 [label="keyref"] + 5 -> 5 [label="unique"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] + 3 [shape=doublecircle, style=filled, color=green] + 4 [shape=doublecircle, style=filled, color=green] + 5 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/LocalSequence_diagram.dot b/src/xmlpatterns/schema/doc/LocalSequence_diagram.dot new file mode 100644 index 0000000..0dc7f39 --- /dev/null +++ b/src/xmlpatterns/schema/doc/LocalSequence_diagram.dot @@ -0,0 +1,22 @@ +digraph LocalSequence { + mindist = 2.0 + 1 -> 3 [label="choice"] + 1 -> 3 [label="group"] + 1 -> 2 [label="annotation"] + 1 -> 3 [label="sequence"] + 1 -> 3 [label="any"] + 1 -> 3 [label="element"] + 2 -> 3 [label="choice"] + 2 -> 3 [label="group"] + 2 -> 3 [label="sequence"] + 2 -> 3 [label="any"] + 2 -> 3 [label="element"] + 3 -> 3 [label="choice"] + 3 -> 3 [label="group"] + 3 -> 3 [label="sequence"] + 3 -> 3 [label="any"] + 3 -> 3 [label="element"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] + 3 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/LocalSimpleType_diagram.dot b/src/xmlpatterns/schema/doc/LocalSimpleType_diagram.dot new file mode 100644 index 0000000..ac13305 --- /dev/null +++ b/src/xmlpatterns/schema/doc/LocalSimpleType_diagram.dot @@ -0,0 +1,13 @@ +digraph LocalSimpleType { + mindist = 2.0 + 1 -> 3 [label="restriction"] + 1 -> 2 [label="annotation"] + 1 -> 3 [label="list"] + 1 -> 3 [label="union"] + 2 -> 3 [label="restriction"] + 2 -> 3 [label="list"] + 2 -> 3 [label="union"] + 1 [shape=circle, style=filled, color=blue] + 2 [shape=circle, style=filled, color=red] + 3 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/MaxExclusiveFacet_diagram.dot b/src/xmlpatterns/schema/doc/MaxExclusiveFacet_diagram.dot new file mode 100644 index 0000000..28364f7 --- /dev/null +++ b/src/xmlpatterns/schema/doc/MaxExclusiveFacet_diagram.dot @@ -0,0 +1,6 @@ +digraph MaxExclusiveFacet { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/MaxInclusiveFacet_diagram.dot b/src/xmlpatterns/schema/doc/MaxInclusiveFacet_diagram.dot new file mode 100644 index 0000000..9e2c265 --- /dev/null +++ b/src/xmlpatterns/schema/doc/MaxInclusiveFacet_diagram.dot @@ -0,0 +1,6 @@ +digraph MaxInclusiveFacet { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/MaxLengthFacet_diagram.dot b/src/xmlpatterns/schema/doc/MaxLengthFacet_diagram.dot new file mode 100644 index 0000000..d565217 --- /dev/null +++ b/src/xmlpatterns/schema/doc/MaxLengthFacet_diagram.dot @@ -0,0 +1,6 @@ +digraph MaxLengthFacet { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/MinExclusiveFacet_diagram.dot b/src/xmlpatterns/schema/doc/MinExclusiveFacet_diagram.dot new file mode 100644 index 0000000..d3b3f1f --- /dev/null +++ b/src/xmlpatterns/schema/doc/MinExclusiveFacet_diagram.dot @@ -0,0 +1,6 @@ +digraph MinExclusiveFacet { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/MinInclusiveFacet_diagram.dot b/src/xmlpatterns/schema/doc/MinInclusiveFacet_diagram.dot new file mode 100644 index 0000000..e5ca65d --- /dev/null +++ b/src/xmlpatterns/schema/doc/MinInclusiveFacet_diagram.dot @@ -0,0 +1,6 @@ +digraph MinInclusiveFacet { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/MinLengthFacet_diagram.dot b/src/xmlpatterns/schema/doc/MinLengthFacet_diagram.dot new file mode 100644 index 0000000..1dcced4 --- /dev/null +++ b/src/xmlpatterns/schema/doc/MinLengthFacet_diagram.dot @@ -0,0 +1,6 @@ +digraph MinLengthFacet { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/NamedAttributeGroup_diagram.dot b/src/xmlpatterns/schema/doc/NamedAttributeGroup_diagram.dot new file mode 100644 index 0000000..1754f67 --- /dev/null +++ b/src/xmlpatterns/schema/doc/NamedAttributeGroup_diagram.dot @@ -0,0 +1,17 @@ +digraph NamedAttributeGroup { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 -> 4 [label="anyAttribute"] + 1 -> 3 [label="attribute"] + 1 -> 3 [label="attributeGroup"] + 2 -> 4 [label="anyAttribute"] + 2 -> 3 [label="attribute"] + 2 -> 3 [label="attributeGroup"] + 3 -> 4 [label="anyAttribute"] + 3 -> 3 [label="attribute"] + 3 -> 3 [label="attributeGroup"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] + 3 [shape=doublecircle, style=filled, color=green] + 4 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/NamedGroup_diagram.dot b/src/xmlpatterns/schema/doc/NamedGroup_diagram.dot new file mode 100644 index 0000000..6d9a289 --- /dev/null +++ b/src/xmlpatterns/schema/doc/NamedGroup_diagram.dot @@ -0,0 +1,13 @@ +digraph NamedGroup { + mindist = 2.0 + 1 -> 3 [label="choice"] + 1 -> 3 [label="all"] + 1 -> 2 [label="annotation"] + 1 -> 3 [label="sequence"] + 2 -> 3 [label="choice"] + 2 -> 3 [label="all"] + 2 -> 3 [label="sequence"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] + 3 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/Notation_diagram.dot b/src/xmlpatterns/schema/doc/Notation_diagram.dot new file mode 100644 index 0000000..951f26a --- /dev/null +++ b/src/xmlpatterns/schema/doc/Notation_diagram.dot @@ -0,0 +1,6 @@ +digraph Notation { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/Override_diagram.dot b/src/xmlpatterns/schema/doc/Override_diagram.dot new file mode 100644 index 0000000..448451a --- /dev/null +++ b/src/xmlpatterns/schema/doc/Override_diagram.dot @@ -0,0 +1,21 @@ +digraph Override { + mindist = 2.0 + 1 -> 2 [label="group"] + 1 -> 2 [label="complexType"] + 1 -> 2 [label="annotation"] + 1 -> 2 [label="simpleType"] + 1 -> 2 [label="element"] + 1 -> 2 [label="notation"] + 1 -> 2 [label="attribute"] + 1 -> 2 [label="attributeGroup"] + 2 -> 2 [label="group"] + 2 -> 2 [label="complexType"] + 2 -> 2 [label="annotation"] + 2 -> 2 [label="simpleType"] + 2 -> 2 [label="element"] + 2 -> 2 [label="notation"] + 2 -> 2 [label="attribute"] + 2 -> 2 [label="attributeGroup"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/PatternFacet_diagram.dot b/src/xmlpatterns/schema/doc/PatternFacet_diagram.dot new file mode 100644 index 0000000..794d74c --- /dev/null +++ b/src/xmlpatterns/schema/doc/PatternFacet_diagram.dot @@ -0,0 +1,6 @@ +digraph PatternFacet { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/Redefine_diagram.dot b/src/xmlpatterns/schema/doc/Redefine_diagram.dot new file mode 100644 index 0000000..ba4871d --- /dev/null +++ b/src/xmlpatterns/schema/doc/Redefine_diagram.dot @@ -0,0 +1,15 @@ +digraph Redefine { + mindist = 2.0 + 1 -> 2 [label="group"] + 1 -> 2 [label="complexType"] + 1 -> 2 [label="annotation"] + 1 -> 2 [label="simpleType"] + 1 -> 2 [label="attributeGroup"] + 2 -> 2 [label="group"] + 2 -> 2 [label="complexType"] + 2 -> 2 [label="annotation"] + 2 -> 2 [label="simpleType"] + 2 -> 2 [label="attributeGroup"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/ReferredAttributeGroup_diagram.dot b/src/xmlpatterns/schema/doc/ReferredAttributeGroup_diagram.dot new file mode 100644 index 0000000..fd08872 --- /dev/null +++ b/src/xmlpatterns/schema/doc/ReferredAttributeGroup_diagram.dot @@ -0,0 +1,6 @@ +digraph ReferredAttributeGroup { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/ReferredGroup_diagram.dot b/src/xmlpatterns/schema/doc/ReferredGroup_diagram.dot new file mode 100644 index 0000000..c32f69f --- /dev/null +++ b/src/xmlpatterns/schema/doc/ReferredGroup_diagram.dot @@ -0,0 +1,13 @@ +digraph ReferredGroup { + mindist = 2.0 + 1 -> 3 [label="choice"] + 1 -> 3 [label="all"] + 1 -> 2 [label="annotation"] + 1 -> 3 [label="sequence"] + 2 -> 3 [label="choice"] + 2 -> 3 [label="all"] + 2 -> 3 [label="sequence"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] + 3 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/Schema_diagram.dot b/src/xmlpatterns/schema/doc/Schema_diagram.dot new file mode 100644 index 0000000..7d39337 --- /dev/null +++ b/src/xmlpatterns/schema/doc/Schema_diagram.dot @@ -0,0 +1,66 @@ +digraph Schema { + mindist = 2.0 + 1 -> 5 [label="group"] + 1 -> 5 [label="complexType"] + 1 -> 2 [label="import"] + 1 -> 2 [label="include"] + 1 -> 2 [label="annotation"] + 1 -> 3 [label="defaultOpenContent"] + 1 -> 5 [label="simpleType"] + 1 -> 5 [label="element"] + 1 -> 5 [label="notation"] + 1 -> 2 [label="override"] + 1 -> 5 [label="attribute"] + 1 -> 5 [label="attributeGroup"] + 1 -> 2 [label="redefine"] + 2 -> 5 [label="group"] + 2 -> 5 [label="complexType"] + 2 -> 2 [label="import"] + 2 -> 2 [label="include"] + 2 -> 2 [label="annotation"] + 2 -> 3 [label="defaultOpenContent"] + 2 -> 5 [label="simpleType"] + 2 -> 5 [label="element"] + 2 -> 5 [label="notation"] + 2 -> 2 [label="override"] + 2 -> 5 [label="attribute"] + 2 -> 5 [label="attributeGroup"] + 2 -> 2 [label="redefine"] + 3 -> 5 [label="group"] + 3 -> 5 [label="complexType"] + 3 -> 4 [label="annotation"] + 3 -> 5 [label="simpleType"] + 3 -> 5 [label="element"] + 3 -> 5 [label="notation"] + 3 -> 5 [label="attribute"] + 3 -> 5 [label="attributeGroup"] + 4 -> 5 [label="group"] + 4 -> 5 [label="complexType"] + 4 -> 5 [label="simpleType"] + 4 -> 5 [label="element"] + 4 -> 5 [label="notation"] + 4 -> 5 [label="attribute"] + 4 -> 5 [label="attributeGroup"] + 5 -> 5 [label="group"] + 5 -> 5 [label="complexType"] + 5 -> 6 [label="annotation"] + 5 -> 5 [label="simpleType"] + 5 -> 5 [label="element"] + 5 -> 5 [label="notation"] + 5 -> 5 [label="attribute"] + 5 -> 5 [label="attributeGroup"] + 6 -> 5 [label="group"] + 6 -> 5 [label="complexType"] + 6 -> 6 [label="annotation"] + 6 -> 5 [label="simpleType"] + 6 -> 5 [label="element"] + 6 -> 5 [label="notation"] + 6 -> 5 [label="attribute"] + 6 -> 5 [label="attributeGroup"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] + 3 [shape=doublecircle, style=filled, color=green] + 4 [shape=doublecircle, style=filled, color=green] + 5 [shape=doublecircle, style=filled, color=green] + 6 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/Selector_diagram.dot b/src/xmlpatterns/schema/doc/Selector_diagram.dot new file mode 100644 index 0000000..f3e93dc --- /dev/null +++ b/src/xmlpatterns/schema/doc/Selector_diagram.dot @@ -0,0 +1,6 @@ +digraph Selector { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/Sequence_diagram.dot b/src/xmlpatterns/schema/doc/Sequence_diagram.dot new file mode 100644 index 0000000..9172744 --- /dev/null +++ b/src/xmlpatterns/schema/doc/Sequence_diagram.dot @@ -0,0 +1,22 @@ +digraph Sequence { + mindist = 2.0 + 1 -> 3 [label="choice"] + 1 -> 3 [label="group"] + 1 -> 2 [label="annotation"] + 1 -> 3 [label="sequence"] + 1 -> 3 [label="any"] + 1 -> 3 [label="element"] + 2 -> 3 [label="choice"] + 2 -> 3 [label="group"] + 2 -> 3 [label="sequence"] + 2 -> 3 [label="any"] + 2 -> 3 [label="element"] + 3 -> 3 [label="choice"] + 3 -> 3 [label="group"] + 3 -> 3 [label="sequence"] + 3 -> 3 [label="any"] + 3 -> 3 [label="element"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] + 3 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/SimpleContentExtension_diagram.dot b/src/xmlpatterns/schema/doc/SimpleContentExtension_diagram.dot new file mode 100644 index 0000000..3ceebfd --- /dev/null +++ b/src/xmlpatterns/schema/doc/SimpleContentExtension_diagram.dot @@ -0,0 +1,23 @@ +digraph SimpleContentExtension { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 -> 4 [label="anyAttribute"] + 1 -> 5 [label="assert"] + 1 -> 3 [label="attribute"] + 1 -> 3 [label="attributeGroup"] + 2 -> 4 [label="anyAttribute"] + 2 -> 5 [label="assert"] + 2 -> 3 [label="attribute"] + 2 -> 3 [label="attributeGroup"] + 3 -> 4 [label="anyAttribute"] + 3 -> 5 [label="assert"] + 3 -> 3 [label="attribute"] + 3 -> 3 [label="attributeGroup"] + 4 -> 5 [label="assert"] + 5 -> 5 [label="assert"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] + 3 [shape=doublecircle, style=filled, color=green] + 4 [shape=doublecircle, style=filled, color=green] + 5 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/SimpleContentRestriction_diagram.dot b/src/xmlpatterns/schema/doc/SimpleContentRestriction_diagram.dot new file mode 100644 index 0000000..75b0b71 --- /dev/null +++ b/src/xmlpatterns/schema/doc/SimpleContentRestriction_diagram.dot @@ -0,0 +1,87 @@ +digraph SimpleContentRestriction { + mindist = 2.0 + 1 -> 3 [label="simpleType"] + 1 -> 2 [label="annotation"] + 1 -> 4 [label="length"] + 1 -> 6 [label="anyAttribute"] + 1 -> 4 [label="maxExclusive"] + 1 -> 4 [label="totalDigits"] + 1 -> 4 [label="maxInclusive"] + 1 -> 4 [label="maxLength"] + 1 -> 7 [label="assert"] + 1 -> 4 [label="assertion"] + 1 -> 5 [label="attribute"] + 1 -> 4 [label="minExclusive"] + 1 -> 5 [label="attributeGroup"] + 1 -> 4 [label="minInclusive"] + 1 -> 4 [label="minLength"] + 1 -> 4 [label="whiteSpace"] + 1 -> 4 [label="pattern"] + 1 -> 4 [label="enumeration"] + 1 -> 4 [label="fractionDigits"] + 2 -> 3 [label="simpleType"] + 2 -> 4 [label="length"] + 2 -> 6 [label="anyAttribute"] + 2 -> 4 [label="maxExclusive"] + 2 -> 4 [label="totalDigits"] + 2 -> 4 [label="maxInclusive"] + 2 -> 4 [label="maxLength"] + 2 -> 7 [label="assert"] + 2 -> 4 [label="assertion"] + 2 -> 5 [label="attribute"] + 2 -> 4 [label="minExclusive"] + 2 -> 5 [label="attributeGroup"] + 2 -> 4 [label="minInclusive"] + 2 -> 4 [label="minLength"] + 2 -> 4 [label="whiteSpace"] + 2 -> 4 [label="pattern"] + 2 -> 4 [label="enumeration"] + 2 -> 4 [label="fractionDigits"] + 3 -> 4 [label="fractionDigits"] + 3 -> 4 [label="minLength"] + 3 -> 4 [label="whiteSpace"] + 3 -> 6 [label="anyAttribute"] + 3 -> 4 [label="length"] + 3 -> 7 [label="assert"] + 3 -> 4 [label="maxExclusive"] + 3 -> 4 [label="enumeration"] + 3 -> 4 [label="assertion"] + 3 -> 4 [label="maxInclusive"] + 3 -> 5 [label="attribute"] + 3 -> 4 [label="maxLength"] + 3 -> 4 [label="pattern"] + 3 -> 4 [label="totalDigits"] + 3 -> 5 [label="attributeGroup"] + 3 -> 4 [label="minExclusive"] + 3 -> 4 [label="minInclusive"] + 4 -> 4 [label="fractionDigits"] + 4 -> 4 [label="minLength"] + 4 -> 4 [label="whiteSpace"] + 4 -> 6 [label="anyAttribute"] + 4 -> 4 [label="length"] + 4 -> 7 [label="assert"] + 4 -> 4 [label="maxExclusive"] + 4 -> 4 [label="enumeration"] + 4 -> 4 [label="assertion"] + 4 -> 4 [label="maxInclusive"] + 4 -> 5 [label="attribute"] + 4 -> 4 [label="maxLength"] + 4 -> 4 [label="pattern"] + 4 -> 4 [label="totalDigits"] + 4 -> 5 [label="attributeGroup"] + 4 -> 4 [label="minExclusive"] + 4 -> 4 [label="minInclusive"] + 5 -> 6 [label="anyAttribute"] + 5 -> 7 [label="assert"] + 5 -> 5 [label="attribute"] + 5 -> 5 [label="attributeGroup"] + 6 -> 7 [label="assert"] + 7 -> 7 [label="assert"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] + 3 [shape=doublecircle, style=filled, color=green] + 4 [shape=doublecircle, style=filled, color=green] + 5 [shape=doublecircle, style=filled, color=green] + 6 [shape=doublecircle, style=filled, color=green] + 7 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/SimpleContent_diagram.dot b/src/xmlpatterns/schema/doc/SimpleContent_diagram.dot new file mode 100644 index 0000000..c996329 --- /dev/null +++ b/src/xmlpatterns/schema/doc/SimpleContent_diagram.dot @@ -0,0 +1,11 @@ +digraph SimpleContent { + mindist = 2.0 + 1 -> 3 [label="restriction"] + 1 -> 2 [label="annotation"] + 1 -> 3 [label="extension"] + 2 -> 3 [label="restriction"] + 2 -> 3 [label="extension"] + 1 [shape=circle, style=filled, color=blue] + 2 [shape=circle, style=filled, color=red] + 3 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/SimpleRestriction_diagram.dot b/src/xmlpatterns/schema/doc/SimpleRestriction_diagram.dot new file mode 100644 index 0000000..09cb041 --- /dev/null +++ b/src/xmlpatterns/schema/doc/SimpleRestriction_diagram.dot @@ -0,0 +1,62 @@ +digraph SimpleRestriction { + mindist = 2.0 + 1 -> 4 [label="fractionDigits"] + 1 -> 4 [label="minLength"] + 1 -> 4 [label="whiteSpace"] + 1 -> 2 [label="annotation"] + 1 -> 3 [label="simpleType"] + 1 -> 4 [label="length"] + 1 -> 4 [label="maxExclusive"] + 1 -> 4 [label="enumeration"] + 1 -> 4 [label="assertion"] + 1 -> 4 [label="maxInclusive"] + 1 -> 4 [label="maxLength"] + 1 -> 4 [label="pattern"] + 1 -> 4 [label="totalDigits"] + 1 -> 4 [label="minExclusive"] + 1 -> 4 [label="minInclusive"] + 2 -> 4 [label="fractionDigits"] + 2 -> 4 [label="minLength"] + 2 -> 4 [label="whiteSpace"] + 2 -> 3 [label="simpleType"] + 2 -> 4 [label="length"] + 2 -> 4 [label="maxExclusive"] + 2 -> 4 [label="enumeration"] + 2 -> 4 [label="assertion"] + 2 -> 4 [label="maxInclusive"] + 2 -> 4 [label="maxLength"] + 2 -> 4 [label="pattern"] + 2 -> 4 [label="totalDigits"] + 2 -> 4 [label="minExclusive"] + 2 -> 4 [label="minInclusive"] + 3 -> 4 [label="fractionDigits"] + 3 -> 4 [label="minLength"] + 3 -> 4 [label="whiteSpace"] + 3 -> 4 [label="length"] + 3 -> 4 [label="maxExclusive"] + 3 -> 4 [label="enumeration"] + 3 -> 4 [label="assertion"] + 3 -> 4 [label="maxInclusive"] + 3 -> 4 [label="maxLength"] + 3 -> 4 [label="pattern"] + 3 -> 4 [label="totalDigits"] + 3 -> 4 [label="minExclusive"] + 3 -> 4 [label="minInclusive"] + 4 -> 4 [label="fractionDigits"] + 4 -> 4 [label="minLength"] + 4 -> 4 [label="whiteSpace"] + 4 -> 4 [label="length"] + 4 -> 4 [label="maxExclusive"] + 4 -> 4 [label="enumeration"] + 4 -> 4 [label="assertion"] + 4 -> 4 [label="maxInclusive"] + 4 -> 4 [label="maxLength"] + 4 -> 4 [label="pattern"] + 4 -> 4 [label="totalDigits"] + 4 -> 4 [label="minExclusive"] + 4 -> 4 [label="minInclusive"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] + 3 [shape=doublecircle, style=filled, color=green] + 4 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/TotalDigitsFacet_diagram.dot b/src/xmlpatterns/schema/doc/TotalDigitsFacet_diagram.dot new file mode 100644 index 0000000..0ef4cd6 --- /dev/null +++ b/src/xmlpatterns/schema/doc/TotalDigitsFacet_diagram.dot @@ -0,0 +1,6 @@ +digraph TotalDigitsFacet { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/Union_diagram.dot b/src/xmlpatterns/schema/doc/Union_diagram.dot new file mode 100644 index 0000000..d6c1865 --- /dev/null +++ b/src/xmlpatterns/schema/doc/Union_diagram.dot @@ -0,0 +1,10 @@ +digraph Union { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 -> 3 [label="simpleType"] + 2 -> 3 [label="simpleType"] + 3 -> 3 [label="simpleType"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] + 3 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/Unique_diagram.dot b/src/xmlpatterns/schema/doc/Unique_diagram.dot new file mode 100644 index 0000000..5b1d098 --- /dev/null +++ b/src/xmlpatterns/schema/doc/Unique_diagram.dot @@ -0,0 +1,12 @@ +digraph Unique { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 -> 3 [label="selector"] + 2 -> 3 [label="selector"] + 3 -> 4 [label="field"] + 4 -> 4 [label="field"] + 1 [shape=circle, style=filled, color=blue] + 2 [shape=circle, style=filled, color=red] + 3 [shape=circle, style=filled, color=red] + 4 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/WhiteSpaceFacet_diagram.dot b/src/xmlpatterns/schema/doc/WhiteSpaceFacet_diagram.dot new file mode 100644 index 0000000..596403c --- /dev/null +++ b/src/xmlpatterns/schema/doc/WhiteSpaceFacet_diagram.dot @@ -0,0 +1,6 @@ +digraph WhiteSpaceFacet { + mindist = 2.0 + 1 -> 2 [label="annotation"] + 1 [shape=doublecircle, style=filled, color=blue] + 2 [shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/doc/legend.dot b/src/xmlpatterns/schema/doc/legend.dot new file mode 100644 index 0000000..4f5792e --- /dev/null +++ b/src/xmlpatterns/schema/doc/legend.dot @@ -0,0 +1,7 @@ +digraph { + size="5,4" + 1 [label=" start state ", shape=circle, style=filled, color=blue] + 2 [label="start/end state", shape=doublecircle, style=filled, color=blue] + 3 [label=" internal state", shape=circle, style=filled, color=red] + 4 [label=" end state ", shape=doublecircle, style=filled, color=green] +} diff --git a/src/xmlpatterns/schema/qnamespacesupport.cpp b/src/xmlpatterns/schema/qnamespacesupport.cpp new file mode 100644 index 0000000..0ae5309 --- /dev/null +++ b/src/xmlpatterns/schema/qnamespacesupport.cpp @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#include "qnamespacesupport_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +NamespaceSupport::NamespaceSupport() +{ +} + +NamespaceSupport::NamespaceSupport(const NamePool::Ptr &namePool) + : m_namePool(namePool) +{ + // the XML namespace + m_ns.insert(StandardPrefixes::xml, StandardNamespaces::xml); +} + +void NamespaceSupport::setPrefix(const QXmlName::PrefixCode prefixCode, const QXmlName::NamespaceCode namespaceCode) +{ + m_ns.insert(prefixCode, namespaceCode); +} + +void NamespaceSupport::setPrefixes(const QXmlStreamNamespaceDeclarations &declarations) +{ + for (int i = 0; i < declarations.count(); i++) { + const QXmlStreamNamespaceDeclaration declaration = declarations.at(i); + + const QXmlName::PrefixCode prefixCode = m_namePool->allocatePrefix(declaration.prefix().toString()); + const QXmlName::NamespaceCode namespaceCode = m_namePool->allocateNamespace(declaration.namespaceUri().toString()); + m_ns.insert(prefixCode, namespaceCode); + } +} + +void NamespaceSupport::setTargetNamespace(const QXmlName::NamespaceCode namespaceCode) +{ + m_ns.insert(0, namespaceCode); +} + +QXmlName::PrefixCode NamespaceSupport::prefix(const QXmlName::NamespaceCode namespaceCode) const +{ + NamespaceHash::const_iterator itc, it = m_ns.constBegin(); + while ((itc=it) != m_ns.constEnd()) { + ++it; + if (*itc == namespaceCode) + return itc.key(); + } + return 0; +} + +QXmlName::NamespaceCode NamespaceSupport::uri(const QXmlName::PrefixCode prefixCode) const +{ + return m_ns.value(prefixCode); +} + +bool NamespaceSupport::processName(const QString& qname, NameType type, QXmlName &name) const +{ + int len = qname.size(); + const QChar *data = qname.constData(); + for (int pos = 0; pos < len; ++pos) { + if (data[pos] == QLatin1Char(':')) { + const QXmlName::PrefixCode prefixCode = m_namePool->allocatePrefix(qname.left(pos)); + if (!m_ns.contains(prefixCode)) + return false; + const QXmlName::NamespaceCode namespaceCode = uri(prefixCode); + const QXmlName::LocalNameCode localNameCode = m_namePool->allocateLocalName(qname.mid(pos + 1)); + name = QXmlName(namespaceCode, localNameCode, prefixCode); + return true; + } + } + + // there was no ':' + QXmlName::NamespaceCode namespaceCode = 0; + // attributes don't take default namespace + if (type == ElementName && !m_ns.isEmpty()) { + namespaceCode = m_ns.value(0); // get default namespace + } + + const QXmlName::LocalNameCode localNameCode = m_namePool->allocateLocalName(qname); + name = QXmlName(namespaceCode, localNameCode, 0); + + return true; +} + +void NamespaceSupport::pushContext() +{ + m_nsStack.push(m_ns); +} + +void NamespaceSupport::popContext() +{ + m_ns.clear(); + if(!m_nsStack.isEmpty()) + m_ns = m_nsStack.pop(); +} + +QList<QXmlName> NamespaceSupport::namespaceBindings() const +{ + QList<QXmlName> bindings; + + QHashIterator<QXmlName::PrefixCode, QXmlName::NamespaceCode> it(m_ns); + while (it.hasNext()) { + it.next(); + bindings.append(QXmlName(it.value(), StandardLocalNames::empty, it.key())); + } + + return bindings; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qnamespacesupport_p.h b/src/xmlpatterns/schema/qnamespacesupport_p.h new file mode 100644 index 0000000..47c21a5 --- /dev/null +++ b/src/xmlpatterns/schema/qnamespacesupport_p.h @@ -0,0 +1,173 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_NamespaceSupport_H +#define Patternist_NamespaceSupport_H + +#include "qnamepool_p.h" + +#include <QtCore/QExplicitlySharedDataPointer> +#include <QtCore/QHash> +#include <QtCore/QSet> +#include <QtCore/QStack> +#include <QtCore/QXmlStreamNamespaceDeclarations> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short A helper class for handling nested namespace declarations. + * + * This class is mostly an adaption of QXmlNamespaceSupport to the NamePool + * mechanism used in XmlPatterns. + * + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class NamespaceSupport + { + public: + /** + * Describes whether the name to process is an attribute or element. + */ + enum NameType + { + AttributeName, ///< An attribute name to process. + ElementName ///< An element name to process. + }; + + /** + * Creates an empty namespace support object. + */ + NamespaceSupport(); + + /** + * Creates a new namespace support object. + * + * @param namePool The name pool where all processed names are stored in. + */ + NamespaceSupport(const NamePool::Ptr &namePool); + + /** + * Adds a new prefix-to-namespace binding. + * + * @param prefixCode The name pool code for the prefix. + * @param namespaceCode The name pool code for the namespace. + */ + void setPrefix(const QXmlName::PrefixCode prefixCode, const QXmlName::NamespaceCode namespaceCode); + + /** + * Adds the prefix-to-namespace bindings from @p declarations to + * the namespace support. + */ + void setPrefixes(const QXmlStreamNamespaceDeclarations &declarations); + + /** + * Sets the name pool code of the target namespace of the schema the + * namespace support works on. + */ + void setTargetNamespace(const QXmlName::NamespaceCode code); + + /** + * Returns the prefix code for the given namespace @p code. + */ + QXmlName::PrefixCode prefix(const QXmlName::NamespaceCode code) const; + + /** + * Returns the namespace code for the given prefix @p code. + */ + QXmlName::NamespaceCode uri(const QXmlName::PrefixCode code) const; + + /** + * Converts the given @p qualifiedName to a resolved QXmlName @p name according + * to the current namespace mapping. + * + * @param qualifiedName The full qualified name. + * @param type The type of name processing. + * @param name The resolved QXmlName. + * + * @returns @c true if the name could be processed correctly or @c false if the + * namespace prefix is unknown. + */ + bool processName(const QString &qualifiedName, NameType type, QXmlName &name) const; + + /** + * Pushes the current namespace mapping onto the stack. + */ + void pushContext(); + + /** + * Pops the current namespace mapping from the stack. + */ + void popContext(); + + /** + * Returns the list of namespace bindings. + */ + QList<QXmlName> namespaceBindings() const; + + private: + typedef QHash<QXmlName::PrefixCode, QXmlName::NamespaceCode> NamespaceHash; + + NamePool::Ptr m_namePool; + QStack<NamespaceHash> m_nsStack; + NamespaceHash m_ns; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdalternative.cpp b/src/xmlpatterns/schema/qxsdalternative.cpp new file mode 100644 index 0000000..ceaa34b --- /dev/null +++ b/src/xmlpatterns/schema/qxsdalternative.cpp @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdalternative_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +void XsdAlternative::setTest(const XsdXPathExpression::Ptr &test) +{ + m_test = test; +} + +XsdXPathExpression::Ptr XsdAlternative::test() const +{ + return m_test; +} + +void XsdAlternative::setType(const SchemaType::Ptr &type) +{ + m_type = type; +} + +SchemaType::Ptr XsdAlternative::type() const +{ + return m_type; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdalternative_p.h b/src/xmlpatterns/schema/qxsdalternative_p.h new file mode 100644 index 0000000..8dcfb12 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdalternative_p.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdAlternative_H +#define Patternist_XsdAlternative_H + +#include "qnamedschemacomponent_p.h" +#include "qschematype_p.h" +#include "qxsdannotated_p.h" +#include "qxsdxpathexpression_p.h" + +#include <QtCore/QList> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short Represents a XSD alternative object. + * + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdAlternative : public NamedSchemaComponent, public XsdAnnotated + { + public: + typedef QExplicitlySharedDataPointer<XsdAlternative> Ptr; + typedef QList<XsdAlternative::Ptr> List; + + /** + * Sets the xpath @p test of the alternative. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#tac-test">Test Definition</a> + */ + void setTest(const XsdXPathExpression::Ptr &test); + + /** + * Returns the xpath test of the alternative. + */ + XsdXPathExpression::Ptr test() const; + + /** + * Sets the @p type of the alternative. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#tac-type_definition">Type Definition</a> + */ + void setType(const SchemaType::Ptr &type); + + /** + * Returns the type of the alternative. + */ + SchemaType::Ptr type() const; + + private: + XsdXPathExpression::Ptr m_test; + SchemaType::Ptr m_type; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdannotated.cpp b/src/xmlpatterns/schema/qxsdannotated.cpp new file mode 100644 index 0000000..d9d89f6 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdannotated.cpp @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdannotated_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +void XsdAnnotated::addAnnotation(const XsdAnnotation::Ptr &annotation) +{ + m_annotations.append(annotation); +} + +void XsdAnnotated::addAnnotations(const XsdAnnotation::List &annotations) +{ + m_annotations << annotations; +} + +XsdAnnotation::List XsdAnnotated::annotations() const +{ + return m_annotations; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdannotated_p.h b/src/xmlpatterns/schema/qxsdannotated_p.h new file mode 100644 index 0000000..05010d9 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdannotated_p.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdAnnotated_H +#define Patternist_XsdAnnotated_H + +#include "qxsdannotation_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short Base class for all XSD components with annotation content. + * + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdAnnotated + { + public: + /** + * Adds a new @p annotation to the component. + */ + void addAnnotation(const XsdAnnotation::Ptr &annotation); + + /** + * Adds a list of new @p annotations to the component. + */ + void addAnnotations(const XsdAnnotation::List &annotations); + + /** + * Returns the list of all annotations of the component. + */ + XsdAnnotation::List annotations() const; + + private: + XsdAnnotation::List m_annotations; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdannotation.cpp b/src/xmlpatterns/schema/qxsdannotation.cpp new file mode 100644 index 0000000..d53e3b6 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdannotation.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdannotation_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +void XsdAnnotation::setId(const DerivedString<TypeID>::Ptr &id) +{ + m_id = id; +} + +DerivedString<TypeID>::Ptr XsdAnnotation::id() const +{ + return m_id; +} + +void XsdAnnotation::addApplicationInformation(const XsdApplicationInformation::Ptr &information) +{ + m_applicationInformation.append(information); +} + +XsdApplicationInformation::List XsdAnnotation::applicationInformation() const +{ + return m_applicationInformation; +} + +void XsdAnnotation::addDocumentation(const XsdDocumentation::Ptr &documentation) +{ + m_documentations.append(documentation); +} + +XsdDocumentation::List XsdAnnotation::documentation() const +{ + return m_documentations; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdannotation_p.h b/src/xmlpatterns/schema/qxsdannotation_p.h new file mode 100644 index 0000000..27fb555 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdannotation_p.h @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdAnnotation_H +#define Patternist_XsdAnnotation_H + +#include "qderivedstring_p.h" +#include "qxsdapplicationinformation_p.h" +#include "qxsddocumentation_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short Represents a XSD annotation object. + * + * This class represents the <em>annotation</em> object of a XML schema as described + * <a href="http://www.w3.org/TR/xmlschema11-1/#cAnnotations">here</a>. + * + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdAnnotation : public NamedSchemaComponent + { + public: + typedef QExplicitlySharedDataPointer<XsdAnnotation> Ptr; + typedef QList<XsdAnnotation::Ptr> List; + + /** + * Sets the @p id of the annotation. + */ + void setId(const DerivedString<TypeID>::Ptr &id); + + /** + * Returns the @p id of the annotation. + */ + DerivedString<TypeID>::Ptr id() const; + + /** + * Adds an application @p information to the annotation. + * + * The application information is meant to be interpreted by + * a software system, e.g. other parts of the XML processor pipeline. + */ + void addApplicationInformation(const XsdApplicationInformation::Ptr &information); + + /** + * Returns the list of all application information of the annotation. + */ + XsdApplicationInformation::List applicationInformation() const; + + /** + * Adds a @p documentation to the annotation. + * + * The documentation is meant to be read by human being, e.g. additional + * constraints or information about schema components. + */ + void addDocumentation(const XsdDocumentation::Ptr &documentation); + + /** + * Returns the list of all documentations of the annotation. + */ + XsdDocumentation::List documentation() const; + + private: + DerivedString<TypeID>::Ptr m_id; + XsdApplicationInformation::List m_applicationInformation; + XsdDocumentation::List m_documentations; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdapplicationinformation.cpp b/src/xmlpatterns/schema/qxsdapplicationinformation.cpp new file mode 100644 index 0000000..46d6d56 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdapplicationinformation.cpp @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdapplicationinformation_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +void XsdApplicationInformation::setSource(const AnyURI::Ptr &source) +{ + m_source = source; +} + +AnyURI::Ptr XsdApplicationInformation::source() const +{ + return m_source; +} + +void XsdApplicationInformation::setContent(const QString &content) +{ + m_content = content; +} + +QString XsdApplicationInformation::content() const +{ + return m_content; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdapplicationinformation_p.h b/src/xmlpatterns/schema/qxsdapplicationinformation_p.h new file mode 100644 index 0000000..2eec83a --- /dev/null +++ b/src/xmlpatterns/schema/qxsdapplicationinformation_p.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdApplicationInformation_H +#define Patternist_XsdApplicationInformation_H + +#include "qanytype_p.h" +#include "qanyuri_p.h" +#include "qnamedschemacomponent_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short Represents a XSD appinfo object. + * + * This class represents the <em>appinfo</em> component of an <em>annotation</em> object + * of a XML schema as described <a href="http://www.w3.org/TR/xmlschema11-1/#cAnnotations">here</a>. + * + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdApplicationInformation : public NamedSchemaComponent + { + public: + typedef QExplicitlySharedDataPointer<XsdApplicationInformation> Ptr; + typedef QList<XsdApplicationInformation::Ptr> List; + + /** + * Sets the @p source of the application information. + * + * The source points to an URL that contains more + * information. + */ + void setSource(const AnyURI::Ptr &source); + + /** + * Returns the source of the application information. + */ + AnyURI::Ptr source() const; + + /** + * Sets the @p content of the application information. + * + * The content can be of abritrary type. + */ + void setContent(const QString &content); + + /** + * Returns the content of the application information. + */ + QString content() const; + + private: + AnyURI::Ptr m_source; + QString m_content; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdassertion.cpp b/src/xmlpatterns/schema/qxsdassertion.cpp new file mode 100644 index 0000000..8898bd2 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdassertion.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdassertion_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +void XsdAssertion::setTest(const XsdXPathExpression::Ptr &test) +{ + m_test = test; +} + +XsdXPathExpression::Ptr XsdAssertion::test() const +{ + return m_test; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdassertion_p.h b/src/xmlpatterns/schema/qxsdassertion_p.h new file mode 100644 index 0000000..56674e5 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdassertion_p.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdAssertion_H +#define Patternist_XsdAssertion_H + +#include "qnamedschemacomponent_p.h" +#include "qxsdannotated_p.h" +#include "qxsdxpathexpression_p.h" + +#include <QtCore/QList> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short Represents a XSD assertion object. + * + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#cAssertions">Assertion Definition</a> + */ + class XsdAssertion : public NamedSchemaComponent, public XsdAnnotated + { + public: + typedef QExplicitlySharedDataPointer<XsdAssertion> Ptr; + typedef QList<XsdAssertion::Ptr> List; + + /** + * Sets the @p test of the assertion. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#as-test">Test Definition</a> + */ + void setTest(const XsdXPathExpression::Ptr &test); + + /** + * Returns the test of the assertion. + */ + XsdXPathExpression::Ptr test() const; + + private: + XsdXPathExpression::Ptr m_test; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdattribute.cpp b/src/xmlpatterns/schema/qxsdattribute.cpp new file mode 100644 index 0000000..7fd883e --- /dev/null +++ b/src/xmlpatterns/schema/qxsdattribute.cpp @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdattribute_p.h" +#include "qxsdcomplextype_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + + +void XsdAttribute::Scope::setVariety(Variety variety) +{ + m_variety = variety; +} + +XsdAttribute::Scope::Variety XsdAttribute::Scope::variety() const +{ + return m_variety; +} + +void XsdAttribute::Scope::setParent(const NamedSchemaComponent::Ptr &parent) +{ + m_parent = parent; +} + +NamedSchemaComponent::Ptr XsdAttribute::Scope::parent() const +{ + return m_parent; +} + +void XsdAttribute::ValueConstraint::setVariety(Variety variety) +{ + m_variety = variety; +} + +XsdAttribute::ValueConstraint::Variety XsdAttribute::ValueConstraint::variety() const +{ + return m_variety; +} + +void XsdAttribute::ValueConstraint::setValue(const QString &value) +{ + m_value = value; +} + +QString XsdAttribute::ValueConstraint::value() const +{ + return m_value; +} + +void XsdAttribute::ValueConstraint::setLexicalForm(const QString &form) +{ + m_lexicalForm = form; +} + +QString XsdAttribute::ValueConstraint::lexicalForm() const +{ + return m_lexicalForm; +} + +void XsdAttribute::setType(const AnySimpleType::Ptr &type) +{ + m_type = type; +} + +AnySimpleType::Ptr XsdAttribute::type() const +{ + return m_type; +} + +void XsdAttribute::setScope(const Scope::Ptr &scope) +{ + m_scope = scope; +} + +XsdAttribute::Scope::Ptr XsdAttribute::scope() const +{ + return m_scope; +} + +void XsdAttribute::setValueConstraint(const ValueConstraint::Ptr &constraint) +{ + m_valueConstraint = constraint; +} + +XsdAttribute::ValueConstraint::Ptr XsdAttribute::valueConstraint() const +{ + return m_valueConstraint; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdattribute_p.h b/src/xmlpatterns/schema/qxsdattribute_p.h new file mode 100644 index 0000000..220dd28 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdattribute_p.h @@ -0,0 +1,246 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdAttribute_H +#define Patternist_XsdAttribute_H + +#include "qanysimpletype_p.h" +#include "qnamedschemacomponent_p.h" +#include "qxsdannotated_p.h" + +#include <QtCore/QList> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short Represents a XSD attribute object. + * + * This class represents the <em>attribute</em> object of a XML schema as described + * <a href="http://www.w3.org/TR/xmlschema11-1/#cAttribute_Declarations">here</a>. + * + * It contains information from either a top-level attribute declaration (as child of + * a <em>schema</em> object) or of a local attribute declaration (as child of <em>complexType</em> + * or <em>attributeGroup</em> object without a 'ref' attribute). + * + * All other occurrences of the <em>attribute</em> object are represented by the XsdAttributeUse class. + * + * @see <a href="http://www.w3.org/Submission/2004/SUBM-xmlschema-api-20040309/xml-schema-api.html#Interface-XSAttributeDeclaration">XML Schema API reference</a> + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdAttribute : public NamedSchemaComponent, public XsdAnnotated + { + public: + typedef QExplicitlySharedDataPointer<XsdAttribute> Ptr; + typedef QList<XsdAttribute::Ptr> List; + + /** + * @short Describes the scope of an attribute. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#sc_a">Scope Definition</a> + */ + class Scope : public QSharedData + { + public: + typedef QExplicitlySharedDataPointer<Scope> Ptr; + + /** + * Describes the <a href="http://www.w3.org/TR/xmlschema11-1/#ad-scope">scope</a> of an attribute. + */ + enum Variety + { + Global, ///< The attribute is defined globally as child of the <em>schema</em> object. + Local ///< The attribute is defined locally as child of a complex type or attribute group definition. + }; + + /** + * Sets the @p variety of the attribute scope. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#sc_a-variety">Variety Definition</a> + */ + void setVariety(Variety variety); + + /** + * Returns the variety of the attribute scope. + */ + Variety variety() const; + + /** + * Sets the @p parent complex type or attribute group definition of the attribute scope. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#sc_a-parent">Parent Definition</a> + */ + void setParent(const NamedSchemaComponent::Ptr &parent); + + /** + * Returns the parent complex type or attribute group definition of the attribute scope. + */ + NamedSchemaComponent::Ptr parent() const; + + private: + Variety m_variety; + NamedSchemaComponent::Ptr m_parent; + }; + + + /** + * @short Describes the value constraint of an attribute. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#vc_a">Value Constraint Definition</a> + */ + class ValueConstraint : public QSharedData + { + public: + typedef QExplicitlySharedDataPointer<ValueConstraint> Ptr; + + /** + * Describes the <a href="http://www.w3.org/TR/xmlschema11-1/#ad-value_constraint">value constraint</a> of an attribute. + */ + enum Variety + { + Default, ///< The attribute has a default value set. + Fixed ///< The attribute has a fixed value set. + }; + + /** + * Sets the @p variety of the attribute value constraint. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#vc_a-variety">Variety Definition</a> + */ + void setVariety(Variety variety); + + /** + * Returns the variety of the attribute value constraint. + */ + Variety variety() const; + + /** + * Sets the @p value of the constraint. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#vc_a-value">Value Definition</a> + */ + void setValue(const QString &value); + + /** + * Returns the value of the constraint. + */ + QString value() const; + + /** + * Sets the lexical @p form of the constraint. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#vc_a-lexical_form">Lexical Form Definition</a> + */ + void setLexicalForm(const QString &form); + + /** + * Returns the lexical form of the constraint. + */ + QString lexicalForm() const; + + private: + Variety m_variety; + QString m_value; + QString m_lexicalForm; + }; + + /** + * Sets the simple @p type definition of the attribute. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#ad-type_definition">Simple Type Definition</a> + */ + void setType(const AnySimpleType::Ptr &type); + + /** + * Returns the simple type definition of the attribute. + */ + AnySimpleType::Ptr type() const; + + /** + * Sets the @p scope of the attribute. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#ad-scope">Scope Definition</a> + */ + void setScope(const Scope::Ptr &scope); + + /** + * Returns the scope of the attribute. + */ + Scope::Ptr scope() const; + + /** + * Sets the value @p constraint of the attribute. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#ad-value_constraint">Value Constraint Definition</a> + */ + void setValueConstraint(const ValueConstraint::Ptr &constraint); + + /** + * Returns the value constraint of the attribute. + */ + ValueConstraint::Ptr valueConstraint() const; + + private: + AnySimpleType::Ptr m_type; + Scope::Ptr m_scope; + ValueConstraint::Ptr m_valueConstraint; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdattributegroup.cpp b/src/xmlpatterns/schema/qxsdattributegroup.cpp new file mode 100644 index 0000000..ff62ef5 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdattributegroup.cpp @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdattributegroup_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +void XsdAttributeGroup::setAttributeUses(const XsdAttributeUse::List &attributeUses) +{ + m_attributeUses = attributeUses; +} + +void XsdAttributeGroup::addAttributeUse(const XsdAttributeUse::Ptr &attributeUse) +{ + m_attributeUses.append(attributeUse); +} + +XsdAttributeUse::List XsdAttributeGroup::attributeUses() const +{ + return m_attributeUses; +} + +void XsdAttributeGroup::setWildcard(const XsdWildcard::Ptr &wildcard) +{ + m_wildcard = wildcard; +} + +XsdWildcard::Ptr XsdAttributeGroup::wildcard() const +{ + return m_wildcard; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdattributegroup_p.h b/src/xmlpatterns/schema/qxsdattributegroup_p.h new file mode 100644 index 0000000..3684df2 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdattributegroup_p.h @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdAttributeGroup_H +#define Patternist_XsdAttributeGroup_H + +#include "qxsdannotated_p.h" +#include "qxsdattributeuse_p.h" +#include "qxsdwildcard_p.h" + +#include <QtCore/QList> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short Represents the XSD attributeGroup object. + * + * This class represents the <em>attributeGroup</em> object of a XML schema as described + * <a href="http://www.w3.org/TR/xmlschema11-1/#cAttribute_Group_Definitions">here</a>. + * + * @see <a href="http://www.w3.org/Submission/2004/SUBM-xmlschema-api-20040309/xml-schema-api.html#Interface-XSAttributeGroup">XML Schema API reference</a> + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdAttributeGroup : public NamedSchemaComponent, public XsdAnnotated + { + public: + typedef QExplicitlySharedDataPointer<XsdAttributeGroup> Ptr; + typedef QList<XsdAttributeGroup::Ptr> List; + + /** + * Sets the list of attribute @p uses that are defined in the attribute group. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#agd-attribute_uses">Attribute Uses</a> + */ + void setAttributeUses(const XsdAttributeUse::List &uses); + + /** + * Adds a new attribute @p use to the attribute group. + */ + void addAttributeUse(const XsdAttributeUse::Ptr &use); + + /** + * Returns the list of all attribute uses of the attribute group. + */ + XsdAttributeUse::List attributeUses() const; + + /** + * Sets the attribute @p wildcard of the attribute group. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#agd-attribute_wildcard">Attribute Wildcard</a> + */ + void setWildcard(const XsdWildcard::Ptr &wildcard); + + /** + * Returns the attribute wildcard of the attribute group. + */ + XsdWildcard::Ptr wildcard() const; + + private: + XsdAttributeUse::List m_attributeUses; + XsdWildcard::Ptr m_wildcard; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdattributereference.cpp b/src/xmlpatterns/schema/qxsdattributereference.cpp new file mode 100644 index 0000000..0b3ce03 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdattributereference.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdattributereference_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +bool XsdAttributeReference::isAttributeUse() const +{ + return false; +} + +bool XsdAttributeReference::isReference() const +{ + return true; +} + +void XsdAttributeReference::setType(Type type) +{ + m_type = type; +} + +XsdAttributeReference::Type XsdAttributeReference::type() const +{ + return m_type; +} + +void XsdAttributeReference::setReferenceName(const QXmlName &referenceName) +{ + m_referenceName = referenceName; +} + +QXmlName XsdAttributeReference::referenceName() const +{ + return m_referenceName; +} + +void XsdAttributeReference::setSourceLocation(const QSourceLocation &location) +{ + m_sourceLocation = location; +} + +QSourceLocation XsdAttributeReference::sourceLocation() const +{ + return m_sourceLocation; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdattributereference_p.h b/src/xmlpatterns/schema/qxsdattributereference_p.h new file mode 100644 index 0000000..0d2bdc1 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdattributereference_p.h @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdAttributeReference_H +#define Patternist_XsdAttributeReference_H + +#include "qxsdattributeuse_p.h" + +#include <QtXmlPatterns/QSourceLocation> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short A helper class for attribute reference resolving. + * + * For easy resolving of attribute references, we have this class + * that can be used as a place holder for the real attribute use + * object it is referring to. + * So whenever the parser detects an attribute reference, it creates + * a XsdAttributeReference and returns it instead of the XsdAttributeUse. + * During a later phase, the resolver will look for all XsdAttributeReferences + * in the schema and will replace them with their referring XsdAttributeUse + * objects. + * + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdAttributeReference : public XsdAttributeUse + { + public: + typedef QExplicitlySharedDataPointer<XsdAttributeReference> Ptr; + + /** + * Describes the type of the attribute reference. + */ + enum Type + { + AttributeUse, ///< The reference points to an attribute use. + AttributeGroup ///< The reference points to an attribute group. + }; + + /** + * Always returns false, used to avoid dynamic casts. + */ + virtual bool isAttributeUse() const; + + /** + * Always returns true, used to avoid dynamic casts. + */ + virtual bool isReference() const; + + /** + * Sets the @p type of the attribute reference. + */ + void setType(Type type); + + /** + * Returns the type of the attribute reference. + */ + Type type() const; + + /** + * Sets the @p name of the attribute or attribute group the + * attribute reference refers to. + */ + void setReferenceName(const QXmlName &name); + + /** + * Returns the name of the attribute or attribute group the + * attribute reference refers to. + */ + QXmlName referenceName() const; + + /** + * Sets the source @p location where the reference is located. + */ + void setSourceLocation(const QSourceLocation &location); + + /** + * Returns the source location where the reference is located. + */ + QSourceLocation sourceLocation() const; + + private: + Type m_type; + QXmlName m_referenceName; + QSourceLocation m_sourceLocation; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdattributeterm.cpp b/src/xmlpatterns/schema/qxsdattributeterm.cpp new file mode 100644 index 0000000..78ddd2f --- /dev/null +++ b/src/xmlpatterns/schema/qxsdattributeterm.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdattributeterm_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +bool XsdAttributeTerm::isAttributeUse() const +{ + return false; +} + +bool XsdAttributeTerm::isReference() const +{ + return false; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdattributeterm_p.h b/src/xmlpatterns/schema/qxsdattributeterm_p.h new file mode 100644 index 0000000..4852d46 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdattributeterm_p.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdAttributeTerm_H +#define Patternist_XsdAttributeTerm_H + +#include "qnamedschemacomponent_p.h" +#include "qxsdannotated_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short A base class for all attribute types. + * + * For easy resolving of attribute references, we use this as + * common base class for XsdAttribute and XsdAttributeReference. + * + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdAttributeTerm : public NamedSchemaComponent, public XsdAnnotated + { + public: + typedef QExplicitlySharedDataPointer<XsdAttributeTerm> Ptr; + + /** + * Returns @c true if the term is an attribute use, @c false otherwise. + */ + virtual bool isAttributeUse() const; + + /** + * Returns @c true if the term is an attribute use reference, @c false otherwise. + * + * @note The reference term is only used internally as helper during type resolving. + */ + virtual bool isReference() const; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdattributeuse.cpp b/src/xmlpatterns/schema/qxsdattributeuse.cpp new file mode 100644 index 0000000..d241167 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdattributeuse.cpp @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdattributeuse_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +void XsdAttributeUse::ValueConstraint::setVariety(Variety variety) +{ + m_variety = variety; +} + +XsdAttributeUse::ValueConstraint::Variety XsdAttributeUse::ValueConstraint::variety() const +{ + return m_variety; +} + +void XsdAttributeUse::ValueConstraint::setValue(const QString &value) +{ + m_value = value; +} + +QString XsdAttributeUse::ValueConstraint::value() const +{ + return m_value; +} + +void XsdAttributeUse::ValueConstraint::setLexicalForm(const QString &form) +{ + m_lexicalForm = form; +} + +QString XsdAttributeUse::ValueConstraint::lexicalForm() const +{ + return m_lexicalForm; +} + +XsdAttributeUse::ValueConstraint::Ptr XsdAttributeUse::ValueConstraint::fromAttributeValueConstraint(const XsdAttribute::ValueConstraint::Ptr &constraint) +{ + XsdAttributeUse::ValueConstraint::Ptr newConstraint(new XsdAttributeUse::ValueConstraint()); + switch (constraint->variety()) { + case XsdAttribute::ValueConstraint::Fixed: newConstraint->setVariety(Fixed); break; + case XsdAttribute::ValueConstraint::Default: newConstraint->setVariety(Default); break; + } + newConstraint->setValue(constraint->value()); + newConstraint->setLexicalForm(constraint->lexicalForm()); + + return newConstraint; +} + +XsdAttributeUse::XsdAttributeUse() + : m_useType(OptionalUse) +{ +} + +bool XsdAttributeUse::isAttributeUse() const +{ + return true; +} + +void XsdAttributeUse::setUseType(UseType type) +{ + m_useType = type; +} + +XsdAttributeUse::UseType XsdAttributeUse::useType() const +{ + return m_useType; +} + +bool XsdAttributeUse::isRequired() const +{ + return (m_useType == RequiredUse); +} + +void XsdAttributeUse::setAttribute(const XsdAttribute::Ptr &attribute) +{ + m_attribute = attribute; +} + +XsdAttribute::Ptr XsdAttributeUse::attribute() const +{ + return m_attribute; +} + +void XsdAttributeUse::setValueConstraint(const ValueConstraint::Ptr &constraint) +{ + m_valueConstraint = constraint; +} + +XsdAttributeUse::ValueConstraint::Ptr XsdAttributeUse::valueConstraint() const +{ + return m_valueConstraint; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdattributeuse_p.h b/src/xmlpatterns/schema/qxsdattributeuse_p.h new file mode 100644 index 0000000..eb1dc40 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdattributeuse_p.h @@ -0,0 +1,224 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdAttributeUse_H +#define Patternist_XsdAttributeUse_H + +#include "qxsdattribute_p.h" +#include "qxsdattributeterm_p.h" + +#include <QtCore/QList> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short Represents a XSD attribute use object. + * + * This class represents the <em>attribute use</em> object of a XML schema as described + * <a href="http://www.w3.org/TR/xmlschema11-1/#cAttributeUse">here</a>. + * + * It contains information from a local attribute declaration (as child of <em>complexType</em> + * or <em>attributeGroup</em> object). + * + * All other occurrences of the <em>attribute</em> object are represented by the XsdAttribute class. + * + * @see <a href="http://www.w3.org/Submission/2004/SUBM-xmlschema-api-20040309/xml-schema-api.html#Interface-XSAttributeUse">XML Schema API reference</a> + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdAttributeUse : public XsdAttributeTerm + { + public: + typedef QExplicitlySharedDataPointer<XsdAttributeUse> Ptr; + typedef QList<XsdAttributeUse::Ptr> List; + + /** + * Describes the value constraint of an attribute use. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#vc_au">Value Constraint Definition</a> + */ + class ValueConstraint : public QSharedData + { + public: + typedef QExplicitlySharedDataPointer<ValueConstraint> Ptr; + + /** + * Describes the <a href="http://www.w3.org/TR/xmlschema11-1/#au-value_constraint">value constraint</a> of an attribute use. + */ + enum Variety + { + Default, ///< The attribute use has a default value set. + Fixed ///< The attribute use has a fixed value set. + }; + + /** + * Sets the @p variety of the attribute use value constraint. + */ + void setVariety(Variety variety); + + /** + * Returns the variety of the attribute use value constraint. + */ + Variety variety() const; + + /** + * Sets the @p value of the constraint. + */ + void setValue(const QString &value); + + /** + * Returns the value of the constraint. + */ + QString value() const; + + /** + * Sets the lexical @p form of the constraint. + */ + void setLexicalForm(const QString &form); + + /** + * Returns the lexical form of the constraint. + */ + QString lexicalForm() const; + + /** + * Creates a new value constraint from a XsdAttribute::ValueConstraint. + */ + static ValueConstraint::Ptr fromAttributeValueConstraint(const XsdAttribute::ValueConstraint::Ptr &constraint); + + private: + Variety m_variety; + QString m_value; + QString m_lexicalForm; + }; + + /** + * Describes the use type of the attribute use. + */ + enum UseType + { + OptionalUse, ///< The attribute can be there but doesn't need to. + RequiredUse, ///< The attribute must be there. + ProhibitedUse ///< The attribute is not allowed to be there. + }; + + /** + * Creates a new attribute use object. + */ + XsdAttributeUse(); + + /** + * Always returns true, used to avoid dynamic casts. + */ + virtual bool isAttributeUse() const; + + /** + * Sets the use @p type of the attribute use. + * + * @see UseType + */ + void setUseType(UseType type); + + /** + * Returns the use type of the attribute use. + */ + UseType useType() const; + + /** + * Returns whether the attribute use is required. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#au-required">Required Definition</a> + */ + bool isRequired() const; + + /** + * Sets the @p attribute the attribute use is referring to. + * That is either a local definition as child of a complexType + * or attributeGroup object, or a reference defined by the + * 'ref' attribute. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#au-attribute_declaration">Attribute Declaration</a> + */ + void setAttribute(const XsdAttribute::Ptr &attribute); + + /** + * Returns the attribute the attribute use is referring to. + */ + XsdAttribute::Ptr attribute() const; + + /** + * Sets the value @p constraint of the attribute use. + * + * @see http://www.w3.org/TR/xmlschema11-1/#vc_au + */ + void setValueConstraint(const ValueConstraint::Ptr &constraint); + + /** + * Returns the value constraint of the attribute use. + */ + ValueConstraint::Ptr valueConstraint() const; + + private: + UseType m_useType; + XsdAttribute::Ptr m_attribute; + ValueConstraint::Ptr m_valueConstraint; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdcomplextype.cpp b/src/xmlpatterns/schema/qxsdcomplextype.cpp new file mode 100644 index 0000000..0ecca9e --- /dev/null +++ b/src/xmlpatterns/schema/qxsdcomplextype.cpp @@ -0,0 +1,231 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdcomplextype_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +void XsdComplexType::OpenContent::setMode(Mode mode) +{ + m_mode = mode; +} + +XsdComplexType::OpenContent::Mode XsdComplexType::OpenContent::mode() const +{ + return m_mode; +} + +void XsdComplexType::OpenContent::setWildcard(const XsdWildcard::Ptr &wildcard) +{ + m_wildcard = wildcard; +} + +XsdWildcard::Ptr XsdComplexType::OpenContent::wildcard() const +{ + return m_wildcard; +} + +void XsdComplexType::ContentType::setVariety(Variety variety) +{ + m_variety = variety; +} + +XsdComplexType::ContentType::Variety XsdComplexType::ContentType::variety() const +{ + return m_variety; +} + +void XsdComplexType::ContentType::setParticle(const XsdParticle::Ptr &particle) +{ + m_particle = particle; +} + +XsdParticle::Ptr XsdComplexType::ContentType::particle() const +{ + return m_particle; +} + +void XsdComplexType::ContentType::setOpenContent(const OpenContent::Ptr &content) +{ + m_openContent = content; +} + +XsdComplexType::OpenContent::Ptr XsdComplexType::ContentType::openContent() const +{ + return m_openContent; +} + +void XsdComplexType::ContentType::setSimpleType(const AnySimpleType::Ptr &type) +{ + m_simpleType = type; +} + +AnySimpleType::Ptr XsdComplexType::ContentType::simpleType() const +{ + return m_simpleType; +} + + +XsdComplexType::XsdComplexType() + : m_isAbstract(false) + , m_contentType(new ContentType()) +{ + m_contentType->setVariety(ContentType::Empty); +} + +void XsdComplexType::setIsAbstract(bool abstract) +{ + m_isAbstract = abstract; +} + +bool XsdComplexType::isAbstract() const +{ + return m_isAbstract; +} + +QString XsdComplexType::displayName(const NamePool::Ptr &np) const +{ + return np->displayName(name(np)); +} + +void XsdComplexType::setWxsSuperType(const SchemaType::Ptr &type) +{ + m_superType = type; +} + +SchemaType::Ptr XsdComplexType::wxsSuperType() const +{ + return m_superType; +} + +void XsdComplexType::setContext(const NamedSchemaComponent::Ptr &component) +{ + m_context = component; +} + +NamedSchemaComponent::Ptr XsdComplexType::context() const +{ + return m_context; +} + +void XsdComplexType::setContentType(const ContentType::Ptr &type) +{ + m_contentType = type; +} + +XsdComplexType::ContentType::Ptr XsdComplexType::contentType() const +{ + return m_contentType; +} + +void XsdComplexType::setAttributeUses(const XsdAttributeUse::List &attributeUses) +{ + m_attributeUses = attributeUses; +} + +void XsdComplexType::addAttributeUse(const XsdAttributeUse::Ptr &attributeUse) +{ + m_attributeUses.append(attributeUse); +} + +XsdAttributeUse::List XsdComplexType::attributeUses() const +{ + return m_attributeUses; +} + +void XsdComplexType::setAttributeWildcard(const XsdWildcard::Ptr &wildcard) +{ + m_attributeWildcard = wildcard; +} + +XsdWildcard::Ptr XsdComplexType::attributeWildcard() const +{ + return m_attributeWildcard; +} + +XsdComplexType::TypeCategory XsdComplexType::category() const +{ + return ComplexType; +} + +void XsdComplexType::setDerivationMethod(DerivationMethod method) +{ + m_derivationMethod = method; +} + +XsdComplexType::DerivationMethod XsdComplexType::derivationMethod() const +{ + return m_derivationMethod; +} + +void XsdComplexType::setProhibitedSubstitutions(const BlockingConstraints &substitutions) +{ + m_prohibitedSubstitutions = substitutions; +} + +XsdComplexType::BlockingConstraints XsdComplexType::prohibitedSubstitutions() const +{ + return m_prohibitedSubstitutions; +} + +void XsdComplexType::setAssertions(const XsdAssertion::List &assertions) +{ + m_assertions = assertions; +} + +void XsdComplexType::addAssertion(const XsdAssertion::Ptr &assertion) +{ + m_assertions.append(assertion); +} + +XsdAssertion::List XsdComplexType::assertions() const +{ + return m_assertions; +} + +bool XsdComplexType::isDefinedBySchema() const +{ + return true; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdcomplextype_p.h b/src/xmlpatterns/schema/qxsdcomplextype_p.h new file mode 100644 index 0000000..ad04f99 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdcomplextype_p.h @@ -0,0 +1,404 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdComplexType_H +#define Patternist_XsdComplexType_H + +#include "qanytype_p.h" +#include "qxsdassertion_p.h" +#include "qxsdattributeuse_p.h" +#include "qxsdparticle_p.h" +#include "qxsdsimpletype_p.h" +#include "qxsduserschematype_p.h" +#include "qxsdwildcard_p.h" + +#include <QtCore/QSet> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short Represents a XSD complexType object. + * + * This class represents the <em>complexType</em> object of a XML schema as described + * <a href="http://www.w3.org/TR/xmlschema11-1/#Complex_Type_Definitions">here</a>. + * + * It contains information from either a top-level complex type declaration (as child of a <em>schema</em> object) + * or a local complex type declaration (as descendant of an <em>element</em> object). + * + * @see <a href="http://www.w3.org/Submission/2004/SUBM-xmlschema-api-20040309/xml-schema-api.html#Interface-XSComplexType">XML Schema API reference</a> + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdComplexType : public XsdUserSchemaType<AnyType> + { + public: + typedef QExplicitlySharedDataPointer<XsdComplexType> Ptr; + + /** + * @short Describes the open content object of a complex type. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#ct-open_content">Open Content Definition</a> + */ + class OpenContent : public QSharedData, public XsdAnnotated + { + public: + typedef QExplicitlySharedDataPointer<OpenContent> Ptr; + + /** + * Describes the mode of the open content. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#oc-mode">Mode Definition</a> + */ + enum Mode + { + None, + Interleave, + Suffix + }; + + /** + * Sets the @p mode of the open content. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#oc-mode">Mode Definition</a> + */ + void setMode(Mode mode); + + /** + * Returns the mode of the open content. + */ + Mode mode() const; + + /** + * Sets the @p wildcard of the open content. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#oc-wildcard">Wildcard Definition</a> + */ + void setWildcard(const XsdWildcard::Ptr &wildcard); + + /** + * Returns the wildcard of the open content. + */ + XsdWildcard::Ptr wildcard() const; + + private: + Mode m_mode; + XsdWildcard::Ptr m_wildcard; + }; + + /** + * @short Describes the content type of a complex type. + */ + class ContentType : public QSharedData + { + public: + typedef QExplicitlySharedDataPointer<ContentType> Ptr; + + /** + * Describes the variety of the content type. + */ + enum Variety + { + Empty = 0, ///< The complex type has no further content. + Simple, ///< The complex type has only simple type content (e.g. text, number etc.) + ElementOnly, ///< The complex type has further elements or attributes but no text as content. + Mixed ///< The complex type has further elements or attributes and text as content. + }; + + /** + * Sets the @p variety of the content type. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#ct-variety">Variety Definition</a> + */ + void setVariety(Variety variety); + + /** + * Returns the variety of the content type. + */ + Variety variety() const; + + /** + * Sets the @p particle object of the content type. + * + * The content type has only a particle object if + * its variety is ElementOnly or Mixed. + * + * @see XsdParticle + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#ct-particle">Particle Declaration</a> + */ + void setParticle(const XsdParticle::Ptr &particle); + + /** + * Returns the particle object of the content type, + * or an empty pointer if its variety is neither + * ElementOnly nor Mixed. + */ + XsdParticle::Ptr particle() const; + + /** + * Sets the open @p content object of the content type. + * + * The content type has only an open content object if + * its variety is ElementOnly or Mixed. + * + * @see OpenContent + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#ct-open_content">Open Content Declaration</a> + */ + void setOpenContent(const OpenContent::Ptr &content); + + /** + * Returns the open content object of the content type, + * or an empty pointer if its variety is neither + * ElementOnly nor Mixed. + */ + OpenContent::Ptr openContent() const; + + /** + * Sets the simple @p type object of the content type. + * + * The content type has only a simple type object if + * its variety is Simple. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#ct-simple_type_definition">Simple Type Definition</a> + */ + void setSimpleType(const AnySimpleType::Ptr &type); + + /** + * Returns the simple type object of the content type, + * or an empty pointer if its variety is not Simple. + */ + AnySimpleType::Ptr simpleType() const; + + private: + Variety m_variety; + XsdParticle::Ptr m_particle; + OpenContent::Ptr m_openContent; + XsdSimpleType::Ptr m_simpleType; + }; + + + /** + * Creates a complex type object with empty content. + */ + XsdComplexType(); + + /** + * Destroys the complex type object. + */ + ~XsdComplexType() {}; + + /** + * Returns the display name of the complex type. + * + * The display name can be used to show the type name + * to the user. + * + * @param namePool The name pool where the type name is stored in. + */ + virtual QString displayName(const NamePool::Ptr &namePool) const; + + /** + * Sets the base type of the complex type. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#ctd-base_type_definition">Base Type Definition</a> + */ + void setWxsSuperType(const SchemaType::Ptr &type); + + /** + * Returns the base type of the complex type. + */ + virtual SchemaType::Ptr wxsSuperType() const; + + /** + * Sets the context @p component of the complex type. + * + * The component is either an element declaration or a complex type definition. + */ + void setContext(const NamedSchemaComponent::Ptr &component); + + /** + * Returns the context component of the complex type. + */ + NamedSchemaComponent::Ptr context() const; + + /** + * Sets the derivation @p method of the complex type. + * + * The derivation method depends on whether the complex + * type object has an extension or restriction object as child. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#ctd-derivation_method">Derivation Method Definition</a> + * @see DerivationMethod + */ + void setDerivationMethod(DerivationMethod method); + + /** + * Returns the derivation method of the complex type. + */ + virtual DerivationMethod derivationMethod() const; + + /** + * Sets whether the complex type is @p abstract. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#ctd-abstract">Abstract Definition</a> + */ + void setIsAbstract(bool abstract); + + /** + * Returns whether the complex type is abstract. + */ + virtual bool isAbstract() const; + + /** + * Sets the list of all attribute @p uses of the complex type. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#ctd-attribute_uses">Attribute Uses Declaration</a> + */ + void setAttributeUses(const XsdAttributeUse::List &uses); + + /** + * Adds a new attribute @p use to the complex type. + */ + void addAttributeUse(const XsdAttributeUse::Ptr &use); + + /** + * Returns the list of all attribute uses of the complex type. + */ + XsdAttributeUse::List attributeUses() const; + + /** + * Sets the attribute @p wildcard of the complex type. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#ctd-attribute_wildcard">Attribute Wildcard Declaration</a> + */ + void setAttributeWildcard(const XsdWildcard::Ptr &wildcard); + + /** + * Returns the attribute wildcard of the complex type. + */ + XsdWildcard::Ptr attributeWildcard() const; + + /** + * Always returns SchemaType::ComplexType + */ + virtual TypeCategory category() const; + + /** + * Sets the content @p type of the complex type. + * + * @see ContentType + */ + void setContentType(const ContentType::Ptr &type); + + /** + * Returns the content type of the complex type. + */ + ContentType::Ptr contentType() const; + + /** + * Sets the prohibited @p substitutions of the complex type. + * + * Only ExtensionConstraint and RestrictionConstraint are allowed. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#ctd-prohibited_substitutions">Prohibited Substitutions Definition</a> + */ + void setProhibitedSubstitutions(const BlockingConstraints &substitutions); + + /** + * Returns the prohibited substitutions of the complex type. + */ + BlockingConstraints prohibitedSubstitutions() const; + + /** + * Sets the @p assertions of the complex type. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#ctd-assertions">Assertions Definition</a> + */ + void setAssertions(const XsdAssertion::List &assertions); + + /** + * Adds an @p assertion to the complex type. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#ctd-assertions">Assertions Definition</a> + */ + void addAssertion(const XsdAssertion::Ptr &assertion); + + /** + * Returns the assertions of the complex type. + */ + XsdAssertion::List assertions() const; + + /** + * Always returns @c true. + */ + virtual bool isDefinedBySchema() const; + + private: + SchemaType::Ptr m_superType; + NamedSchemaComponent::Ptr m_context; + DerivationMethod m_derivationMethod; + bool m_isAbstract; + XsdAttributeUse::List m_attributeUses; + XsdWildcard::Ptr m_attributeWildcard; + ContentType::Ptr m_contentType; + BlockingConstraints m_prohibitedSubstitutions; + XsdAssertion::List m_assertions; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsddocumentation.cpp b/src/xmlpatterns/schema/qxsddocumentation.cpp new file mode 100644 index 0000000..b3e1682 --- /dev/null +++ b/src/xmlpatterns/schema/qxsddocumentation.cpp @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsddocumentation_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +XsdDocumentation::XsdDocumentation() +{ +} + +XsdDocumentation::~XsdDocumentation() +{ +} + +void XsdDocumentation::setSource(const AnyURI::Ptr &source) +{ + m_source = source; +} + +AnyURI::Ptr XsdDocumentation::source() const +{ + return m_source; +} + +void XsdDocumentation::setLanguage(const DerivedString<TypeLanguage>::Ptr &language) +{ + m_language = language; +} + +DerivedString<TypeLanguage>::Ptr XsdDocumentation::language() const +{ + return m_language; +} + +void XsdDocumentation::setContent(const QString &content) +{ + m_content = content; +} + +QString XsdDocumentation::content() const +{ + return m_content; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsddocumentation_p.h b/src/xmlpatterns/schema/qxsddocumentation_p.h new file mode 100644 index 0000000..049ba80 --- /dev/null +++ b/src/xmlpatterns/schema/qxsddocumentation_p.h @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdDocumentation_H +#define Patternist_XsdDocumentation_H + +#include "qanytype_p.h" +#include "qanyuri_p.h" +#include "qderivedstring_p.h" +#include "qnamedschemacomponent_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short Represents a XSD documentation object. + * + * This class represents the <em>documentation</em> component of an <em>annotation</em> object + * of a XML schema as described <a href="http://www.w3.org/TR/xmlschema11-1/#cAnnotations">here</a>. + * + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdDocumentation : public NamedSchemaComponent + { + public: + typedef QExplicitlySharedDataPointer<XsdDocumentation> Ptr; + typedef QList<XsdDocumentation::Ptr> List; + + /** + * Creates a new documentation object. + */ + XsdDocumentation(); + + /** + * Destroys the documentation object. + */ + ~XsdDocumentation(); + + /** + * Sets the @p source of the documentation. + * + * The source points to an URL that contains more + * information. + */ + void setSource(const AnyURI::Ptr &source); + + /** + * Returns the source of the documentation. + */ + AnyURI::Ptr source() const; + + /** + * Sets the @p language of the documentation. + */ + void setLanguage(const DerivedString<TypeLanguage>::Ptr &language); + + /** + * Returns the language of the documentation. + */ + DerivedString<TypeLanguage>::Ptr language() const; + + /** + * Sets the @p content of the documentation. + * + * The content can be of abritrary type. + */ + void setContent(const QString &content); + + /** + * Returns the content of the documentation. + */ + QString content() const; + + private: + AnyURI::Ptr m_source; + DerivedString<TypeLanguage>::Ptr m_language; + QString m_content; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdelement.cpp b/src/xmlpatterns/schema/qxsdelement.cpp new file mode 100644 index 0000000..c907144 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdelement.cpp @@ -0,0 +1,244 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdelement_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +void XsdElement::Scope::setVariety(Variety variety) +{ + m_variety = variety; +} + +XsdElement::Scope::Variety XsdElement::Scope::variety() const +{ + return m_variety; +} + +void XsdElement::Scope::setParent(const NamedSchemaComponent::Ptr &parent) +{ + m_parent = parent; +} + +NamedSchemaComponent::Ptr XsdElement::Scope::parent() const +{ + return m_parent; +} + +void XsdElement::ValueConstraint::setVariety(Variety variety) +{ + m_variety = variety; +} + +XsdElement::ValueConstraint::Variety XsdElement::ValueConstraint::variety() const +{ + return m_variety; +} + +void XsdElement::ValueConstraint::setValue(const QString &value) +{ + m_value = value; +} + +QString XsdElement::ValueConstraint::value() const +{ + return m_value; +} + +void XsdElement::ValueConstraint::setLexicalForm(const QString &form) +{ + m_lexicalForm = form; +} + +QString XsdElement::ValueConstraint::lexicalForm() const +{ + return m_lexicalForm; +} + +void XsdElement::TypeTable::addAlternative(const XsdAlternative::Ptr &alternative) +{ + m_alternatives.append(alternative); +} + +XsdAlternative::List XsdElement::TypeTable::alternatives() const +{ + return m_alternatives; +} + +void XsdElement::TypeTable::setDefaultTypeDefinition(const XsdAlternative::Ptr &type) +{ + m_defaultTypeDefinition = type; +} + +XsdAlternative::Ptr XsdElement::TypeTable::defaultTypeDefinition() const +{ + return m_defaultTypeDefinition; +} + + +XsdElement::XsdElement() + : m_isAbstract(false) +{ +} + +bool XsdElement::isElement() const +{ + return true; +} + +void XsdElement::setType(const SchemaType::Ptr &type) +{ + m_type = type; +} + +SchemaType::Ptr XsdElement::type() const +{ + return m_type; +} + +void XsdElement::setScope(const Scope::Ptr &scope) +{ + m_scope = scope; +} + +XsdElement::Scope::Ptr XsdElement::scope() const +{ + return m_scope; +} + +void XsdElement::setValueConstraint(const ValueConstraint::Ptr &constraint) +{ + m_valueConstraint = constraint; +} + +XsdElement::ValueConstraint::Ptr XsdElement::valueConstraint() const +{ + return m_valueConstraint; +} + +void XsdElement::setTypeTable(const TypeTable::Ptr &table) +{ + m_typeTable = table; +} + +XsdElement::TypeTable::Ptr XsdElement::typeTable() const +{ + return m_typeTable; +} + +void XsdElement::setIsAbstract(bool abstract) +{ + m_isAbstract = abstract; +} + +bool XsdElement::isAbstract() const +{ + return m_isAbstract; +} + +void XsdElement::setIsNillable(bool nillable) +{ + m_isNillable = nillable; +} + +bool XsdElement::isNillable() const +{ + return m_isNillable; +} + +void XsdElement::setDisallowedSubstitutions(const BlockingConstraints &substitutions) +{ + m_disallowedSubstitutions = substitutions; +} + +XsdElement::BlockingConstraints XsdElement::disallowedSubstitutions() const +{ + return m_disallowedSubstitutions; +} + +void XsdElement::setSubstitutionGroupExclusions(const SchemaType::DerivationConstraints &exclusions) +{ + m_substitutionGroupExclusions = exclusions; +} + +SchemaType::DerivationConstraints XsdElement::substitutionGroupExclusions() const +{ + return m_substitutionGroupExclusions; +} + +void XsdElement::setIdentityConstraints(const XsdIdentityConstraint::List &constraints) +{ + m_identityConstraints = constraints; +} + +void XsdElement::addIdentityConstraint(const XsdIdentityConstraint::Ptr &constraint) +{ + m_identityConstraints.append(constraint); +} + +XsdIdentityConstraint::List XsdElement::identityConstraints() const +{ + return m_identityConstraints; +} + +void XsdElement::setSubstitutionGroupAffiliations(const XsdElement::List &affiliations) +{ + m_substitutionGroupAffiliations = affiliations; +} + +XsdElement::List XsdElement::substitutionGroupAffiliations() const +{ + return m_substitutionGroupAffiliations; +} + +void XsdElement::addSubstitutionGroup(const XsdElement::Ptr &element) +{ + m_substitutionGroups.insert(element); +} + +XsdElement::List XsdElement::substitutionGroups() const +{ + return m_substitutionGroups.toList(); +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdelement_p.h b/src/xmlpatterns/schema/qxsdelement_p.h new file mode 100644 index 0000000..304e888 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdelement_p.h @@ -0,0 +1,403 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdElement_H +#define Patternist_XsdElement_H + +#include "qschemacomponent_p.h" +#include "qschematype_p.h" +#include "qxsdalternative_p.h" +#include "qxsdidentityconstraint_p.h" +#include "qxsdcomplextype_p.h" + +#include <QtCore/QList> +#include <QtCore/QSet> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short Represents a XSD element object. + * + * This class represents the <em>element</em> object of a XML schema as described + * <a href="http://www.w3.org/TR/xmlschema11-1/#cElement_Declarations">here</a>. + * + * It contains information from either a top-level element declaration (as child of a <em>schema</em> object) + * or a local element declaration (as descendant of an <em>complexType</em> object). + * + * @see <a href="http://www.w3.org/Submission/2004/SUBM-xmlschema-api-20040309/xml-schema-api.html#Interface-XSElementDecl">XML Schema API reference</a> + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdElement : public XsdTerm + { + public: + typedef QExplicitlySharedDataPointer<XsdElement> Ptr; + typedef QList<XsdElement::Ptr> List; + + + /** + * Describes the <a href="http://www.w3.org/TR/xmlschema11-1/#ed-value_constraint">constraint type</a> of the element. + */ + enum ConstraintType + { + NoneConstraint, ///< The value of the element has no constraints. + DefaultConstraint, ///< The element has a default value set. + FixedConstraint ///< The element has a fixed value set. + }; + + /** + * Describes the scope of an element. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#sc_e">Scope Definition</a> + */ + class Scope : public QSharedData + { + public: + typedef QExplicitlySharedDataPointer<Scope> Ptr; + + /** + * Describes the <a href="http://www.w3.org/TR/xmlschema11-1/#ad-scope">scope</a> of an attribute. + */ + enum Variety + { + Global, ///< The element is defined globally as child of the <em>schema</em> object. + Local ///< The element is defined locally as child of a complex type or model group definition. + }; + + /** + * Sets the @p variety of the element scope. + */ + void setVariety(Variety variety); + + /** + * Returns the variety of the element scope. + */ + Variety variety() const; + + /** + * Sets the @p parent complex type or model group definition of the element scope. + */ + void setParent(const NamedSchemaComponent::Ptr &parent); + + /** + * Returns the parent complex type or model group definition of the element scope. + */ + NamedSchemaComponent::Ptr parent() const; + + private: + Variety m_variety; + NamedSchemaComponent::Ptr m_parent; + }; + + /** + * Describes a type table of an element. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#tt">Type Table Definition</a> + */ + class TypeTable : public QSharedData + { + public: + typedef QExplicitlySharedDataPointer<TypeTable> Ptr; + + /** + * Adds an @p alternative to the type table. + */ + void addAlternative(const XsdAlternative::Ptr &alternative); + + /** + * Returns the alternatives of the type table. + */ + XsdAlternative::List alternatives() const; + + /** + * Sets the default @p type definition. + */ + void setDefaultTypeDefinition(const XsdAlternative::Ptr &type); + + /** + * Returns the default type definition. + */ + XsdAlternative::Ptr defaultTypeDefinition() const; + + private: + XsdAlternative::List m_alternatives; + XsdAlternative::Ptr m_defaultTypeDefinition; + }; + + + /** + * Describes the value constraint of an element. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#vc_e">Value Constraint Definition</a> + */ + class ValueConstraint : public QSharedData + { + public: + typedef QExplicitlySharedDataPointer<ValueConstraint> Ptr; + + /** + * Describes the <a href="http://www.w3.org/TR/xmlschema11-1/#ed-value_constraint">value constraint</a> of an element. + */ + enum Variety + { + Default, ///< The element has a default value set. + Fixed ///< The element has a fixed value set. + }; + + /** + * Sets the @p variety of the element value constraint. + */ + void setVariety(Variety variety); + + /** + * Returns the variety of the element value constraint. + */ + Variety variety() const; + + /** + * Sets the @p value of the constraint. + */ + void setValue(const QString &value); + + /** + * Returns the value of the constraint. + */ + QString value() const; + + /** + * Sets the lexical @p form of the constraint. + */ + void setLexicalForm(const QString &form); + + /** + * Returns the lexical form of the constraint. + */ + QString lexicalForm() const; + + private: + Variety m_variety; + QString m_value; + QString m_lexicalForm; + }; + + /** + * Creates a new element object. + */ + XsdElement(); + + /** + * Always returns @c true, used to avoid dynamic casts. + */ + virtual bool isElement() const; + + /** + * Sets the @p type of the element. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#ed-type_definition">Type Definition</a> + */ + void setType(const SchemaType::Ptr &type); + + /** + * Returns the type of the element. + */ + SchemaType::Ptr type() const; + + /** + * Sets the @p scope of the element. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#ed-scope">Scope Definition</a> + */ + void setScope(const Scope::Ptr &scope); + + /** + * Returns the scope of the element. + */ + Scope::Ptr scope() const; + + /** + * Sets the value @p constraint of the element. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#ed-value_constraint">Value Constraint Definition</a> + */ + void setValueConstraint(const ValueConstraint::Ptr &constraint); + + /** + * Returns the value constraint of the element. + */ + ValueConstraint::Ptr valueConstraint() const; + + /** + * Sets the type table of the element. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#ed-type_table">Type Table Definition</a> + */ + void setTypeTable(const TypeTable::Ptr &table); + + /** + * Returns the type table of the element. + */ + TypeTable::Ptr typeTable() const; + + /** + * Sets whether the element is @p abstract. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#ed-abstract">Abstract Definition</a> + */ + void setIsAbstract(bool abstract); + + /** + * Returns whether the element is abstract. + */ + bool isAbstract() const; + + /** + * Sets whether the element is @p nillable. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#ed-nillable">Nillable Definition</a> + */ + void setIsNillable(bool nillable); + + /** + * Returns whether the element is nillable. + */ + bool isNillable() const; + + /** + * Sets the disallowed @p substitutions of the element. + * + * Only ExtensionConstraint, RestrictionConstraint and SubstitutionConstraint are allowed. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#ed-disallowed_substitutions">Disallowed Substitutions Definition</a> + */ + void setDisallowedSubstitutions(const BlockingConstraints &substitutions); + + /** + * Returns the disallowed substitutions of the element. + */ + BlockingConstraints disallowedSubstitutions() const; + + /** + * Sets the substitution group @p exclusions of the element. + * + * Only SchemaType::ExtensionConstraint and SchemaType::RestrictionConstraint are allowed. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#ed-substitution_group_exclusions">Substitution Group Exclusions Definition</a> + */ + void setSubstitutionGroupExclusions(const SchemaType::DerivationConstraints &exclusions); + + /** + * Returns the substitution group exclusions of the element. + */ + SchemaType::DerivationConstraints substitutionGroupExclusions() const; + + /** + * Sets the identity @p constraints of the element. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#ed-identity-constraint_definitions">Identity Constraint Definition</a> + */ + void setIdentityConstraints(const XsdIdentityConstraint::List &constraints); + + /** + * Adds a new identity @p constraint to the element. + */ + void addIdentityConstraint(const XsdIdentityConstraint::Ptr &constraint); + + /** + * Returns a list of all identity constraints of the element. + */ + XsdIdentityConstraint::List identityConstraints() const; + + /** + * Sets the substitution group @p affiliations of the element. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#ed-substituion_group_affiliations">Substitution Group Affiliations</a> + */ + void setSubstitutionGroupAffiliations(const XsdElement::List &affiliations); + + /** + * Returns the substitution group affiliations of the element. + */ + XsdElement::List substitutionGroupAffiliations() const; + + /** + * Adds a substitution group to the element. + */ + void addSubstitutionGroup(const XsdElement::Ptr &elements); + + /** + * Returns the substitution groups of the element. + */ + XsdElement::List substitutionGroups() const; + + private: + SchemaType::Ptr m_type; + Scope::Ptr m_scope; + ValueConstraint::Ptr m_valueConstraint; + TypeTable::Ptr m_typeTable; + bool m_isAbstract; + bool m_isNillable; + BlockingConstraints m_disallowedSubstitutions; + SchemaType::DerivationConstraints m_substitutionGroupExclusions; + XsdIdentityConstraint::List m_identityConstraints; + XsdElement::List m_substitutionGroupAffiliations; + QSet<XsdElement::Ptr> m_substitutionGroups; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdfacet.cpp b/src/xmlpatterns/schema/qxsdfacet.cpp new file mode 100644 index 0000000..7bbbc9d --- /dev/null +++ b/src/xmlpatterns/schema/qxsdfacet.cpp @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdfacet_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +XsdFacet::XsdFacet() + : m_type(None) +{ +} + +void XsdFacet::setType(Type type) +{ + m_type = type; +} + +XsdFacet::Type XsdFacet::type() const +{ + return m_type; +} + +void XsdFacet::setValue(const AtomicValue::Ptr &value) +{ + m_value = value; +} + +AtomicValue::Ptr XsdFacet::value() const +{ + return m_value; +} + +void XsdFacet::setMultiValue(const AtomicValue::List &value) +{ + m_multiValue = value; +} + +AtomicValue::List XsdFacet::multiValue() const +{ + return m_multiValue; +} + +void XsdFacet::setAssertions(const XsdAssertion::List &assertions) +{ + m_assertions = assertions; +} + +XsdAssertion::List XsdFacet::assertions() const +{ + return m_assertions; +} + +void XsdFacet::setFixed(bool fixed) +{ + m_fixed = fixed; +} + +bool XsdFacet::fixed() const +{ + return m_fixed; +} + +QString XsdFacet::typeName(Type type) +{ + switch (type) { + case Length: return QLatin1String("length"); break; + case MinimumLength: return QLatin1String("minLength"); break; + case MaximumLength: return QLatin1String("maxLength"); break; + case Pattern: return QLatin1String("pattern"); break; + case WhiteSpace: return QLatin1String("whiteSpace"); break; + case MaximumInclusive: return QLatin1String("maxInclusive"); break; + case MaximumExclusive: return QLatin1String("maxExclusive"); break; + case MinimumInclusive: return QLatin1String("minInclusive"); break; + case MinimumExclusive: return QLatin1String("minExclusive"); break; + case TotalDigits: return QLatin1String("totalDigits"); break; + case FractionDigits: return QLatin1String("fractionDigits"); break; + case Enumeration: return QLatin1String("enumeration"); break; + case Assertion: return QLatin1String("assertion"); break; + case None: // fall through + default: return QLatin1String("none"); break; + } +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdfacet_p.h b/src/xmlpatterns/schema/qxsdfacet_p.h new file mode 100644 index 0000000..5d16b4e --- /dev/null +++ b/src/xmlpatterns/schema/qxsdfacet_p.h @@ -0,0 +1,213 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdFacet_H +#define Patternist_XsdFacet_H + +#include "qitem_p.h" +#include "qnamedschemacomponent_p.h" +#include "qxsdannotated_p.h" +#include "qxsdassertion_p.h" + +#include <QtCore/QList> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short Represents a XSD facet object. + * + * This class represents one of the following XML schema objects: + * + * <ul> + * <li><em>length</em> <a href="http://www.w3.org/TR/xmlschema-2/#rf-length">Definition</a></li> + * <li><em>minLength</em> <a href="http://www.w3.org/TR/xmlschema-2/#rf-minLength">Definition</a></li> + * <li><em>maxLength</em> <a href="http://www.w3.org/TR/xmlschema-2/#rf-maxLength">Definition</a></li> + * <li><em>pattern</em> <a href="http://www.w3.org/TR/xmlschema-2/#rf-pattern">Definition</a></li> + * <li><em>whiteSpace</em> <a href="http://www.w3.org/TR/xmlschema-2/#rf-whiteSpace">Definition</a></li> + * <li><em>maxInclusive</em> <a href="http://www.w3.org/TR/xmlschema-2/#rf-maxInclusive">Definition</a></li> + * <li><em>maxExclusive</em> <a href="http://www.w3.org/TR/xmlschema-2/#rf-maxExclusive">Definition</a></li> + * <li><em>minInclusive</em> <a href="http://www.w3.org/TR/xmlschema-2/#rf-minInclusive">Definition</a></li> + * <li><em>minExclusive</em> <a href="http://www.w3.org/TR/xmlschema-2/#rf-minExclusive">Definition</a></li> + * <li><em>totalDigits</em> <a href="http://www.w3.org/TR/xmlschema-2/#rf-totalDigits">Definition</a></li> + * <li><em>fractionDigits</em> <a href="http://www.w3.org/TR/xmlschema-2/#rf-fractionDigits">Definition</a></li> + * <li><em>enumeration</em> <a href="http://www.w3.org/TR/xmlschema-2/#rf-enumeration">Definition</a></li> + * <li><em>assertion</em> <a href="http://www.w3.org/TR/xmlschema-2/#rf-assertion">Definition</a></li> + * </ul> + * + * @see <a href="http://www.w3.org/Submission/2004/SUBM-xmlschema-api-20040309/xml-schema-api.html#Interface-XSFacet">XML Schema API reference</a> + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdFacet : public NamedSchemaComponent, public XsdAnnotated + { + public: + typedef QExplicitlySharedDataPointer<XsdFacet> Ptr; + + /** + * Describes the type of the facet. + */ + enum Type + { + None = 0, ///< An invalid facet. + Length = 1 << 0, ///< Match the exact length (<a href="http://www.w3.org/TR/xmlschema-2/#rf-length">Length Definition</a>) + MinimumLength = 1 << 1, ///< Match the minimum length (<a href="http://www.w3.org/TR/xmlschema-2/#rf-minLength">Minimum Length Definition</a>) + MaximumLength = 1 << 2, ///< Match the maximum length (<a href="http://www.w3.org/TR/xmlschema-2/#rf-maxLength">Maximum Length Definition</a>) + Pattern = 1 << 3, ///< Match a regular expression (<a href="http://www.w3.org/TR/xmlschema-2/#rf-pattern">Pattern Definition</a>) + WhiteSpace = 1 << 4, ///< Match a whitespace rule (<a href="http://www.w3.org/TR/xmlschema-2/#rf-whiteSpace">White Space Definition</a>) + MaximumInclusive = 1 << 5, ///< Match a maximum inclusive (<a href="http://www.w3.org/TR/xmlschema-2/#rf-maxInclusive">Maximum Inclusive Definition</a>) + MaximumExclusive = 1 << 6, ///< Match a maximum exclusive (<a href="http://www.w3.org/TR/xmlschema-2/#rf-maxExclusive">Maximum Exclusive Definition</a>) + MinimumInclusive = 1 << 7, ///< Match a minimum inclusive (<a href="http://www.w3.org/TR/xmlschema-2/#rf-minInclusive">Minimum Inclusive Definition</a>) + MinimumExclusive = 1 << 8, ///< Match a minimum exclusive (<a href="http://www.w3.org/TR/xmlschema-2/#rf-minExclusive">Minimum Exclusive Definition</a>) + TotalDigits = 1 << 9, ///< Match some integer digits (<a href="http://www.w3.org/TR/xmlschema-2/#rf-totalDigits">Total Digits Definition</a>) + FractionDigits = 1 << 10, ///< Match some double digits (<a href="http://www.w3.org/TR/xmlschema-2/#rf-fractionDigits">Fraction Digits Definition</a>) + Enumeration = 1 << 11, ///< Match an enumeration (<a href="http://www.w3.org/TR/xmlschema-2/#rf-enumeration">Enumeration Definition</a>) + Assertion = 1 << 12, ///< Match an assertion (<a href="http://www.w3.org/TR/xmlschema-2/#rf-assertion">Assertion Definition</a>) + }; + typedef QHash<XsdFacet::Type, XsdFacet::Ptr> Hash; + typedef QHashIterator<XsdFacet::Type, XsdFacet::Ptr> HashIterator; + + /** + * Creates a new facet object of type None. + */ + XsdFacet(); + + /** + * Sets the @p type of the facet. + * + * @see Type + */ + void setType(Type type); + + /** + * Returns the type of the facet. + */ + Type type() const; + + /** + * Sets the @p value of the facet. + * + * Depending on the type of the facet the + * value can be a string, interger, double etc. + * + * @note This method should be used for all types of facets + * except Pattern, Enumeration and Assertion. + */ + void setValue(const AtomicValue::Ptr &value); + + /** + * Returns the value of the facet or an empty pointer if facet + * type is Pattern, Enumeration or Assertion. + */ + AtomicValue::Ptr value() const; + + /** + * Sets the @p value of the facet. + * + * @note This method should be used for if the type of the + * facet is Pattern or Enumeration. + */ + void setMultiValue(const AtomicValue::List &value); + + /** + * Returns the value of the facet or an empty pointer if facet + * type is not of type Pattern or Enumeration. + */ + AtomicValue::List multiValue() const; + + /** + * Sets the @p assertions of the facet. + * + * @note This method should be used if the type of the + * facet is Assertion. + */ + void setAssertions(const XsdAssertion::List &assertions); + + /** + * Returns the assertions of the facet or an empty pointer if facet + * type is not of type Assertion. + */ + XsdAssertion::List assertions() const; + + /** + * Sets whether the facet is @p fixed. + * + * All facets except pattern, enumeration and assertion can be fixed. + */ + void setFixed(bool fixed); + + /** + * Returns whether the facet is fixed. + */ + bool fixed() const; + + /** + * Returns the textual description of the facet @p type. + */ + static QString typeName(Type type); + + private: + Type m_type; + AtomicValue::Ptr m_value; + AtomicValue::List m_multiValue; + XsdAssertion::List m_assertions; + bool m_fixed; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdidcache.cpp b/src/xmlpatterns/schema/qxsdidcache.cpp new file mode 100644 index 0000000..25788c8 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdidcache.cpp @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdidcache_p.h" + +#include <QtCore/QReadLocker> +#include <QtCore/QWriteLocker> + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +void XsdIdCache::addId(const QString &id) +{ + const QWriteLocker locker(&m_lock); + Q_ASSERT(!m_ids.contains(id)); + + m_ids.insert(id); +} + +bool XsdIdCache::hasId(const QString &id) const +{ + const QReadLocker locker(&m_lock); + + return m_ids.contains(id); +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdidcache_p.h b/src/xmlpatterns/schema/qxsdidcache_p.h new file mode 100644 index 0000000..dae967e --- /dev/null +++ b/src/xmlpatterns/schema/qxsdidcache_p.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdIdCache_H +#define Patternist_XsdIdCache_H + +#include "qschemacomponent_p.h" + +#include <QtCore/QExplicitlySharedDataPointer> +#include <QtCore/QReadWriteLock> +#include <QtCore/QSet> +#include <QtCore/QString> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short Helper class for keeping track of all existing IDs in a schema. + * + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdIdCache : public QSharedData + { + public: + typedef QExplicitlySharedDataPointer<XsdIdCache> Ptr; + + /** + * Adds an @p id to the id cache. + */ + void addId(const QString &id); + + /** + * Returns whether the id cache contains the given @p id already. + */ + bool hasId(const QString &id) const; + + private: + QSet<QString> m_ids; + mutable QReadWriteLock m_lock; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdidchelper.cpp b/src/xmlpatterns/schema/qxsdidchelper.cpp new file mode 100644 index 0000000..a7fa00d --- /dev/null +++ b/src/xmlpatterns/schema/qxsdidchelper.cpp @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdidchelper_p.h" + +#include "qderivedstring_p.h" +#include "qxsdschemahelper_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +FieldNode::FieldNode() +{ +} + +FieldNode::FieldNode(const QXmlItem &item, const QString &data, const SchemaType::Ptr &type) + : m_item(item) + , m_data(data) + , m_type(type) +{ +} + +bool FieldNode::isEmpty() const +{ + return m_item.isNull(); +} + +bool FieldNode::isEqualTo(const FieldNode &other, const NamePool::Ptr &namePool, const ReportContext::Ptr &context, const SourceLocationReflection *const reflection) const +{ + if (m_type != other.m_type) + return false; + + const DerivedString<TypeString>::Ptr string = DerivedString<TypeString>::fromLexical(namePool, m_data); + const DerivedString<TypeString>::Ptr otherString = DerivedString<TypeString>::fromLexical(namePool, other.m_data); + + return XsdSchemaHelper::constructAndCompare(string, AtomicComparator::OperatorEqual, otherString, m_type, context, reflection); +} + +QXmlItem FieldNode::item() const +{ + return m_item; +} + +TargetNode::TargetNode(const QXmlItem &item) + : m_item(item) +{ +} + +QXmlItem TargetNode::item() const +{ + return m_item; +} + +QVector<QXmlItem> TargetNode::fieldItems() const +{ + QVector<QXmlItem> items; + + for (int i = 0; i < m_fields.count(); ++i) + items.append(m_fields.at(i).item()); + + return items; +} + +int TargetNode::emptyFieldsCount() const +{ + int counter = 0; + for (int i = 0; i < m_fields.count(); ++i) { + if (m_fields.at(i).isEmpty()) + ++counter; + } + + return counter; +} + +bool TargetNode::fieldsAreEqual(const TargetNode &other, const NamePool::Ptr &namePool, const ReportContext::Ptr &context, const SourceLocationReflection *const reflection) const +{ + if (m_fields.count() != other.m_fields.count()) + return false; + + for (int i = 0; i < m_fields.count(); ++i) { + if (!m_fields.at(i).isEqualTo(other.m_fields.at(i), namePool, context, reflection)) + return false; + } + + return true; +} + +void TargetNode::addField(const QXmlItem &item, const QString &data, const SchemaType::Ptr &type) +{ + m_fields.append(FieldNode(item, data, type)); +} + +bool TargetNode::operator==(const TargetNode &other) const +{ + return (m_item.toNodeModelIndex() == other.m_item.toNodeModelIndex()); +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdidchelper_p.h b/src/xmlpatterns/schema/qxsdidchelper_p.h new file mode 100644 index 0000000..ee593b8 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdidchelper_p.h @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdIdcHelper_H +#define Patternist_XsdIdcHelper_H + +#include "qreportcontext_p.h" +#include "qschematype_p.h" + +#include <QtXmlPatterns/QXmlItem> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + + /** + * @short A helper class for validating identity constraints. + * + * This class represents a field node from the key-sequence as defined in + * the validation rules at http://www.w3.org/TR/xmlschema11-1/#d0e32243. + */ + class FieldNode + { + public: + /** + * Creates an empty field node. + */ + FieldNode(); + + /** + * Creates a field node that is bound to a xml node. + * + * @param item The xml node the field is bound to. + * @param data The string content of that field. + * @param type The type that is bound to that field. + */ + FieldNode(const QXmlItem &item, const QString &data, const SchemaType::Ptr &type); + + /** + * Returns whether this field is empty. + * + * A field can be empty, if the xpath expression selects an absent attribute + * or element. + */ + bool isEmpty() const; + + /** + * Returns whether this field is equal to the @p other field. + * + * Equal means that both have the same type and there content is equal in the + * types value space. + */ + bool isEqualTo(const FieldNode &other, const NamePool::Ptr &namePool, const ReportContext::Ptr &context, const SourceLocationReflection *const reflection) const; + + /** + * Returns the xml node item the field is bound to. + */ + QXmlItem item() const; + + private: + QXmlItem m_item; + QString m_data; + SchemaType::Ptr m_type; + }; + + /** + * @short A helper class for validating identity constraints. + * + * This class represents a target or qualified node from the target or qualified + * node set as defined in the validation rules at http://www.w3.org/TR/xmlschema11-1/#d0e32243. + * + * A target node is part of the qualified node set, if all of its fields are not empty. + */ + class TargetNode + { + public: + /** + * Defines a set of target nodes. + */ + typedef QSet<TargetNode> Set; + + /** + * Creates a new target node that is bound to the xml node @p item. + */ + explicit TargetNode(const QXmlItem &item); + + /** + * Returns the xml node item the target node is bound to. + */ + QXmlItem item() const; + + /** + * Returns all xml node items, the fields of that target node are bound to. + */ + QVector<QXmlItem> fieldItems() const; + + /** + * Returns the number of fields that are empty. + */ + int emptyFieldsCount() const; + + /** + * Returns whether the target node has the same fields as the @p other target node. + */ + bool fieldsAreEqual(const TargetNode &other, const NamePool::Ptr &namePool, const ReportContext::Ptr &context, const SourceLocationReflection *const reflection) const; + + /** + * Adds a new field to the target node with the given values. + */ + void addField(const QXmlItem &item, const QString &data, const SchemaType::Ptr &type); + + /** + * Returns whether the target node is equal to the @p other target node. + */ + bool operator==(const TargetNode &other) const; + + private: + QXmlItem m_item; + QVector<FieldNode> m_fields; + }; + + /** + * Creates a hash value for the given target @p node. + */ + inline uint qHash(const QPatternist::TargetNode &node) + { + return qHash(node.item().toNodeModelIndex()); + } +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdidentityconstraint.cpp b/src/xmlpatterns/schema/qxsdidentityconstraint.cpp new file mode 100644 index 0000000..9d0207c --- /dev/null +++ b/src/xmlpatterns/schema/qxsdidentityconstraint.cpp @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdidentityconstraint_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +void XsdIdentityConstraint::setCategory(Category category) +{ + m_category = category; +} + +XsdIdentityConstraint::Category XsdIdentityConstraint::category() const +{ + return m_category; +} + +void XsdIdentityConstraint::setSelector(const XsdXPathExpression::Ptr &selector) +{ + m_selector = selector; +} + +XsdXPathExpression::Ptr XsdIdentityConstraint::selector() const +{ + return m_selector; +} + +void XsdIdentityConstraint::setFields(const XsdXPathExpression::List &fields) +{ + m_fields = fields; +} + +void XsdIdentityConstraint::addField(const XsdXPathExpression::Ptr &field) +{ + m_fields.append(field); +} + +XsdXPathExpression::List XsdIdentityConstraint::fields() const +{ + return m_fields; +} + +void XsdIdentityConstraint::setReferencedKey(const XsdIdentityConstraint::Ptr &referencedKey) +{ + m_referencedKey = referencedKey; +} + +XsdIdentityConstraint::Ptr XsdIdentityConstraint::referencedKey() const +{ + return m_referencedKey; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdidentityconstraint_p.h b/src/xmlpatterns/schema/qxsdidentityconstraint_p.h new file mode 100644 index 0000000..b6bb3d0 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdidentityconstraint_p.h @@ -0,0 +1,173 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdIdentityConstraint_H +#define Patternist_XsdIdentityConstraint_H + +#include "qnamedschemacomponent_p.h" +#include "qxsdannotated_p.h" +#include "qxsdxpathexpression_p.h" + +#include <QtCore/QStringList> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short Represents a XSD identity constraint object. + * + * This class represents the <em>identity constraint</em> object of a XML schema as described + * <a href="http://www.w3.org/TR/xmlschema11-1/#cIdentity-constraint_Definitions">here</a>. + * + * It contains information from either a <em>key</em> object, a <em>keyref</em> object or an + * <em>unique</em> object. + * + * @see <a href="http://www.w3.org/Submission/2004/SUBM-xmlschema-api-20040309/xml-schema-api.html#Interface-XSIdentityConstraint">XML Schema API reference</a> + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdIdentityConstraint : public NamedSchemaComponent, public XsdAnnotated + { + public: + typedef QExplicitlySharedDataPointer<XsdIdentityConstraint> Ptr; + typedef QList<XsdIdentityConstraint::Ptr> List; + + /** + * Describes the <a href="http://www.w3.org/TR/xmlschema11-1/#icd-identity-constraint_category">category</a> of the identity constraint. + */ + enum Category + { + Key = 1, ///< The constraint is a key constraint + KeyReference, ///< The constraint is a keyref constraint + Unique ///< The constraint is an unique constraint + }; + + /** + * Sets the @p category of the identity constraint. + * + * @see Category + */ + void setCategory(Category category); + + /** + * Returns the category of the identity constraint. + */ + Category category() const; + + /** + * Sets the @p selector of the identity constraint. + * + * The selector is a restricted XPath 1.0 expression, + * that selects a set of nodes. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#icd-selector"></a> + */ + void setSelector(const XsdXPathExpression::Ptr &selector); + + /** + * Returns the selector of the identity constraint. + */ + XsdXPathExpression::Ptr selector() const; + + /** + * Sets the @p fields of the identity constraint. + * + * Each field is a restricted XPath 1.0 expression, + * that selects a set of nodes. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#icd-fields"></a> + */ + void setFields(const XsdXPathExpression::List &fields); + + /** + * Adds a new @p field to the identity constraint. + */ + void addField(const XsdXPathExpression::Ptr &field); + + /** + * Returns all fields of the identity constraint. + */ + XsdXPathExpression::List fields() const; + + /** + * Sets the referenced @p key of the identity constraint. + * + * The key points to a identity constraint of type Key or Unique. + * + * The identity constraint has only a referenced key if its + * type is KeyReference. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#icd-referenced_key"></a> + */ + void setReferencedKey(const XsdIdentityConstraint::Ptr &key); + + /** + * Returns the referenced key of the identity constraint or an empty + * pointer if its type is not KeyReference. + */ + XsdIdentityConstraint::Ptr referencedKey() const; + + private: + Category m_category; + XsdXPathExpression::Ptr m_selector; + XsdXPathExpression::List m_fields; + XsdIdentityConstraint::Ptr m_referencedKey; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdinstancereader.cpp b/src/xmlpatterns/schema/qxsdinstancereader.cpp new file mode 100644 index 0000000..9ff8d61 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdinstancereader.cpp @@ -0,0 +1,196 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdinstancereader_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +XsdInstanceReader::XsdInstanceReader(const QAbstractXmlNodeModel *model, const XsdSchemaContext::Ptr &context) + : m_context(context) + , m_model(model->iterate(model->root(QXmlNodeModelIndex()), QXmlNodeModelIndex::AxisChild)) +{ +} + +bool XsdInstanceReader::atEnd() const +{ + return (m_model.current() == AbstractXmlPullProvider::EndOfInput); +} + +void XsdInstanceReader::readNext() +{ + m_model.next(); + + if (m_model.current() == AbstractXmlPullProvider::StartElement) { + m_cachedAttributes = m_model.attributes(); + m_cachedAttributeItems = m_model.attributeItems(); + m_cachedSourceLocation = m_model.sourceLocation(); + m_cachedItem = QXmlItem(m_model.index()); + } +} + +bool XsdInstanceReader::isStartElement() const +{ + return (m_model.current() == AbstractXmlPullProvider::StartElement); +} + +bool XsdInstanceReader::isEndElement() const +{ + return (m_model.current() == AbstractXmlPullProvider::EndElement); +} + +bool XsdInstanceReader::hasChildText() const +{ + const QXmlNodeModelIndex index = m_model.index(); + QXmlNodeModelIndex::Iterator::Ptr it = index.model()->iterate(index, QXmlNodeModelIndex::AxisChild); + + QXmlNodeModelIndex currentIndex = it->next(); + while (!currentIndex.isNull()) { + if (currentIndex.kind() == QXmlNodeModelIndex::Text) + return true; + + currentIndex = it->next(); + } + + return false; +} + +bool XsdInstanceReader::hasChildElement() const +{ + const QXmlNodeModelIndex index = m_model.index(); + QXmlNodeModelIndex::Iterator::Ptr it = index.model()->iterate(index, QXmlNodeModelIndex::AxisChild); + + QXmlNodeModelIndex currentIndex = it->next(); + while (!currentIndex.isNull()) { + if (currentIndex.kind() == QXmlNodeModelIndex::Element) + return true; + + currentIndex = it->next(); + } + + return false; +} + +QXmlName XsdInstanceReader::name() const +{ + return m_model.name(); +} + +QXmlName XsdInstanceReader::convertToQName(const QString &name) const +{ + const int pos = name.indexOf(QLatin1Char(':')); + + QXmlName::PrefixCode prefixCode = 0; + QXmlName::NamespaceCode namespaceCode; + QXmlName::LocalNameCode localNameCode; + if (pos != -1) { + prefixCode = m_context->namePool()->allocatePrefix(name.left(pos)); + namespaceCode = m_cachedItem.toNodeModelIndex().namespaceForPrefix(prefixCode); + localNameCode = m_context->namePool()->allocateLocalName(name.mid(pos + 1)); + } else { + prefixCode = StandardPrefixes::empty; + namespaceCode = m_cachedItem.toNodeModelIndex().namespaceForPrefix(prefixCode); + if (namespaceCode == -1) + namespaceCode = StandardNamespaces::empty; + localNameCode = m_context->namePool()->allocateLocalName(name); + } + + return QXmlName(namespaceCode, localNameCode, prefixCode); +} + +bool XsdInstanceReader::hasAttribute(const QXmlName &name) const +{ + return m_cachedAttributes.contains(name); +} + +QString XsdInstanceReader::attribute(const QXmlName &name) const +{ + Q_ASSERT(m_cachedAttributes.contains(name)); + + return m_cachedAttributes.value(name); +} + +QSet<QXmlName> XsdInstanceReader::attributeNames() const +{ + return m_cachedAttributes.keys().toSet(); +} + +QString XsdInstanceReader::text() const +{ + const QXmlNodeModelIndex index = m_model.index(); + QXmlNodeModelIndex::Iterator::Ptr it = index.model()->iterate(index, QXmlNodeModelIndex::AxisChild); + + QString result; + + QXmlNodeModelIndex currentIndex = it->next(); + while (!currentIndex.isNull()) { + if (currentIndex.kind() == QXmlNodeModelIndex::Text) { + result.append(Item(currentIndex).stringValue()); + } + + currentIndex = it->next(); + } + + return result; +} + +QXmlItem XsdInstanceReader::item() const +{ + return m_cachedItem; +} + +QXmlItem XsdInstanceReader::attributeItem(const QXmlName &name) const +{ + return m_cachedAttributeItems.value(name); +} + +QSourceLocation XsdInstanceReader::sourceLocation() const +{ + return m_cachedSourceLocation; +} + +QVector<QXmlName> XsdInstanceReader::namespaceBindings(const QXmlNodeModelIndex &index) const +{ + return index.namespaceBindings(); +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdinstancereader_p.h b/src/xmlpatterns/schema/qxsdinstancereader_p.h new file mode 100644 index 0000000..af189e3 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdinstancereader_p.h @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdInstanceReader_H +#define Patternist_XsdInstanceReader_H + +#include "qabstractxmlnodemodel.h" +#include "qpullbridge_p.h" +#include "qxsdschemacontext_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short The schema instance reader. + * + * This class reads in a xml instance document from a QAbstractXmlNodeModel + * and provides a QXmlStreamReader like interface with some additional context + * information. + * + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdInstanceReader + { + public: + typedef QExplicitlySharedDataPointer<XsdInstanceReader> Ptr; + + /** + * Creates a new instance reader that will read the data from + * the given @p model. + * + * @param model The model the data are read from. + * @param context The context that is used for error reporting etc. + */ + XsdInstanceReader(const QAbstractXmlNodeModel *model, const XsdSchemaContext::Ptr &context); + + protected: + /** + * Returns @c true if the end of the document is reached, @c false otherwise. + */ + bool atEnd() const; + + /** + * Reads the next node from the document. + */ + void readNext(); + + /** + * Returns whether the current node is a start element. + */ + bool isStartElement() const; + + /** + * Returns whether the current node is an end element. + */ + bool isEndElement() const; + + /** + * Returns whether the current node has a text node among its children. + */ + bool hasChildText() const; + + /** + * Returns whether the current node has an element node among its children. + */ + bool hasChildElement() const; + + /** + * Returns the name of the current node. + */ + QXmlName name() const; + + /** + * Returns whether the current node has an attribute with the given @p name. + */ + bool hasAttribute(const QXmlName &name) const; + + /** + * Returns the attribute with the given @p name of the current node. + */ + QString attribute(const QXmlName &name) const; + + /** + * Returns the list of attribute names of the current node. + */ + QSet<QXmlName> attributeNames() const; + + /** + * Returns the concatenated text of all direct child text nodes. + */ + QString text() const; + + /** + * Converts a qualified name into a QXmlName according to the namespace + * mappings of the current node. + */ + QXmlName convertToQName(const QString &name) const; + + /** + * Returns a source location object for the current position. + */ + QSourceLocation sourceLocation() const; + + /** + * Returns the QXmlItem for the current position. + */ + QXmlItem item() const; + + /** + * Returns the QXmlItem for the attribute with the given @p name at the current position. + */ + QXmlItem attributeItem(const QXmlName &name) const; + + /** + * Returns the namespace bindings for the given node model @p index. + */ + QVector<QXmlName> namespaceBindings(const QXmlNodeModelIndex &index) const; + + /** + * The shared schema context. + */ + XsdSchemaContext::Ptr m_context; + + private: + PullBridge m_model; + QHash<QXmlName, QString> m_cachedAttributes; + QHash<QXmlName, QXmlItem> m_cachedAttributeItems; + QSourceLocation m_cachedSourceLocation; + QXmlItem m_cachedItem; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdmodelgroup.cpp b/src/xmlpatterns/schema/qxsdmodelgroup.cpp new file mode 100644 index 0000000..ca7eb42 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdmodelgroup.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdmodelgroup_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +XsdModelGroup::XsdModelGroup() + : m_compositor(SequenceCompositor) +{ +} + +bool XsdModelGroup::isModelGroup() const +{ + return true; +} + +void XsdModelGroup::setCompositor(ModelCompositor compositor) +{ + m_compositor = compositor; +} + +XsdModelGroup::ModelCompositor XsdModelGroup::compositor() const +{ + return m_compositor; +} + +void XsdModelGroup::setParticles(const XsdParticle::List &particles) +{ + m_particles = particles; +} + +XsdParticle::List XsdModelGroup::particles() const +{ + return m_particles; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdmodelgroup_p.h b/src/xmlpatterns/schema/qxsdmodelgroup_p.h new file mode 100644 index 0000000..f01d5bf --- /dev/null +++ b/src/xmlpatterns/schema/qxsdmodelgroup_p.h @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdModelGroup_H +#define Patternist_XsdModelGroup_H + +#include "qxsdparticle_p.h" +#include "qxsdterm_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +template<typename N> class QList; + +namespace QPatternist +{ + /** + * @short Represents a XSD model group object. + * + * This class represents the <em>model group</em> object of a XML schema as described + * <a href="http://www.w3.org/TR/xmlschema11-1/#cModel_Group_Definitions">here</a>. + * + * It contains information from either a <em>sequence</em> object, a <em>choice</em> object or an + * <em>all</em> object. + * + * @see <a href="http://www.w3.org/Submission/2004/SUBM-xmlschema-api-20040309/xml-schema-api.html#Interface-XSModelGroup">XML Schema API reference</a> + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdModelGroup : public XsdTerm + { + public: + typedef QExplicitlySharedDataPointer<XsdModelGroup> Ptr; + typedef QList<XsdModelGroup::Ptr> List; + + /** + * Describes the <a href="http://www.w3.org/TR/xmlschema11-1/#mg-compositor">compositor</a> of the model group. + */ + enum ModelCompositor + { + SequenceCompositor, ///< The model group is a sequence. + ChoiceCompositor, ///< The model group is a choice. + AllCompositor ///< The model group contains elements only. + }; + + /** + * Creates a new model group object. + */ + XsdModelGroup(); + + /** + * Returns always @c true, used to avoid dynamic casts. + */ + virtual bool isModelGroup() const; + + /** + * Sets the @p compositor of the model group. + * + * @see ModelCompositor + */ + void setCompositor(ModelCompositor compositor); + + /** + * Returns the compositor of the model group. + */ + ModelCompositor compositor() const; + + /** + * Sets the list of @p particles of the model group. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#mg-particles">Particles Definition</a> + */ + void setParticles(const XsdParticle::List &particles); + + /** + * Returns the list of particles of the model group. + */ + XsdParticle::List particles() const; + + private: + ModelCompositor m_compositor; + XsdParticle::List m_particles; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdnotation.cpp b/src/xmlpatterns/schema/qxsdnotation.cpp new file mode 100644 index 0000000..59697d7 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdnotation.cpp @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdnotation_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +void XsdNotation::setPublicId(const DerivedString<TypeToken>::Ptr &id) +{ + m_publicId = id; +} + +DerivedString<TypeToken>::Ptr XsdNotation::publicId() const +{ + return m_publicId; +} + +void XsdNotation::setSystemId(const AnyURI::Ptr &id) +{ + m_systemId = id; +} + +AnyURI::Ptr XsdNotation::systemId() const +{ + return m_systemId; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdnotation_p.h b/src/xmlpatterns/schema/qxsdnotation_p.h new file mode 100644 index 0000000..1ad2c47 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdnotation_p.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdNotation_H +#define Patternist_XsdNotation_H + +#include "qanyuri_p.h" +#include "qderivedstring_p.h" +#include "qnamedschemacomponent_p.h" +#include "qxsdannotated_p.h" + +#include <QtCore/QList> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short Represents a XSD notation object, which should not + * be confused with the atomic type @c xs:NOTATION. + * + * This class represents the <em>notation</em> object of a XML schema as described + * <a href="http://www.w3.org/TR/xmlschema11-1/#cNotation_Declarations">here</a>. + * + * @see <a href="http://www.w3.org/Submission/2004/SUBM-xmlschema-api-20040309/xml-schema-api.html#XS-NotationDecl">XML Schema API reference</a> + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdNotation : public NamedSchemaComponent, public XsdAnnotated + { + public: + typedef QExplicitlySharedDataPointer<XsdNotation> Ptr; + typedef QList<XsdNotation::Ptr> List; + + /** + * Sets the public @p identifier of the notation. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#nd-public_identifier">Public Identifier Definition</a> + */ + void setPublicId(const DerivedString<TypeToken>::Ptr &identifier); + + /** + * Returns the public identifier of the notation. + */ + DerivedString<TypeToken>::Ptr publicId() const; + + /** + * Sets the system @p identifier of the notation. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#nd-system_identifier">System Identifier Definition</a> + */ + void setSystemId(const AnyURI::Ptr &identifier); + + /** + * Returns the system identifier of the notation. + */ + AnyURI::Ptr systemId() const; + + private: + DerivedString<TypeToken>::Ptr m_publicId; + AnyURI::Ptr m_systemId; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdparticle.cpp b/src/xmlpatterns/schema/qxsdparticle.cpp new file mode 100644 index 0000000..0e58bf6 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdparticle.cpp @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdparticle_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +XsdParticle::XsdParticle() + : m_minimumOccurs(1) + , m_maximumOccurs(1) + , m_maximumOccursUnbounded(false) +{ +} + +void XsdParticle::setMinimumOccurs(unsigned int occurs) +{ + m_minimumOccurs = occurs; +} + +unsigned int XsdParticle::minimumOccurs() const +{ + return m_minimumOccurs; +} + +void XsdParticle::setMaximumOccurs(unsigned int occurs) +{ + m_maximumOccurs = occurs; +} + +unsigned int XsdParticle::maximumOccurs() const +{ + return m_maximumOccurs; +} + +void XsdParticle::setMaximumOccursUnbounded(bool unbounded) +{ + m_maximumOccursUnbounded = unbounded; +} + +bool XsdParticle::maximumOccursUnbounded() const +{ + return m_maximumOccursUnbounded; +} + +void XsdParticle::setTerm(const XsdTerm::Ptr &term) +{ + m_term = term; +} + +XsdTerm::Ptr XsdParticle::term() const +{ + return m_term; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdparticle_p.h b/src/xmlpatterns/schema/qxsdparticle_p.h new file mode 100644 index 0000000..a183192 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdparticle_p.h @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdParticle_H +#define Patternist_XsdParticle_H + +#include "qnamedschemacomponent_p.h" +#include "qxsdterm_p.h" + +#include <QtCore/QList> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short Represents a XSD particle object. + * + * This class represents the <em>particle</em> object of a XML schema as described + * <a href="http://www.w3.org/TR/xmlschema11-1/#cParticles">here</a>. + * + * It contains information about the number of occurrence and a reference to + * either an <em>element</em> object, a <em>group</em> object or an <em>any</em> object. + * + * @see <a href="http://www.w3.org/Submission/2004/SUBM-xmlschema-api-20040309/xml-schema-api.html#Interface-XSParticle">XML Schema API reference</a> + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdParticle : public NamedSchemaComponent + { + public: + typedef QExplicitlySharedDataPointer<XsdParticle> Ptr; + typedef QList<XsdParticle::Ptr> List; + + /** + * Creates a new particle object. + */ + XsdParticle(); + + /** + * Sets the minimum @p occurrence of the particle. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#p-min_occurs">Minimum Occurrence Definition</a> + */ + void setMinimumOccurs(unsigned int occurrence); + + /** + * Returns the minimum occurrence of the particle. + */ + unsigned int minimumOccurs() const; + + /** + * Sets the maximum @p occurrence of the particle. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#p-max_occurs">Maximum Occurrence Definition</a> + */ + void setMaximumOccurs(unsigned int occurrence); + + /** + * Returns the maximum occurrence of the particle. + * + * @note This value has only a meaning if maximumOccursUnbounded is @c false. + */ + unsigned int maximumOccurs() const; + + /** + * Sets whether the maximum occurrence of the particle is unbounded. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#p-max_occurs">Maximum Occurrence Definition</a> + */ + void setMaximumOccursUnbounded(bool unbounded); + + /** + * Returns whether the maximum occurrence of the particle is unbounded. + */ + bool maximumOccursUnbounded() const; + + /** + * Sets the @p term of the particle. + * + * The term can be an element, a model group or an element wildcard. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#p-term">Term Definition</a> + */ + void setTerm(const XsdTerm::Ptr &term); + + /** + * Returns the term of the particle. + */ + XsdTerm::Ptr term() const; + + private: + unsigned int m_minimumOccurs; + unsigned int m_maximumOccurs; + bool m_maximumOccursUnbounded; + XsdTerm::Ptr m_term; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdparticlechecker.cpp b/src/xmlpatterns/schema/qxsdparticlechecker.cpp new file mode 100644 index 0000000..f7fa442 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdparticlechecker.cpp @@ -0,0 +1,540 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdparticlechecker_p.h" + +#include "qxsdelement_p.h" +#include "qxsdmodelgroup_p.h" +#include "qxsdschemahelper_p.h" +#include "qxsdstatemachine_p.h" +#include "qxsdstatemachinebuilder_p.h" +#include "qxsdtypechecker_p.h" + +#include <QtCore/QFile> + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +namespace QPatternist +{ + /** + * This template specialization is picked up by XsdStateMachine and allows us + * to print nice edge labels. + */ + template <> + QString XsdStateMachine<XsdTerm::Ptr>::transitionTypeToString(XsdTerm::Ptr term) const + { + if (!term) + return QLatin1String("(empty)"); + + if (term->isElement()) { + return XsdElement::Ptr(term)->displayName(m_namePool); + } else if (term->isWildcard()) { + const XsdWildcard::Ptr wildcard(term); + return QLatin1String("(wildcard)"); + } else { + return QString(); + } + } +} + +/** + * This method is used by the isUPAConform method to check whether @p term and @p otherTerm + * are the same resp. match each other. + */ +static bool termMatches(const XsdTerm::Ptr &term, const XsdTerm::Ptr &otherTerm, const NamePool::Ptr &namePool) +{ + if (term->isElement()) { + const XsdElement::Ptr element(term); + + if (otherTerm->isElement()) { + // both, the term and the other term are elements + + const XsdElement::Ptr otherElement(otherTerm); + + // if they have the same name they match + if (element->name(namePool) == otherElement->name(namePool)) + return true; + + } else if (otherTerm->isWildcard()) { + // the term is an element and the other term a wildcard + + const XsdWildcard::Ptr wildcard(otherTerm); + + // wildcards using XsdWildcard::absentNamespace, so we have to fix that here + QXmlName name = element->name(namePool); + if (name.namespaceURI() == StandardNamespaces::empty) + name.setNamespaceURI(namePool->allocateNamespace(XsdWildcard::absentNamespace())); + + // if the wildcards namespace constraint allows the elements name, they match + if (XsdSchemaHelper::wildcardAllowsExpandedName(name, wildcard, namePool)) + return true; + } + } else if (term->isWildcard()) { + const XsdWildcard::Ptr wildcard(term); + + if (otherTerm->isElement()) { + // the term is a wildcard and the other term an element + + const XsdElement::Ptr otherElement(otherTerm); + + // wildcards using XsdWildcard::absentNamespace, so we have to fix that here + QXmlName name = otherElement->name(namePool); + if (name.namespaceURI() == StandardNamespaces::empty) + name.setNamespaceURI(namePool->allocateNamespace(XsdWildcard::absentNamespace())); + + // if the wildcards namespace constraint allows the elements name, they match + if (XsdSchemaHelper::wildcardAllowsExpandedName(name, wildcard, namePool)) + return true; + + } else if (otherTerm->isWildcard()) { + // both, the term and the other term are wildcards + + const XsdWildcard::Ptr otherWildcard(otherTerm); + + // check if the range of the wildcard overlaps. + const XsdWildcard::Ptr intersectionWildcard = XsdSchemaHelper::wildcardIntersection(wildcard, otherWildcard); + if (!intersectionWildcard || + (intersectionWildcard && !(intersectionWildcard->namespaceConstraint()->variety() != XsdWildcard::NamespaceConstraint::Not && intersectionWildcard->namespaceConstraint()->namespaces().isEmpty()))) + return true; + } + } + + return false; +} + +/** + * This method is used by the subsumes algorithm to check whether the @p derivedTerm is validly derived from the @p baseTerm. + * + * @param baseTerm The term of the base component (type or group). + * @param derivedTerm The term of the derived component (type or group). + * @param particles A hash to map the passed base and derived term to the particles they belong to. + * @param context The schema context. + * @param errorMsg The error message in the case that an error occurs. + */ +static bool derivedTermValid(const XsdTerm::Ptr &baseTerm, const XsdTerm::Ptr &derivedTerm, const QHash<XsdTerm::Ptr, XsdParticle::Ptr> &particles, const XsdSchemaContext::Ptr &context, QString &errorMsg) +{ + const NamePool::Ptr namePool(context->namePool()); + + // find the particles where the base and derived term belongs to + const XsdParticle::Ptr baseParticle = particles.value(baseTerm); + const XsdParticle::Ptr derivedParticle = particles.value(derivedTerm); + + // check that an empty particle can not be derived from a non-empty particle + if (derivedParticle && baseParticle) { + if (XsdSchemaHelper::isParticleEmptiable(derivedParticle) && !XsdSchemaHelper::isParticleEmptiable(baseParticle)) { + errorMsg = QtXmlPatterns::tr("empty particle cannot be derived from non-empty particle"); + return false; + } + } + + if (baseTerm->isElement()) { + const XsdElement::Ptr element(baseTerm); + + if (derivedTerm->isElement()) { + // if both terms are elements + + const XsdElement::Ptr derivedElement(derivedTerm); + + // check names are equal + if (element->name(namePool) != derivedElement->name(namePool)) { + errorMsg = QtXmlPatterns::tr("derived particle is missing element %1").arg(formatKeyword(element->displayName(namePool))); + return false; + } + + // check value constraints are equal (if available) + if (element->valueConstraint() && element->valueConstraint()->variety() == XsdElement::ValueConstraint::Fixed) { + if (!derivedElement->valueConstraint()) { + errorMsg = QtXmlPatterns::tr("derived element %1 is missing value constraint as defined in base particle").arg(formatKeyword(derivedElement->displayName(namePool))); + return false; + } + + if (derivedElement->valueConstraint()->variety() != XsdElement::ValueConstraint::Fixed) { + errorMsg = QtXmlPatterns::tr("derived element %1 has weaker value constraint than base particle").arg(formatKeyword(derivedElement->displayName(namePool))); + return false; + } + + const QSourceLocation dummyLocation(QUrl(QLatin1String("http://dummy.org")), 1, 1); + const XsdTypeChecker checker(context, QVector<QXmlName>(), dummyLocation); + if (!checker.valuesAreEqual(element->valueConstraint()->value(), derivedElement->valueConstraint()->value(), derivedElement->type())) { + errorMsg = QtXmlPatterns::tr("fixed value constraint of element %1 differs from value constraint in base particle").arg(formatKeyword(derivedElement->displayName(namePool))); + return false; + } + } + + // check that a derived element can not be nillable if the base element is not nillable + if (!element->isNillable() && derivedElement->isNillable()) { + errorMsg = QtXmlPatterns::tr("derived element %1 cannot be nillable as base element is not nillable").arg(formatKeyword(derivedElement->displayName(namePool))); + return false; + } + + // check that the constraints of the derived element are more strict then the constraints of the base element + const XsdElement::BlockingConstraints baseConstraints = element->disallowedSubstitutions(); + const XsdElement::BlockingConstraints derivedConstraints = derivedElement->disallowedSubstitutions(); + if (((baseConstraints & XsdElement::RestrictionConstraint) && !(derivedConstraints & XsdElement::RestrictionConstraint)) || + ((baseConstraints & XsdElement::ExtensionConstraint) && !(derivedConstraints & XsdElement::ExtensionConstraint)) || + ((baseConstraints & XsdElement::SubstitutionConstraint) && !(derivedConstraints & XsdElement::SubstitutionConstraint))) { + errorMsg = QtXmlPatterns::tr("block constraints of derived element %1 must not be more weaker than in the base element").arg(formatKeyword(derivedElement->displayName(namePool))); + return false; + } + + // if the type of both elements is the same we can stop testing here + if (element->type()->name(namePool) == derivedElement->type()->name(namePool)) + return true; + + // check that the type of the derived element can validly derived from the type of the base element + if (derivedElement->type()->isSimpleType()) { + if (!XsdSchemaHelper::isSimpleDerivationOk(derivedElement->type(), element->type(), SchemaType::DerivationConstraints())) { + errorMsg = QtXmlPatterns::tr("simple type of derived element %1 cannot be validly derived from base element").arg(formatKeyword(derivedElement->displayName(namePool))); + return false; + } + } else if (derivedElement->type()->isComplexType()) { + if (!XsdSchemaHelper::isComplexDerivationOk(derivedElement->type(), element->type(), SchemaType::DerivationConstraints())) { + errorMsg = QtXmlPatterns::tr("complex type of derived element %1 cannot be validly derived from base element").arg(formatKeyword(derivedElement->displayName(namePool))); + return false; + } + } + + // if both, derived and base element, have a complex type that contains a particle itself, apply the subsumes algorithm + // recursive on their particles + if (element->type()->isComplexType() && derivedElement->type()->isComplexType()) { + if (element->type()->isDefinedBySchema() && derivedElement->type()->isDefinedBySchema()) { + const XsdComplexType::Ptr baseType(element->type()); + const XsdComplexType::Ptr derivedType(derivedElement->type()); + if ((baseType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly || + baseType->contentType()->variety() == XsdComplexType::ContentType::Mixed) && + (derivedType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly || + derivedType->contentType()->variety() == XsdComplexType::ContentType::Mixed)) { + + return XsdParticleChecker::subsumes(baseType->contentType()->particle(), derivedType->contentType()->particle(), context, errorMsg); + } + } + } + + return true; + } else if (derivedTerm->isWildcard()) { + // derive a wildcard from an element is not allowed + errorMsg = QtXmlPatterns::tr("element %1 is missing in derived particle").arg(formatKeyword(element->displayName(namePool))); + return false; + } + } else if (baseTerm->isWildcard()) { + const XsdWildcard::Ptr wildcard(baseTerm); + + if (derivedTerm->isElement()) { + // the base term is a wildcard and derived term an element + + const XsdElement::Ptr derivedElement(derivedTerm); + + // wildcards using XsdWildcard::absentNamespace, so we have to fix that here + QXmlName name = derivedElement->name(namePool); + if (name.namespaceURI() == StandardNamespaces::empty) + name.setNamespaceURI(namePool->allocateNamespace(XsdWildcard::absentNamespace())); + + // check that name of the element is allowed by the wildcards namespace constraint + if (!XsdSchemaHelper::wildcardAllowsExpandedName(name, wildcard, namePool)) { + errorMsg = QtXmlPatterns::tr("element %1 does not match namespace constraint of wildcard in base particle").arg(formatKeyword(derivedElement->displayName(namePool))); + return false; + } + + } else if (derivedTerm->isWildcard()) { + // both, derived and base term are wildcards + + const XsdWildcard::Ptr derivedWildcard(derivedTerm); + + // check that the derived wildcard is a valid subset of the base wildcard + if (!XsdSchemaHelper::isWildcardSubset(derivedWildcard, wildcard)) { + errorMsg = QtXmlPatterns::tr("wildcard in derived particle is not a valid subset of wildcard in base particle"); + return false; + } + + if (!XsdSchemaHelper::checkWildcardProcessContents(wildcard, derivedWildcard)) { + errorMsg = QtXmlPatterns::tr("processContent of wildcard in derived particle is weaker than wildcard in base particle"); + return false; + } + } + + return true; + } + + return false; +} + +typedef QHash<QXmlName, XsdElement::Ptr> ElementHash; + +/** + * Internal helper method that checks if the given @p particle contains an element with the + * same name and type twice. + */ +static bool hasDuplicatedElementsInternal(const XsdParticle::Ptr &particle, const NamePool::Ptr &namePool, ElementHash &hash, XsdElement::Ptr &conflictingElement) +{ + const XsdTerm::Ptr term = particle->term(); + if (term->isElement()) { + const XsdElement::Ptr mainElement(term); + XsdElement::List substGroups = mainElement->substitutionGroups(); + if (substGroups.isEmpty()) + substGroups << mainElement; + + for (int i = 0; i < substGroups.count(); ++i) { + const XsdElement::Ptr element = substGroups.at(i); + if (hash.contains(element->name(namePool))) { + if (element->type()->name(namePool) != hash.value(element->name(namePool))->type()->name(namePool)) { + conflictingElement = element; + return true; + } + } else { + hash.insert(element->name(namePool), element); + } + } + } else if (term->isModelGroup()) { + const XsdModelGroup::Ptr group(term); + const XsdParticle::List particles = group->particles(); + for (int i = 0; i < particles.count(); ++i) { + if (hasDuplicatedElementsInternal(particles.at(i), namePool, hash, conflictingElement)) + return true; + } + } + + return false; +} + +bool XsdParticleChecker::hasDuplicatedElements(const XsdParticle::Ptr &particle, const NamePool::Ptr &namePool, XsdElement::Ptr &conflictingElement) +{ + ElementHash hash; + return hasDuplicatedElementsInternal(particle, namePool, hash, conflictingElement); +} + +bool XsdParticleChecker::isUPAConform(const XsdParticle::Ptr &particle, const NamePool::Ptr &namePool) +{ + /** + * The algorithm is implemented like described in http://www.ltg.ed.ac.uk/~ht/XML_Europe_2003.html#S2.2 + */ + + // create a state machine for the given particle + XsdStateMachine<XsdTerm::Ptr> stateMachine(namePool); + + XsdStateMachineBuilder builder(&stateMachine, namePool); + const XsdStateMachine<XsdTerm::Ptr>::StateId endState = builder.reset(); + const XsdStateMachine<XsdTerm::Ptr>::StateId startState = builder.buildParticle(particle, endState); + builder.addStartState(startState); + +/* + static int counter = 0; + { + QFile file(QString("/tmp/file_upa%1.dot").arg(counter)); + file.open(QIODevice::WriteOnly); + stateMachine.outputGraph(&file, "Base"); + file.close(); + } + ::system(QString("dot -Tpng /tmp/file_upa%1.dot -o/tmp/file_upa%1.png").arg(counter).toLatin1().data()); +*/ + const XsdStateMachine<XsdTerm::Ptr> dfa = stateMachine.toDFA(); +/* + { + QFile file(QString("/tmp/file_upa%1dfa.dot").arg(counter)); + file.open(QIODevice::WriteOnly); + dfa.outputGraph(&file, "Base"); + file.close(); + } + ::system(QString("dot -Tpng /tmp/file_upa%1dfa.dot -o/tmp/file_upa%1dfa.png").arg(counter).toLatin1().data()); +*/ + const QHash<XsdStateMachine<XsdTerm::Ptr>::StateId, XsdStateMachine<XsdTerm::Ptr>::StateType> states = dfa.states(); + const QHash<XsdStateMachine<XsdTerm::Ptr>::StateId, QHash<XsdTerm::Ptr, QVector<XsdStateMachine<XsdTerm::Ptr>::StateId> > > transitions = dfa.transitions(); + + // the basic idea of that algorithm is to iterate over all states of that machine and check that no two edges + // that match on the same term leave a state, so for a given term it should always be obvious which edge to take + QHashIterator<XsdStateMachine<XsdTerm::Ptr>::StateId, XsdStateMachine<XsdTerm::Ptr>::StateType> stateIt(states); + while (stateIt.hasNext()) { // iterate over all states + stateIt.next(); + + // fetch all transitions the current state allows + const QHash<XsdTerm::Ptr, QVector<XsdStateMachine<XsdTerm::Ptr>::StateId> > currentTransitions = transitions.value(stateIt.key()); + QHashIterator<XsdTerm::Ptr, QVector<XsdStateMachine<XsdTerm::Ptr>::StateId> > transitionIt(currentTransitions); + while (transitionIt.hasNext()) { // iterate over all transitions + transitionIt.next(); + + if (transitionIt.value().size() > 1) { + // we have one state with two edges leaving it, that means + // the XsdTerm::Ptr exists twice, that is an error + return false; + } + + QHashIterator<XsdTerm::Ptr, QVector<XsdStateMachine<XsdTerm::Ptr>::StateId> > innerTransitionIt(currentTransitions); + while (innerTransitionIt.hasNext()) { // iterate over all transitions again, as we have to compare all transitions with all + innerTransitionIt.next(); + + if (transitionIt.key() == innerTransitionIt.key()) // do no compare with ourself + continue; + + // use the helper method termMatches to check if both term matches + if (termMatches(transitionIt.key(), innerTransitionIt.key(), namePool)) + return false; + } + } + } + + return true; +} + +bool XsdParticleChecker::subsumes(const XsdParticle::Ptr &particle, const XsdParticle::Ptr &derivedParticle, const XsdSchemaContext::Ptr &context, QString &errorMsg) +{ + /** + * The algorithm is implemented like described in http://www.ltg.ed.ac.uk/~ht/XML_Europe_2003.html#S2.3 + */ + + const NamePool::Ptr namePool(context->namePool()); + + XsdStateMachine<XsdTerm::Ptr> baseStateMachine(namePool); + XsdStateMachine<XsdTerm::Ptr> derivedStateMachine(namePool); + + // build up state machines for both particles + { + XsdStateMachineBuilder builder(&baseStateMachine, namePool); + const XsdStateMachine<XsdTerm::Ptr>::StateId endState = builder.reset(); + const XsdStateMachine<XsdTerm::Ptr>::StateId startState = builder.buildParticle(particle, endState); + builder.addStartState(startState); + + baseStateMachine = baseStateMachine.toDFA(); + } + { + XsdStateMachineBuilder builder(&derivedStateMachine, namePool); + const XsdStateMachine<XsdTerm::Ptr>::StateId endState = builder.reset(); + const XsdStateMachine<XsdTerm::Ptr>::StateId startState = builder.buildParticle(derivedParticle, endState); + builder.addStartState(startState); + + derivedStateMachine = derivedStateMachine.toDFA(); + } + + QHash<XsdTerm::Ptr, XsdParticle::Ptr> particlesHash = XsdStateMachineBuilder::particleLookupMap(particle); + particlesHash.unite(XsdStateMachineBuilder::particleLookupMap(derivedParticle)); + +/* + static int counter = 0; + { + QFile file(QString("/tmp/file_base%1.dot").arg(counter)); + file.open(QIODevice::WriteOnly); + baseStateMachine.outputGraph(&file, QLatin1String("Base")); + file.close(); + } + { + QFile file(QString("/tmp/file_derived%1.dot").arg(counter)); + file.open(QIODevice::WriteOnly); + derivedStateMachine.outputGraph(&file, QLatin1String("Base")); + file.close(); + } + ::system(QString("dot -Tpng /tmp/file_base%1.dot -o/tmp/file_base%1.png").arg(counter).toLatin1().data()); + ::system(QString("dot -Tpng /tmp/file_derived%1.dot -o/tmp/file_derived%1.png").arg(counter).toLatin1().data()); +*/ + + const XsdStateMachine<XsdTerm::Ptr>::StateId baseStartState = baseStateMachine.startState(); + const QHash<XsdStateMachine<XsdTerm::Ptr>::StateId, XsdStateMachine<XsdTerm::Ptr>::StateType> baseStates = baseStateMachine.states(); + const QHash<XsdStateMachine<XsdTerm::Ptr>::StateId, QHash<XsdTerm::Ptr, QVector<XsdStateMachine<XsdTerm::Ptr>::StateId> > > baseTransitions = baseStateMachine.transitions(); + + const XsdStateMachine<XsdTerm::Ptr>::StateId derivedStartState = derivedStateMachine.startState(); + const QHash<XsdStateMachine<XsdTerm::Ptr>::StateId, XsdStateMachine<XsdTerm::Ptr>::StateType> derivedStates = derivedStateMachine.states(); + const QHash<XsdStateMachine<XsdTerm::Ptr>::StateId, QHash<XsdTerm::Ptr, QVector<XsdStateMachine<XsdTerm::Ptr>::StateId> > > derivedTransitions = derivedStateMachine.transitions(); + + // @see http://www.ltg.ed.ac.uk/~ht/XML_Europe_2003.html#S2.3.1 + + // define working set + QList<QPair<XsdStateMachine<XsdTerm::Ptr>::StateId, XsdStateMachine<XsdTerm::Ptr>::StateId> > workSet; + QList<QPair<XsdStateMachine<XsdTerm::Ptr>::StateId, XsdStateMachine<XsdTerm::Ptr>::StateId> > processedSet; + + // 1) fill working set initially with start states + workSet.append(qMakePair<XsdStateMachine<XsdTerm::Ptr>::StateId, XsdStateMachine<XsdTerm::Ptr>::StateId>(baseStartState, derivedStartState)); + processedSet.append(qMakePair<XsdStateMachine<XsdTerm::Ptr>::StateId, XsdStateMachine<XsdTerm::Ptr>::StateId>(baseStartState, derivedStartState)); + + while (!workSet.isEmpty()) { // while there are state sets to process + + // 3) dequeue on state set + const QPair<XsdStateMachine<XsdTerm::Ptr>::StateId, XsdStateMachine<XsdTerm::Ptr>::StateId> set = workSet.takeFirst(); + + const QHash<XsdTerm::Ptr, QVector<XsdStateMachine<XsdTerm::Ptr>::StateId> > derivedTrans = derivedTransitions.value(set.second); + QHashIterator<XsdTerm::Ptr, QVector<XsdStateMachine<XsdTerm::Ptr>::StateId> > derivedIt(derivedTrans); + + const QHash<XsdTerm::Ptr, QVector<XsdStateMachine<XsdTerm::Ptr>::StateId> > baseTrans = baseTransitions.value(set.first); + + while (derivedIt.hasNext()) { + derivedIt.next(); + + bool found = false; + QHashIterator<XsdTerm::Ptr, QVector<XsdStateMachine<XsdTerm::Ptr>::StateId> > baseIt(baseTrans); + while (baseIt.hasNext()) { + baseIt.next(); + if (derivedTermValid(baseIt.key(), derivedIt.key(), particlesHash, context, errorMsg)) { + const QPair<XsdStateMachine<XsdTerm::Ptr>::StateId, XsdStateMachine<XsdTerm::Ptr>::StateId> endSet = + qMakePair<XsdStateMachine<XsdTerm::Ptr>::StateId, XsdStateMachine<XsdTerm::Ptr>::StateId>(baseIt.value().first(), derivedIt.value().first()); + if (!processedSet.contains(endSet) && !workSet.contains(endSet)) { + workSet.append(endSet); + processedSet.append(endSet); + } + + found = true; + } + } + + if (!found) { + return false; + } + } + } + + // 5) + QHashIterator<XsdStateMachine<XsdTerm::Ptr>::StateId, XsdStateMachine<XsdTerm::Ptr>::StateType> it(derivedStates); + while (it.hasNext()) { + it.next(); + + if (it.value() == XsdStateMachine<XsdTerm::Ptr>::EndState || it.value() == XsdStateMachine<XsdTerm::Ptr>::StartEndState) { + for (int i = 0; i < processedSet.count(); ++i) { + if (processedSet.at(i).second == it.key() && + (baseStates.value(processedSet.at(i).first) != XsdStateMachine<XsdTerm::Ptr>::EndState && + baseStates.value(processedSet.at(i).first) != XsdStateMachine<XsdTerm::Ptr>::StartEndState)) { + errorMsg = QtXmlPatterns::tr("derived particle allows content that is not allowed in the base particle"); + return false; + } + } + } + } + + return true; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdparticlechecker_p.h b/src/xmlpatterns/schema/qxsdparticlechecker_p.h new file mode 100644 index 0000000..feed108 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdparticlechecker_p.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdParticleChecker_H +#define Patternist_XsdParticleChecker_H + +#include "qxsdelement_p.h" +#include "qxsdparticle_p.h" +#include "qxsdschemacontext_p.h" +#include "qxsdwildcard_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short A helper class to check validity of particles. + * + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdParticleChecker + { + public: + /** + * Checks whether the given @p particle has two or more element + * declarations with the same name but different type definitions. + */ + static bool hasDuplicatedElements(const XsdParticle::Ptr &particle, const NamePool::Ptr &namePool, XsdElement::Ptr &conflictingElement); + + /** + * Checks whether the given @p particle is valid according the + * UPA (http://www.w3.org/TR/xmlschema-1/#cos-nonambig) constraint. + */ + static bool isUPAConform(const XsdParticle::Ptr &particle, const NamePool::Ptr &namePool); + + /** + * Checks whether the given @p particle subsumes the given @p derivedParticle. + * (http://www.w3.org/TR/xmlschema-1/#cos-particle-restrict) + */ + static bool subsumes(const XsdParticle::Ptr &particle, const XsdParticle::Ptr &derivedParticle, const XsdSchemaContext::Ptr &context, QString &errorMsg); + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdreference.cpp b/src/xmlpatterns/schema/qxsdreference.cpp new file mode 100644 index 0000000..176dc31 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdreference.cpp @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdreference_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +bool XsdReference::isReference() const +{ + return true; +} + +void XsdReference::setType(Type type) +{ + m_type = type; +} + +XsdReference::Type XsdReference::type() const +{ + return m_type; +} + +void XsdReference::setReferenceName(const QXmlName &referenceName) +{ + m_referenceName = referenceName; +} + +QXmlName XsdReference::referenceName() const +{ + return m_referenceName; +} + +void XsdReference::setSourceLocation(const QSourceLocation &location) +{ + m_sourceLocation = location; +} + +QSourceLocation XsdReference::sourceLocation() const +{ + return m_sourceLocation; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdreference_p.h b/src/xmlpatterns/schema/qxsdreference_p.h new file mode 100644 index 0000000..1354d77 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdreference_p.h @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdReference_H +#define Patternist_XsdReference_H + +#include "qxsdterm_p.h" + +#include <QtXmlPatterns/QSourceLocation> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short A helper class for element and group reference resolving. + * + * For easy resolving of element and group references, we have this class + * that can be used as a place holder for the real element or group + * object it is referring to. + * So whenever the parser detects an element or group reference, it creates + * a XsdReference and returns it instead of the XsdElement or XsdModelGroup. + * During a later phase, the resolver will look for all XsdReferences + * in the schema and will replace them with their referring XsdElement or + * XsdModelGroup objects. + * + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdReference : public XsdTerm + { + public: + typedef QExplicitlySharedDataPointer<XsdReference> Ptr; + + /** + * Describes the type of the reference. + */ + enum Type + { + Element, ///< The reference points to an element. + ModelGroup ///< The reference points to a model group. + }; + + /** + * Returns always @c true, used to avoid dynamic casts. + */ + virtual bool isReference() const; + + /** + * Sets the @p type of the reference. + * + * @see Type + */ + void setType(Type type); + + /** + * Returns the type of the reference. + */ + Type type() const; + + /** + * Sets the @p name of the referenced object. + * + * The name can either be a top-level element declaration + * or a top-level group declaration. + */ + void setReferenceName(const QXmlName &ame); + + /** + * Returns the name of the referenced object. + */ + QXmlName referenceName() const; + + /** + * Sets the source @p location where the reference is located. + */ + void setSourceLocation(const QSourceLocation &location); + + /** + * Returns the source location where the reference is located. + */ + QSourceLocation sourceLocation() const; + + private: + Type m_type; + QXmlName m_referenceName; + QSourceLocation m_sourceLocation; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdschema.cpp b/src/xmlpatterns/schema/qxsdschema.cpp new file mode 100644 index 0000000..aac5773 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdschema.cpp @@ -0,0 +1,272 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdschema_p.h" + +#include <QtCore/QReadLocker> +#include <QtCore/QWriteLocker> + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +XsdSchema::XsdSchema(const NamePool::Ptr &namePool) + : m_namePool(namePool) +{ +} + +XsdSchema::~XsdSchema() +{ +} + +NamePool::Ptr XsdSchema::namePool() const +{ + return m_namePool; +} + +void XsdSchema::setTargetNamespace(const QString &targetNamespace) +{ + m_targetNamespace = targetNamespace; +} + +QString XsdSchema::targetNamespace() const +{ + return m_targetNamespace; +} + +void XsdSchema::addElement(const XsdElement::Ptr &element) +{ + const QWriteLocker locker(&m_lock); + + m_elements.insert(element->name(m_namePool), element); +} + +XsdElement::Ptr XsdSchema::element(const QXmlName &name) const +{ + const QReadLocker locker(&m_lock); + + return m_elements.value(name); +} + +XsdElement::List XsdSchema::elements() const +{ + const QReadLocker locker(&m_lock); + + return m_elements.values(); +} + +void XsdSchema::addAttribute(const XsdAttribute::Ptr &attribute) +{ + const QWriteLocker locker(&m_lock); + + m_attributes.insert(attribute->name(m_namePool), attribute); +} + +XsdAttribute::Ptr XsdSchema::attribute(const QXmlName &name) const +{ + const QReadLocker locker(&m_lock); + + return m_attributes.value(name); +} + +XsdAttribute::List XsdSchema::attributes() const +{ + const QReadLocker locker(&m_lock); + + return m_attributes.values(); +} + +void XsdSchema::addType(const SchemaType::Ptr &type) +{ + const QWriteLocker locker(&m_lock); + + m_types.insert(type->name(m_namePool), type); +} + +SchemaType::Ptr XsdSchema::type(const QXmlName &name) const +{ + const QReadLocker locker(&m_lock); + + return m_types.value(name); +} + +SchemaType::List XsdSchema::types() const +{ + const QReadLocker locker(&m_lock); + + return m_types.values(); +} + +XsdSimpleType::List XsdSchema::simpleTypes() const +{ + QReadLocker locker(&m_lock); + + XsdSimpleType::List retval; + + const SchemaType::List types = m_types.values(); + for (int i = 0; i < types.count(); ++i) { + if (types.at(i)->isSimpleType() && types.at(i)->isDefinedBySchema()) + retval.append(types.at(i)); + } + + return retval; +} + +XsdComplexType::List XsdSchema::complexTypes() const +{ + QReadLocker locker(&m_lock); + + XsdComplexType::List retval; + + const SchemaType::List types = m_types.values(); + for (int i = 0; i < types.count(); ++i) { + if (types.at(i)->isComplexType() && types.at(i)->isDefinedBySchema()) + retval.append(types.at(i)); + } + + return retval; +} + +void XsdSchema::addAnonymousType(const SchemaType::Ptr &type) +{ + const QWriteLocker locker(&m_lock); + + // search for not used anonymous type name + QXmlName typeName = type->name(m_namePool); + while (m_anonymousTypes.contains(typeName)) { + typeName = m_namePool->allocateQName(QString(), QLatin1String("merged_") + m_namePool->stringForLocalName(typeName.localName()), QString()); + } + + m_anonymousTypes.insert(typeName, type); +} + +SchemaType::List XsdSchema::anonymousTypes() const +{ + const QReadLocker locker(&m_lock); + + return m_anonymousTypes.values(); +} + +void XsdSchema::addAttributeGroup(const XsdAttributeGroup::Ptr &group) +{ + const QWriteLocker locker(&m_lock); + + m_attributeGroups.insert(group->name(m_namePool), group); +} + +XsdAttributeGroup::Ptr XsdSchema::attributeGroup(const QXmlName name) const +{ + const QReadLocker locker(&m_lock); + + return m_attributeGroups.value(name); +} + +XsdAttributeGroup::List XsdSchema::attributeGroups() const +{ + const QReadLocker locker(&m_lock); + + return m_attributeGroups.values(); +} + +void XsdSchema::addElementGroup(const XsdModelGroup::Ptr &group) +{ + const QWriteLocker locker(&m_lock); + + m_elementGroups.insert(group->name(m_namePool), group); +} + +XsdModelGroup::Ptr XsdSchema::elementGroup(const QXmlName &name) const +{ + const QReadLocker locker(&m_lock); + + return m_elementGroups.value(name); +} + +XsdModelGroup::List XsdSchema::elementGroups() const +{ + const QReadLocker locker(&m_lock); + + return m_elementGroups.values(); +} + +void XsdSchema::addNotation(const XsdNotation::Ptr ¬ation) +{ + const QWriteLocker locker(&m_lock); + + m_notations.insert(notation->name(m_namePool), notation); +} + +XsdNotation::Ptr XsdSchema::notation(const QXmlName &name) const +{ + const QReadLocker locker(&m_lock); + + return m_notations.value(name); +} + +XsdNotation::List XsdSchema::notations() const +{ + const QReadLocker locker(&m_lock); + + return m_notations.values(); +} + +void XsdSchema::addIdentityConstraint(const XsdIdentityConstraint::Ptr &constraint) +{ + const QWriteLocker locker(&m_lock); + + m_identityConstraints.insert(constraint->name(m_namePool), constraint); +} + +XsdIdentityConstraint::Ptr XsdSchema::identityConstraint(const QXmlName &name) const +{ + const QReadLocker locker(&m_lock); + + return m_identityConstraints.value(name); +} + +XsdIdentityConstraint::List XsdSchema::identityConstraints() const +{ + const QReadLocker locker(&m_lock); + + return m_identityConstraints.values(); +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdschema_p.h b/src/xmlpatterns/schema/qxsdschema_p.h new file mode 100644 index 0000000..d697673 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdschema_p.h @@ -0,0 +1,301 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdSchema_H +#define Patternist_XsdSchema_H + +#include "qschematype_p.h" +#include "qxsdannotated_p.h" +#include "qxsdattribute_p.h" +#include "qxsdattributegroup_p.h" +#include "qxsdcomplextype_p.h" +#include "qxsdelement_p.h" +#include "qxsdidentityconstraint_p.h" +#include "qxsdmodelgroup_p.h" +#include "qxsdnotation_p.h" +#include "qxsdsimpletype_p.h" + +#include <QtCore/QHash> +#include <QtCore/QReadWriteLock> + +/** + * @defgroup Patternist_schema XML Schema Processing + */ + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short Represents a XSD schema object. + * + * The class provides access to all components of a parsed XSD. + * + * @note In the documentation of this class objects, which are direct + * children of the <em>schema</em> object, are called top-level objects. + * + * @see <a href="http://www.w3.org/Submission/2004/SUBM-xmlschema-api-20040309/xml-schema-api.html#Interface-XSModel">XML Schema API reference</a> + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdSchema : public QSharedData, public XsdAnnotated + { + public: + typedef QExplicitlySharedDataPointer<XsdSchema> Ptr; + typedef QList<XsdSchema::Ptr> List; + + /** + * Creates a new schema object. + * + * @param namePool The namepool that should be used for names of + * all schema components. + */ + XsdSchema(const NamePool::Ptr &namePool); + + /** + * Destroys the schema object. + */ + ~XsdSchema(); + + /** + * Returns the namepool that is used for names of + * all schema components. + */ + NamePool::Ptr namePool() const; + + /** + * Sets the @p targetNamespace of the schema. + */ + void setTargetNamespace(const QString &targetNamespace); + + /** + * Returns the target namespace of the schema. + */ + QString targetNamespace() const; + + /** + * Adds a new top-level @p element to the schema. + * + * @param element The new element. + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#declare-element">Element Declaration</a> + */ + void addElement(const XsdElement::Ptr &element); + + /** + * Returns the top-level element of the schema with + * the given @p name or an empty pointer if none exist. + */ + XsdElement::Ptr element(const QXmlName &name) const; + + /** + * Returns the list of all top-level elements. + */ + XsdElement::List elements() const; + + /** + * Adds a new top-level @p attribute to the schema. + * + * @param attribute The new attribute. + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#declare-attribute">Attribute Declaration</a> + */ + void addAttribute(const XsdAttribute::Ptr &attribute); + + /** + * Returns the top-level attribute of the schema with + * the given @p name or an empty pointer if none exist. + */ + XsdAttribute::Ptr attribute(const QXmlName &name) const; + + /** + * Returns the list of all top-level attributes. + */ + XsdAttribute::List attributes() const; + + /** + * Adds a new top-level @p type to the schema. + * That can be a simple or a complex type. + * + * @param type The new type. + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#declare-datatype">Simple Type Declaration</a> + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#declare-type">Complex Type Declaration</a> + */ + void addType(const SchemaType::Ptr &type); + + /** + * Returns the top-level type of the schema with + * the given @p name or an empty pointer if none exist. + */ + SchemaType::Ptr type(const QXmlName &name) const; + + /** + * Returns the list of all top-level types. + */ + SchemaType::List types() const; + + /** + * Returns the list of all top-level simple types. + */ + XsdSimpleType::List simpleTypes() const; + + /** + * Returns the list of all top-level complex types. + */ + XsdComplexType::List complexTypes() const; + + /** + * Adds an anonymous @p type to the schema. + * Anonymous types have no name and are declared + * locally inside an element object. + * + * @param type The new anonymous type. + */ + void addAnonymousType(const SchemaType::Ptr &type); + + /** + * Returns the list of all anonymous types. + */ + SchemaType::List anonymousTypes() const; + + /** + * Adds a new top-level attribute @p group to the schema. + * + * @param group The new attribute group. + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#declare-attributeGroup">Attribute Group Declaration</a> + */ + void addAttributeGroup(const XsdAttributeGroup::Ptr &group); + + /** + * Returns the top-level attribute group of the schema with + * the given @p name or an empty pointer if none exist. + */ + XsdAttributeGroup::Ptr attributeGroup(const QXmlName name) const; + + /** + * Returns the list of all top-level attribute groups. + */ + XsdAttributeGroup::List attributeGroups() const; + + /** + * Adds a new top-level element @p group to the schema. + * + * @param group The new element group. + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#declare-namedModelGroup">Element Group Declaration</a> + */ + void addElementGroup(const XsdModelGroup::Ptr &group); + + /** + * Returns the top-level element group of the schema with + * the given @p name or an empty pointer if none exist. + */ + XsdModelGroup::Ptr elementGroup(const QXmlName &name) const; + + /** + * Returns the list of all top-level element groups. + */ + XsdModelGroup::List elementGroups() const; + + /** + * Adds a new top-level @p notation to the schema. + * + * @param notation The new notation. + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#declare-notation">Notation Declaration</a> + */ + void addNotation(const XsdNotation::Ptr ¬ation); + + /** + * Returns the top-level notation of the schema with + * the given @p name or an empty pointer if none exist. + */ + XsdNotation::Ptr notation(const QXmlName &name) const; + + /** + * Returns the list of all top-level notations. + */ + XsdNotation::List notations() const; + + /** + * Adds a new identity @p constraint to the schema. + */ + void addIdentityConstraint(const XsdIdentityConstraint::Ptr &constraint); + + /** + * Returns the identity constraint with the given @p name + * or an empty pointer if none exist. + */ + XsdIdentityConstraint::Ptr identityConstraint(const QXmlName &name) const; + + /** + * Returns the list of all identity constraints in this schema. + */ + XsdIdentityConstraint::List identityConstraints() const; + + private: + NamePool::Ptr m_namePool; + QString m_targetNamespace; + QHash<QXmlName, XsdElement::Ptr> m_elements; + QHash<QXmlName, XsdAttribute::Ptr> m_attributes; + QHash<QXmlName, SchemaType::Ptr> m_types; + QHash<QXmlName, SchemaType::Ptr> m_anonymousTypes; + QHash<QXmlName, XsdAttributeGroup::Ptr> m_attributeGroups; + QHash<QXmlName, XsdModelGroup::Ptr> m_elementGroups; + QHash<QXmlName, XsdNotation::Ptr> m_notations; + QHash<QXmlName, XsdIdentityConstraint::Ptr> m_identityConstraints; + mutable QReadWriteLock m_lock; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdschemachecker.cpp b/src/xmlpatterns/schema/qxsdschemachecker.cpp new file mode 100644 index 0000000..d2001eb --- /dev/null +++ b/src/xmlpatterns/schema/qxsdschemachecker.cpp @@ -0,0 +1,2061 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdschemachecker_p.h" + +#include "qderivedinteger_p.h" +#include "qderivedstring_p.h" +#include "qpatternplatform_p.h" +#include "qqnamevalue_p.h" +#include "qsourcelocationreflection_p.h" +#include "qvaluefactory_p.h" +#include "qxsdattributereference_p.h" +#include "qxsdparticlechecker_p.h" +#include "qxsdreference_p.h" +#include "qxsdschemacontext_p.h" +#include "qxsdschemahelper_p.h" +#include "qxsdschemaparsercontext_p.h" +#include "qxsdschematypesfactory_p.h" +#include "qxsdtypechecker_p.h" + +#include "qxsdschemachecker_helper.cpp" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +XsdSchemaChecker::XsdSchemaChecker(const QExplicitlySharedDataPointer<XsdSchemaContext> &context, const XsdSchemaParserContext *parserContext) + : m_context(context) + , m_namePool(parserContext->namePool()) + , m_schema(parserContext->schema()) +{ + setupAllowedAtomicFacets(); +} + +XsdSchemaChecker::~XsdSchemaChecker() +{ +} + +/* + * This method is called after the resolver has set the base type for every + * type and information about deriavtion and 'is simple type vs. is complex type' + * are available. + */ +void XsdSchemaChecker::basicCheck() +{ + // first check that there is no circular inheritance, only the + // wxsSuperType is used here + checkBasicCircularInheritances(); + + // check the basic constraints like simple type can not inherit from complex type etc. + checkBasicSimpleTypeConstraints(); + checkBasicComplexTypeConstraints(); +} + +void XsdSchemaChecker::check() +{ + checkCircularInheritances(); + checkInheritanceRestrictions(); + checkSimpleDerivationRestrictions(); + checkSimpleTypeConstraints(); + checkComplexTypeConstraints(); + checkDuplicatedAttributeUses(); + + checkElementConstraints(); + checkAttributeConstraints(); + checkAttributeUseConstraints(); +// checkElementDuplicates(); +} + +void XsdSchemaChecker::addComponentLocationHash(const ComponentLocationHash &hash) +{ + m_componentLocationHash.unite(hash); +} + +/** + * Checks whether the @p otherType is the same as @p myType or if one of its + * ancestors is the same as @p myType. + */ +static bool matchesType(const SchemaType::Ptr &myType, const SchemaType::Ptr &otherType, QSet<SchemaType::Ptr> visitedTypes) +{ + bool retval = false; + + if (otherType) { + if (visitedTypes.contains(otherType)) { + return true; + } else { + visitedTypes.insert(otherType); + } + // simple types can have different varieties, so we have to check each of them + if (otherType->isSimpleType()) { + const XsdSimpleType::Ptr simpleType = otherType; + if (simpleType->category() == XsdSimpleType::SimpleTypeAtomic) { + // for atomic type we use the same test as in SchemaType::wxsTypeMatches + retval = (myType == simpleType ? true : matchesType(myType, simpleType->wxsSuperType(), visitedTypes)); + } else if (simpleType->category() == XsdSimpleType::SimpleTypeList) { + // for list type we test against the itemType property + retval = (myType == simpleType->itemType() ? true : matchesType(myType, simpleType->itemType()->wxsSuperType(), visitedTypes)); + } else if (simpleType->category() == XsdSimpleType::SimpleTypeUnion) { + // for union type we test against each member type + const XsdSimpleType::List members = simpleType->memberTypes(); + for (int i = 0; i < members.count(); ++i) { + if (myType == members.at(i) ? true : matchesType(myType, members.at(i)->wxsSuperType(), visitedTypes)) { + retval = true; + break; + } + } + } else { + // reached xsAnySimple type whichs category is None + retval = false; + } + } else { + // if no simple type we handle it like in SchemaType::wxsTypeMatches + retval = (myType == otherType ? true : matchesType(myType, otherType->wxsSuperType(), visitedTypes)); + } + } else // if otherType is null it doesn't match + retval = false; + + return retval; +} + +/** + * Checks whether there is a circular inheritance for the union inheritance. + */ +static bool hasCircularUnionInheritance(const XsdSimpleType::Ptr &type, const SchemaType::Ptr &otherType, NamePool::Ptr &namePool) +{ + if (type == otherType) { + return true; + } + + if (!otherType->isSimpleType() || !otherType->isDefinedBySchema()) { + return false; + } + + const XsdSimpleType::Ptr simpleOtherType = otherType; + + if (simpleOtherType->category() == XsdSimpleType::SimpleTypeUnion) { + const XsdSimpleType::List memberTypes = simpleOtherType->memberTypes(); + for (int i = 0; i < memberTypes.count(); ++i) { + if (otherType->wxsSuperType() == type) { + return true; + } + if (hasCircularUnionInheritance(type, memberTypes.at(i), namePool)) { + return true; + } + } + } + + return false; +} + +static inline bool wxsTypeMatches(const SchemaType::Ptr &type, const SchemaType::Ptr &otherType, QSet<SchemaType::Ptr> &visitedTypes, SchemaType::Ptr &conflictingType) +{ + if (!otherType) + return false; + + if (visitedTypes.contains(otherType)) { // inheritance loop detected + conflictingType = otherType; + return true; + } else { + visitedTypes.insert(otherType); + } + + if (type == otherType) + return true; + + return wxsTypeMatches(type, otherType->wxsSuperType(), visitedTypes, conflictingType); +} + +void XsdSchemaChecker::checkBasicCircularInheritances() +{ + // check all global types... + SchemaType::List types = m_schema->types(); + + // .. and anonymous types + types << m_schema->anonymousTypes(); + + for (int i = 0; i < types.count(); ++i) { + const SchemaType::Ptr type = types.at(i); + const QSourceLocation location = sourceLocationForType(type); + + // @see http://www.w3.org/TR/xmlschema11-1/#ct-props-correct 3) + + // check normal base type inheritance + QSet<SchemaType::Ptr> visitedTypes; + SchemaType::Ptr conflictingType; + + if (wxsTypeMatches(type, type->wxsSuperType(), visitedTypes, conflictingType)) { + if (conflictingType) + m_context->error(QtXmlPatterns::tr("%1 has inheritance loop in its base type %2") + .arg(formatType(m_namePool, type)) + .arg(formatType(m_namePool, conflictingType)), + XsdSchemaContext::XSDError, location); + else + m_context->error(QtXmlPatterns::tr("circular inheritance of base type %1").arg(formatType(m_namePool, type)), XsdSchemaContext::XSDError, location); + + return; + } + } +} + +void XsdSchemaChecker::checkCircularInheritances() +{ + // check all global types... + SchemaType::List types = m_schema->types(); + + // .. and anonymous types + types << m_schema->anonymousTypes(); + + for (int i = 0; i < types.count(); ++i) { + const SchemaType::Ptr type = types.at(i); + const QSourceLocation location = sourceLocationForType(type); + + // @see http://www.w3.org/TR/xmlschema11-1/#ct-props-correct 3) + + // check normal base type inheritance + QSet<SchemaType::Ptr> visitedTypes; + if (matchesType(type, type->wxsSuperType(), visitedTypes)) { + m_context->error(QtXmlPatterns::tr("circular inheritance of base type %1").arg(formatType(m_namePool, type)), XsdSchemaContext::XSDError, location); + return; + } + + // check union member inheritance + if (type->isSimpleType() && type->isDefinedBySchema()) { + const XsdSimpleType::Ptr simpleType = type; + if (simpleType->category() == XsdSimpleType::SimpleTypeUnion) { + const XsdSimpleType::List memberTypes = simpleType->memberTypes(); + for (int j = 0; j < memberTypes.count(); ++j) { + if (hasCircularUnionInheritance(simpleType, memberTypes.at(j), m_namePool)) { + m_context->error(QtXmlPatterns::tr("circular inheritance of union %1").arg(formatType(m_namePool, type)), XsdSchemaContext::XSDError, location); + return; + } + } + } + } + } +} + +void XsdSchemaChecker::checkInheritanceRestrictions() +{ + // check all global types... + SchemaType::List types = m_schema->types(); + + // .. and anonymous types + types << m_schema->anonymousTypes(); + + for (int i = 0; i < types.count(); ++i) { + const SchemaType::Ptr type = types.at(i); + const QSourceLocation location = sourceLocationForType(type); + + // check inheritance restrictions given by final property of base class + const SchemaType::Ptr baseType = type->wxsSuperType(); + if (baseType->isDefinedBySchema()) { + if ((type->derivationMethod() == SchemaType::DerivationRestriction) && (baseType->derivationConstraints() & SchemaType::RestrictionConstraint)) { + m_context->error(QtXmlPatterns::tr("%1 is not allowed to derive from %2 by restriction as the latter defines it as final") + .arg(formatType(m_namePool, type)) + .arg(formatType(m_namePool, baseType)), XsdSchemaContext::XSDError, location); + return; + } else if ((type->derivationMethod() == SchemaType::DerivationExtension) && (baseType->derivationConstraints() & SchemaType::ExtensionConstraint)) { + m_context->error(QtXmlPatterns::tr("%1 is not allowed to derive from %2 by extension as the latter defines it as final") + .arg(formatType(m_namePool, type)) + .arg(formatType(m_namePool, baseType)), XsdSchemaContext::XSDError, location); + return; + } + } + } +} + +void XsdSchemaChecker::checkBasicSimpleTypeConstraints() +{ + // check all global types... + SchemaType::List types = m_schema->types(); + + // .. and anonymous types + types << m_schema->anonymousTypes(); + + for (int i = 0; i < types.count(); ++i) { + const SchemaType::Ptr type = types.at(i); + + if (!type->isSimpleType()) + continue; + + const XsdSimpleType::Ptr simpleType = type; + + const QSourceLocation location = sourceLocation(simpleType); + + // check inheritance restrictions of simple type defined by schema constraints + const SchemaType::Ptr baseType = simpleType->wxsSuperType(); + + if (baseType->isComplexType() && (simpleType->name(m_namePool) != BuiltinTypes::xsAnySimpleType->name(m_namePool))) { + m_context->error(QtXmlPatterns::tr("base type of simple type %1 cannot be complex type %2") + .arg(formatType(m_namePool, simpleType)) + .arg(formatType(m_namePool, baseType)), + XsdSchemaContext::XSDError, location); + return; + } + + if (baseType == BuiltinTypes::xsAnyType) { + if (type->name(m_namePool) != BuiltinTypes::xsAnySimpleType->name(m_namePool)) { + m_context->error(QtXmlPatterns::tr("simple type %1 cannot have direct base type %2") + .arg(formatType(m_namePool, simpleType)) + .arg(formatType(m_namePool, BuiltinTypes::xsAnyType)), + XsdSchemaContext::XSDError, location); + return; + } + } + } +} + +void XsdSchemaChecker::checkSimpleTypeConstraints() +{ + // check all global types... + SchemaType::List types = m_schema->types(); + + // .. and anonymous types + types << m_schema->anonymousTypes(); + + for (int i = 0; i < types.count(); ++i) { + const SchemaType::Ptr type = types.at(i); + + if (!type->isSimpleType()) + continue; + + const XsdSimpleType::Ptr simpleType = type; + + const QSourceLocation location = sourceLocation(simpleType); + + if (simpleType->category() == XsdSimpleType::None) { + // additional checks + // check that no user defined type has xs:AnySimpleType as base type (except xs:AnyAtomicType) + if (simpleType->wxsSuperType()->name(m_namePool) == BuiltinTypes::xsAnySimpleType->name(m_namePool)) { + if (simpleType->name(m_namePool) != BuiltinTypes::xsAnyAtomicType->name(m_namePool)) { + m_context->error(QtXmlPatterns::tr("simple type %1 is not allowed to have base type %2") + .arg(formatType(m_namePool, simpleType)) + .arg(formatType(m_namePool, simpleType->wxsSuperType())), + XsdSchemaContext::XSDError, location); + return; + } + } + // check that no user defined type has xs:AnyAtomicType as base type + if (simpleType->wxsSuperType()->name(m_namePool) == BuiltinTypes::xsAnyAtomicType->name(m_namePool)) { + m_context->error(QtXmlPatterns::tr("simple type %1 is not allowed to have base type %2") + .arg(formatType(m_namePool, simpleType)) + .arg(formatType(m_namePool, simpleType->wxsSuperType())), + XsdSchemaContext::XSDError, location); + return; + } + } + + // @see http://www.w3.org/TR/xmlschema11-1/#d0e37310 + if (simpleType->category() == XsdSimpleType::SimpleTypeAtomic) { + // 1.1 + if ((simpleType->wxsSuperType()->category() != XsdSimpleType::SimpleTypeAtomic) && (simpleType->name(m_namePool) != BuiltinTypes::xsAnyAtomicType->name(m_namePool))) { + m_context->error(QtXmlPatterns::tr("simple type %1 can only have simple atomic type as base type") + .arg(formatType(m_namePool, simpleType)), + XsdSchemaContext::XSDError, location); + } + // 1.2 + if (simpleType->wxsSuperType()->derivationConstraints() & SchemaType::RestrictionConstraint) { + m_context->error(QtXmlPatterns::tr("simple type %1 cannot derive from %2 as the latter defines restriction as final") + .arg(formatType(m_namePool, simpleType->wxsSuperType())) + .arg(formatType(m_namePool, simpleType)), + XsdSchemaContext::XSDError, location); + } + + // 1.3 + // checked by checkConstrainingFacets already + } else if (simpleType->category() == XsdSimpleType::SimpleTypeList) { + const AnySimpleType::Ptr itemType = simpleType->itemType(); + + // 2.1 or @see http://www.w3.org/TR/xmlschema-2/#cos-list-of-atomic + if (itemType->category() != SchemaType::SimpleTypeAtomic && itemType->category() != SchemaType::SimpleTypeUnion) { + m_context->error(QtXmlPatterns::tr("variety of item type of %1 must be either atomic or union").arg(formatType(m_namePool, simpleType)), XsdSchemaContext::XSDError, location); + return; + } + + // 2.1 second part + if (itemType->category() == SchemaType::SimpleTypeUnion && itemType->isDefinedBySchema()) { + const XsdSimpleType::Ptr simpleItemType = itemType; + const AnySimpleType::List memberTypes = simpleItemType->memberTypes(); + for (int j = 0; j < memberTypes.count(); ++j) { + if (memberTypes.at(j)->category() != SchemaType::SimpleTypeAtomic) { + m_context->error(QtXmlPatterns::tr("variety of member types of %1 must be atomic").arg(formatType(m_namePool, simpleItemType)), XsdSchemaContext::XSDError, location); + return; + } + } + } + + // 2.2.1 + if (simpleType->wxsSuperType()->name(m_namePool) == BuiltinTypes::xsAnySimpleType->name(m_namePool)) { + if (itemType->isSimpleType() && itemType->isDefinedBySchema()) { + const XsdSimpleType::Ptr simpleItemType = itemType; + + // 2.2.1.1 + if (simpleItemType->derivationConstraints() & XsdSimpleType::ListConstraint) { + m_context->error(QtXmlPatterns::tr("%1 is not allowed to derive from %2 by list as the latter defines it as final") + .arg(formatType(m_namePool, simpleType)) + .arg(formatType(m_namePool, simpleItemType)), XsdSchemaContext::XSDError, location); + return; + } + + // 2.2.1.2 + const XsdFacet::Hash facets = simpleType->facets(); + XsdFacet::HashIterator it(facets); + + bool invalidFacetFound = false; + while (it.hasNext()) { + it.next(); + if (it.key() != XsdFacet::WhiteSpace) { + invalidFacetFound = true; + break; + } + } + + if (invalidFacetFound) { + m_context->error(QtXmlPatterns::tr("simple type %1 is only allowed to have %2 facet") + .arg(formatType(m_namePool, simpleType)) + .arg(formatKeyword("whiteSpace")), + XsdSchemaContext::XSDError, location); + return; + } + } + } else { // 2.2.2 + // 2.2.2.1 + if (simpleType->wxsSuperType()->category() != XsdSimpleType::SimpleTypeList) { + m_context->error(QtXmlPatterns::tr("base type of simple type %1 must have variety of type list").arg(formatType(m_namePool, simpleType)), XsdSchemaContext::XSDError, location); + return; + } + + // 2.2.2.2 + if (simpleType->wxsSuperType()->derivationConstraints() & SchemaType::RestrictionConstraint) { + m_context->error(QtXmlPatterns::tr("base type of simple type %1 has defined derivation by restriction as final").arg(formatType(m_namePool, simpleType)), XsdSchemaContext::XSDError, location); + return; + } + + // 2.2.2.3 + if (!XsdSchemaHelper::isSimpleDerivationOk(itemType, XsdSimpleType::Ptr(simpleType->wxsSuperType())->itemType(), SchemaType::DerivationConstraints())) { + m_context->error(QtXmlPatterns::tr("item type of base type does not match item type of %1").arg(formatType(m_namePool, simpleType)), XsdSchemaContext::XSDError, location); + return; + } + + // 2.2.2.4 + const XsdFacet::Hash facets = simpleType->facets(); + XsdFacet::HashIterator it(facets); + + bool invalidFacetFound = false; + XsdFacet::Type invalidFacetType = XsdFacet::None; + while (it.hasNext()) { + it.next(); + const XsdFacet::Type facetType = it.key(); + if (facetType != XsdFacet::Length && + facetType != XsdFacet::MinimumLength && + facetType != XsdFacet::MaximumLength && + facetType != XsdFacet::WhiteSpace && + facetType != XsdFacet::Pattern && + facetType != XsdFacet::Enumeration) { + invalidFacetType = facetType; + invalidFacetFound = true; + break; + } + } + + if (invalidFacetFound) { + m_context->error(QtXmlPatterns::tr("simple type %1 contains not allowed facet type %2") + .arg(formatType(m_namePool, simpleType)) + .arg(formatKeyword(XsdFacet::typeName(invalidFacetType))), + XsdSchemaContext::XSDError, location); + return; + } + + // 2.2.2.5 + // TODO: check value constraints + } + + + } else if (simpleType->category() == XsdSimpleType::SimpleTypeUnion) { + const AnySimpleType::List memberTypes = simpleType->memberTypes(); + + if (simpleType->wxsSuperType()->name(m_namePool) == BuiltinTypes::xsAnySimpleType->name(m_namePool)) { // 3.1.1 + // 3.3.1.1 + for (int i = 0; i < memberTypes.count(); ++i) { + const AnySimpleType::Ptr memberType = memberTypes.at(i); + + if (memberType->derivationConstraints() & XsdSimpleType::UnionConstraint) { + m_context->error(QtXmlPatterns::tr("%1 is not allowed to derive from %2 by union as the latter defines it as final") + .arg(formatType(m_namePool, simpleType)) + .arg(formatType(m_namePool, memberType)), XsdSchemaContext::XSDError, location); + return; + } + } + + // 3.3.1.2 + if (!simpleType->facets().isEmpty()) { + m_context->error(QtXmlPatterns::tr("%1 is not allowed to have any facets") + .arg(formatType(m_namePool, simpleType)), + XsdSchemaContext::XSDError, location); + return; + } + } else { + // 3.1.2.1 + if (simpleType->wxsSuperType()->category() != SchemaType::SimpleTypeUnion) { + m_context->error(QtXmlPatterns::tr("base type %1 of simple type %2 must have variety of union") + .arg(formatType(m_namePool, simpleType->wxsSuperType())) + .arg(formatType(m_namePool, simpleType)), + XsdSchemaContext::XSDError, location); + return; + } + + // 3.1.2.2 + if (simpleType->wxsSuperType()->derivationConstraints() & SchemaType::DerivationRestriction) { + m_context->error(QtXmlPatterns::tr("base type %1 of simple type %2 is not allowed to have restriction in %3 attribute") + .arg(formatType(m_namePool, simpleType->wxsSuperType())) + .arg(formatType(m_namePool, simpleType)) + .arg(formatAttribute("final")), + XsdSchemaContext::XSDError, location); + return; + } + + //3.1.2.3 + if (simpleType->wxsSuperType()->isDefinedBySchema()) { + const XsdSimpleType::Ptr simpleBaseType(simpleType->wxsSuperType()); + + AnySimpleType::List baseMemberTypes = simpleBaseType->memberTypes(); + for (int i = 0; i < memberTypes.count(); ++i) { + const AnySimpleType::Ptr memberType = memberTypes.at(i); + const AnySimpleType::Ptr baseMemberType = baseMemberTypes.at(i); + + if (!XsdSchemaHelper::isSimpleDerivationOk(memberType, baseMemberType, SchemaType::DerivationConstraints())) { + m_context->error(QtXmlPatterns::tr("member type %1 cannot be derived from member type %2 of %3's base type %4") + .arg(formatType(m_namePool, memberType)) + .arg(formatType(m_namePool, baseMemberType)) + .arg(formatType(m_namePool, simpleType)) + .arg(formatType(m_namePool, simpleBaseType)), + XsdSchemaContext::XSDError, location); + } + } + } + + // 3.1.2.4 + const XsdFacet::Hash facets = simpleType->facets(); + XsdFacet::HashIterator it(facets); + + bool invalidFacetFound = false; + XsdFacet::Type invalidFacetType = XsdFacet::None; + while (it.hasNext()) { + it.next(); + const XsdFacet::Type facetType = it.key(); + if (facetType != XsdFacet::Pattern && + facetType != XsdFacet::Enumeration) { + invalidFacetType = facetType; + invalidFacetFound = true; + break; + } + } + + if (invalidFacetFound) { + m_context->error(QtXmlPatterns::tr("simple type %1 contains not allowed facet type %2") + .arg(formatType(m_namePool, simpleType)) + .arg(formatKeyword(XsdFacet::typeName(invalidFacetType))), + XsdSchemaContext::XSDError, location); + return; + } + + // 3.1.2.5 + // TODO: check value constraints + } + } + } +} + +void XsdSchemaChecker::checkBasicComplexTypeConstraints() +{ + // check all global types... + SchemaType::List types = m_schema->types(); + + // .. and anonymous types + types << m_schema->anonymousTypes(); + + for (int i = 0; i < types.count(); ++i) { + const SchemaType::Ptr type = types.at(i); + + if (!type->isComplexType() || !type->isDefinedBySchema()) + continue; + + const XsdComplexType::Ptr complexType = type; + + const QSourceLocation location = sourceLocation(complexType); + + // check inheritance restrictions of complex type defined by schema constraints + const SchemaType::Ptr baseType = complexType->wxsSuperType(); + + // @see http://www.w3.org/TR/xmlschema11-1/#ct-props-correct 2) + if (baseType->isSimpleType() && (complexType->derivationMethod() != XsdComplexType::DerivationExtension)) { + m_context->error(QtXmlPatterns::tr("derivation method of %1 must be extension because the base type %2 is a simple type") + .arg(formatType(m_namePool, complexType)) + .arg(formatType(m_namePool, baseType)), + XsdSchemaContext::XSDError, location); + return; + } + } +} + +void XsdSchemaChecker::checkComplexTypeConstraints() +{ + // check all global types... + SchemaType::List types = m_schema->types(); + + // .. and anonymous types + types << m_schema->anonymousTypes(); + + for (int i = 0; i < types.count(); ++i) { + const SchemaType::Ptr type = types.at(i); + + if (!type->isComplexType() || !type->isDefinedBySchema()) + continue; + + const XsdComplexType::Ptr complexType = type; + + const QSourceLocation location = sourceLocation(complexType); + + if (complexType->contentType()->particle()) { + XsdElement::Ptr duplicatedElement; + if (XsdParticleChecker::hasDuplicatedElements(complexType->contentType()->particle(), m_namePool, duplicatedElement)) { + m_context->error(QtXmlPatterns::tr("complex type %1 has duplicated element %2 in its content model") + .arg(formatType(m_namePool, complexType)) + .arg(formatKeyword(duplicatedElement->displayName(m_namePool))), + XsdSchemaContext::XSDError, location); + return; + } + + if (!XsdParticleChecker::isUPAConform(complexType->contentType()->particle(), m_namePool)) { + m_context->error(QtXmlPatterns::tr("complex type %1 has non-deterministic content") + .arg(formatType(m_namePool, complexType)), + XsdSchemaContext::XSDError, location); + return; + } + } + + // check inheritance restrictions of complex type defined by schema constraints + const SchemaType::Ptr baseType = complexType->wxsSuperType(); + + // @see http://www.w3.org/TR/xmlschema11-1/#cos-ct-extends + if (complexType->derivationMethod() == XsdComplexType::DerivationExtension) { + if (baseType->isComplexType() && baseType->isDefinedBySchema()) { + const XsdComplexType::Ptr complexBaseType = baseType; + + // we can skip 1.1 here, as it is tested in checkInheritanceRestrictions() already + + // 1.2 and 1.3 + QString errorMsg; + if (!XsdSchemaHelper::isValidAttributeUsesExtension(complexType->attributeUses(), complexBaseType->attributeUses(), + complexType->attributeWildcard(), complexBaseType->attributeWildcard(), m_context, errorMsg)) { + m_context->error(QtXmlPatterns::tr("attributes of complex type %1 are not a valid extension of the attributes of base type %2: %3") + .arg(formatType(m_namePool, complexType)) + .arg(formatType(m_namePool, baseType)) + .arg(errorMsg), + XsdSchemaContext::XSDError, location); + return; + } + + // 1.4 + bool validContentType = false; + if (complexType->contentType()->variety() == XsdComplexType::ContentType::Simple && complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Simple) { + if (complexType->contentType()->simpleType() == complexBaseType->contentType()->simpleType()) { + validContentType = true; // 1.4.1 + } + } else if (complexType->contentType()->variety() == XsdComplexType::ContentType::Empty && complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Empty) { + validContentType = true; // 1.4.2 + } else { // 1.4.3 + if (complexType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly || complexType->contentType()->variety() == XsdComplexType::ContentType::Mixed) { // 1.4.3.1 + if (complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Empty) { + validContentType = true; // 1.4.3.2.1 + } else { // 1.4.3.2.2 + if (complexType->contentType()->particle()) { // our own check + if ((complexType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly && complexBaseType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly) || + (complexType->contentType()->variety() == XsdComplexType::ContentType::Mixed && complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Mixed)) { // 1.4.3.2.2.1 + if (isValidParticleExtension(complexType->contentType()->particle(), complexBaseType->contentType()->particle())) { + validContentType = true; // 1.4.3.2.2.2 + } + } + } + // 1.4.3.2.2.3 and 1.4.3.2.2.4 handle 'open content' that we do not support yet + } + } + } + + // 1.5 WTF?!? + + if (!validContentType) { + m_context->error(QtXmlPatterns::tr("content model of complex type %1 is not a valid extension of content model of %2") + .arg(formatType(m_namePool, complexType)) + .arg(formatType(m_namePool, complexBaseType)), + XsdSchemaContext::XSDError, location); + return; + } + + } else if (baseType->isSimpleType()) { + // 2.1 + if (complexType->contentType()->variety() != XsdComplexType::ContentType::Simple) { + m_context->error(QtXmlPatterns::tr("complex type %1 must have simple content") + .arg(formatType(m_namePool, complexType)), + XsdSchemaContext::XSDError, location); + return; + } + + if (complexType->contentType()->simpleType() != baseType) { + m_context->error(QtXmlPatterns::tr("complex type %1 must have the same simple type as its base class %2") + .arg(formatType(m_namePool, complexType)) + .arg(formatType(m_namePool, baseType)), + XsdSchemaContext::XSDError, location); + return; + } + + // 2.2 tested in checkInheritanceRestrictions() already + } + } else if (complexType->derivationMethod() == XsdComplexType::DerivationRestriction) { + // @see http://www.w3.org/TR/xmlschema11-1/#d0e21402 + const SchemaType::Ptr baseType(complexType->wxsSuperType()); + + bool derivationOk = false; + QString errorMsg; + + // we can partly skip 1 here, as it is tested in checkInheritanceRestrictions() already + if (baseType->isComplexType()) { + + // 2.1 + if (baseType->name(m_namePool) == BuiltinTypes::xsAnyType->name(m_namePool)) { + derivationOk = true; + } + + if (baseType->isDefinedBySchema()) { + const XsdComplexType::Ptr complexBaseType(baseType); + + // 2.2.1 + if (complexType->contentType()->variety() == XsdComplexType::ContentType::Simple) { + // 2.2.2.1 + if (XsdSchemaHelper::isSimpleDerivationOk(complexType->contentType()->simpleType(), complexBaseType->contentType()->simpleType(), SchemaType::DerivationConstraints())) + derivationOk = true; + + // 2.2.2.2 + if (complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Mixed) { + if (XsdSchemaHelper::isParticleEmptiable(complexBaseType->contentType()->particle())) + derivationOk = true; + } + } + + // 2.3.1 + if (complexType->contentType()->variety() == XsdComplexType::ContentType::Empty) { + // 2.3.2.1 + if (complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Empty) + derivationOk = true; + + // 2.3.2.2 + if (complexBaseType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly || complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Mixed) { + if (XsdSchemaHelper::isParticleEmptiable(complexBaseType->contentType()->particle())) + derivationOk = true; + } + } + + // 2.4.1.1 + if (((complexType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly) && + (complexBaseType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly || complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Mixed)) || + // 2.4.1.2 + (complexType->contentType()->variety() == XsdComplexType::ContentType::Mixed && complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Mixed)) { + + // 2.4.2 + if (XsdParticleChecker::subsumes(complexBaseType->contentType()->particle(), complexType->contentType()->particle(), m_context, errorMsg)) + derivationOk = true; + } + } + } + + if (!derivationOk) { + m_context->error(QtXmlPatterns::tr("complex type %1 cannot be derived from base type %2%3") + .arg(formatType(m_namePool, complexType)) + .arg(formatType(m_namePool, baseType)) + .arg(errorMsg.isEmpty() ? QString() : QLatin1String(": ") + errorMsg), + XsdSchemaContext::XSDError, location); + return; + } + + if (baseType->isDefinedBySchema()) { + const XsdComplexType::Ptr complexBaseType(baseType); + + QString errorMsg; + if (!XsdSchemaHelper::isValidAttributeUsesRestriction(complexType->attributeUses(), complexBaseType->attributeUses(), + complexType->attributeWildcard(), complexBaseType->attributeWildcard(), m_context, errorMsg)) { + m_context->error(QtXmlPatterns::tr("attributes of complex type %1 are not a valid restriction from the attributes of base type %2: %3") + .arg(formatType(m_namePool, complexType)) + .arg(formatType(m_namePool, baseType)) + .arg(errorMsg), + XsdSchemaContext::XSDError, location); + return; + } + } + } + + // check that complex type with simple content is not allowed to inherit from + // built in complex type xs:AnyType + if (complexType->contentType()->variety() == XsdComplexType::ContentType::Simple) { + if (baseType->name(m_namePool) == BuiltinTypes::xsAnyType->name(m_namePool)) { + m_context->error(QtXmlPatterns::tr("complex type %1 with simple content cannot be derived from complex base type %2") + .arg(formatType(m_namePool, complexType)) + .arg(formatType(m_namePool, baseType)), + XsdSchemaContext::XSDError, location); + return; + } + } + } +} + +void XsdSchemaChecker::checkSimpleDerivationRestrictions() +{ + // check all global types... + SchemaType::List types = m_schema->types(); + + // .. and anonymous types + types << m_schema->anonymousTypes(); + + for (int i = 0; i < types.count(); ++i) { + const SchemaType::Ptr type = types.at(i); + + if (type->isComplexType()) + continue; + + if (type->category() != SchemaType::SimpleTypeList && type->category() != SchemaType::SimpleTypeUnion) + continue; + + const XsdSimpleType::Ptr simpleType = type; + const QSourceLocation location = sourceLocation(simpleType); + + // check all simple types derived by list + if (simpleType->category() == XsdSimpleType::SimpleTypeList) { + const AnySimpleType::Ptr itemType = simpleType->itemType(); + + if (itemType->isComplexType()) { + m_context->error(QtXmlPatterns::tr("item type of simple type %1 cannot be a complex type") + .arg(formatType(m_namePool, simpleType)), + XsdSchemaContext::XSDError, location); + return; + } + + + if (itemType->isSimpleType() && itemType->isDefinedBySchema()) { + const XsdSimpleType::Ptr simpleItemType = itemType; + if (simpleItemType->derivationConstraints() & XsdSimpleType::ListConstraint) { + m_context->error(QtXmlPatterns::tr("%1 is not allowed to derive from %2 by list as the latter defines it as final") + .arg(formatType(m_namePool, simpleType)) + .arg(formatType(m_namePool, simpleItemType)), + XsdSchemaContext::XSDError, location); + return; + } + } + + // @see http://www.w3.org/TR/xmlschema-2/#cos-list-of-atomic + if (itemType->category() != SchemaType::SimpleTypeAtomic && itemType->category() != SchemaType::SimpleTypeUnion) { + m_context->error(QtXmlPatterns::tr("variety of item type of %1 must be either atomic or union").arg(formatType(m_namePool, simpleType)), XsdSchemaContext::XSDError, location); + return; + } + + if (itemType->category() == SchemaType::SimpleTypeUnion && itemType->isDefinedBySchema()) { + const XsdSimpleType::Ptr simpleItemType = itemType; + const AnySimpleType::List memberTypes = simpleItemType->memberTypes(); + for (int j = 0; j < memberTypes.count(); ++j) { + if (memberTypes.at(j)->category() != SchemaType::SimpleTypeAtomic) { + m_context->error(QtXmlPatterns::tr("variety of member types of %1 must be atomic").arg(formatType(m_namePool, simpleItemType)), XsdSchemaContext::XSDError, location); + return; + } + } + } + } + + // check all simple types derived by union + if (simpleType->category() == XsdSimpleType::SimpleTypeUnion) { + const AnySimpleType::List memberTypes = simpleType->memberTypes(); + + for (int i = 0; i < memberTypes.count(); ++i) { + const AnySimpleType::Ptr memberType = memberTypes.at(i); + + if (memberType->isComplexType()) { + m_context->error(QtXmlPatterns::tr("member type of simple type %1 cannot be a complex type") + .arg(formatType(m_namePool, simpleType)), + XsdSchemaContext::XSDError, location); + return; + } + + // @see http://www.w3.org/TR/xmlschema-2/#cos-no-circular-unions + if (simpleType->name(m_namePool) == memberType->name(m_namePool)) { + m_context->error(QtXmlPatterns::tr("%1 is not allowed to have a member type with the same name as itself") + .arg(formatType(m_namePool, simpleType)), + XsdSchemaContext::XSDError, location); + return; + } + + if (memberType->isSimpleType() && memberType->isDefinedBySchema()) { + const XsdSimpleType::Ptr simpleMemberType = memberType; + if (simpleMemberType->derivationConstraints() & XsdSimpleType::UnionConstraint) { + m_context->error(QtXmlPatterns::tr("%1 is not allowed to derive from %2 by union as the latter defines it as final") + .arg(formatType(m_namePool, simpleType)) + .arg(formatType(m_namePool, simpleMemberType)), + XsdSchemaContext::XSDError, location); + return; + } + } + } + } + } +} + +void XsdSchemaChecker::checkConstrainingFacets() +{ + // first the global simple types + const SchemaType::List types = m_schema->types(); + for (int i = 0; i < types.count(); ++i) { + if (!(types.at(i)->isSimpleType()) || !(types.at(i)->isDefinedBySchema())) + continue; + + const XsdSimpleType::Ptr simpleType = types.at(i); + checkConstrainingFacets(simpleType->facets(), simpleType); + } + + // and afterwards all anonymous simple types + const SchemaType::List anonymousTypes = m_schema->anonymousTypes(); + for (int i = 0; i < anonymousTypes.count(); ++i) { + if (!(anonymousTypes.at(i)->isSimpleType()) || !(anonymousTypes.at(i)->isDefinedBySchema())) + continue; + + const XsdSimpleType::Ptr simpleType = anonymousTypes.at(i); + checkConstrainingFacets(simpleType->facets(), simpleType); + } +} + +void XsdSchemaChecker::checkConstrainingFacets(const XsdFacet::Hash &facets, const XsdSimpleType::Ptr &simpleType) +{ + if (facets.isEmpty()) + return; + + SchemaType::Ptr comparableBaseType; + if (!simpleType->wxsSuperType()->isDefinedBySchema()) + comparableBaseType = simpleType->wxsSuperType(); + else + comparableBaseType = simpleType->primitiveType(); + + const XsdSchemaSourceLocationReflection reflection(sourceLocation(simpleType)); + + // start checks + if (facets.contains(XsdFacet::Length)) { + const XsdFacet::Ptr lengthFacet = facets.value(XsdFacet::Length); + const DerivedInteger<TypeNonNegativeInteger>::Ptr lengthValue = lengthFacet->value(); + + // @see http://www.w3.org/TR/xmlschema-2/#length-minLength-maxLength + if (facets.contains(XsdFacet::MinimumLength)) { + const XsdFacet::Ptr minLengthFacet = facets.value(XsdFacet::MinimumLength); + const DerivedInteger<TypeNonNegativeInteger>::Ptr minLengthValue = minLengthFacet->value(); + + bool foundSuperMinimumLength = false; + SchemaType::Ptr baseType = simpleType->wxsSuperType(); + while (baseType) { + const XsdFacet::Hash baseFacets = m_context->facetsForType(baseType); + if (baseFacets.contains(XsdFacet::MinimumLength) && !baseFacets.contains(XsdFacet::Length)) { + const DerivedInteger<TypeNonNegativeInteger>::Ptr superValue(baseFacets.value(XsdFacet::MinimumLength)->value()); + if (minLengthValue->toInteger() == superValue->toInteger()) { + foundSuperMinimumLength = true; + break; + } + } + + baseType = baseType->wxsSuperType(); + } + + if ((minLengthValue->toInteger() > lengthValue->toInteger()) || !foundSuperMinimumLength) { + m_context->error(QtXmlPatterns::tr("%1 facet collides with %2 facet") + .arg(formatKeyword("length")) + .arg(formatKeyword("minLength")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + + // @see http://www.w3.org/TR/xmlschema-2/#length-minLength-maxLength + if (facets.contains(XsdFacet::MaximumLength)) { + const XsdFacet::Ptr maxLengthFacet = facets.value(XsdFacet::MaximumLength); + const DerivedInteger<TypeNonNegativeInteger>::Ptr maxLengthValue = maxLengthFacet->value(); + + bool foundSuperMaximumLength = false; + SchemaType::Ptr baseType = simpleType->wxsSuperType(); + while (baseType) { + const XsdFacet::Hash baseFacets = m_context->facetsForType(baseType); + if (baseFacets.contains(XsdFacet::MaximumLength) && !baseFacets.contains(XsdFacet::Length)) { + const DerivedInteger<TypeNonNegativeInteger>::Ptr superValue(baseFacets.value(XsdFacet::MaximumLength)->value()); + if (maxLengthValue->toInteger() == superValue->toInteger()) { + foundSuperMaximumLength = true; + break; + } + } + + baseType = baseType->wxsSuperType(); + } + + if ((maxLengthValue->toInteger() < lengthValue->toInteger()) || !foundSuperMaximumLength) { + m_context->error(QtXmlPatterns::tr("%1 facet collides with %2 facet") + .arg(formatKeyword("length")) + .arg(formatKeyword("maxLength")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + + // @see http://www.w3.org/TR/xmlschema-2/#length-valid-restriction + if (simpleType->derivationMethod() == XsdSimpleType::DerivationRestriction) { + const XsdFacet::Hash baseFacets = m_context->facetsForType(simpleType->wxsSuperType()); + if (baseFacets.contains(XsdFacet::Length)) { + const DerivedInteger<TypeNonNegativeInteger>::Ptr baseValue = baseFacets.value(XsdFacet::Length)->value(); + if (lengthValue->toInteger() != baseValue->toInteger()) { + m_context->error(QtXmlPatterns::tr("%1 facet must have the same value as %2 facet of base type") + .arg(formatKeyword("length")) + .arg(formatKeyword("length")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + } + } + + if (facets.contains(XsdFacet::MinimumLength)) { + const XsdFacet::Ptr minLengthFacet = facets.value(XsdFacet::MinimumLength); + const DerivedInteger<TypeNonNegativeInteger>::Ptr minLengthValue = minLengthFacet->value(); + + if (facets.contains(XsdFacet::MaximumLength)) { + const XsdFacet::Ptr maxLengthFacet = facets.value(XsdFacet::MaximumLength); + const DerivedInteger<TypeNonNegativeInteger>::Ptr maxLengthValue = maxLengthFacet->value(); + + // @see http://www.w3.org/TR/xmlschema-2/#minLength-less-than-equal-to-maxLength + if (maxLengthValue->toInteger() < minLengthValue->toInteger()) { + m_context->error(QtXmlPatterns::tr("%1 facet collides with %2 facet") + .arg(formatKeyword("minLength")) + .arg(formatKeyword("maxLength")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + + // @see http://www.w3.org/TR/xmlschema-2/#minLength-valid-restriction + //TODO: check parent facets + } + + // @see http://www.w3.org/TR/xmlschema-2/#minLength-valid-restriction + if (simpleType->derivationMethod() == XsdSimpleType::DerivationRestriction) { + const XsdFacet::Hash baseFacets = m_context->facetsForType(simpleType->wxsSuperType()); + if (baseFacets.contains(XsdFacet::MinimumLength)) { + const DerivedInteger<TypeNonNegativeInteger>::Ptr baseValue = baseFacets.value(XsdFacet::MinimumLength)->value(); + if (minLengthValue->toInteger() < baseValue->toInteger()) { + m_context->error(QtXmlPatterns::tr("%1 facet must be equal or greater than %2 facet of base type") + .arg(formatKeyword("minLength")) + .arg(formatKeyword("minLength")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + } + } + if (facets.contains(XsdFacet::MaximumLength)) { + const XsdFacet::Ptr maxLengthFacet = facets.value(XsdFacet::MaximumLength); + const DerivedInteger<TypeNonNegativeInteger>::Ptr maxLengthValue = maxLengthFacet->value(); + + // @see http://www.w3.org/TR/xmlschema-2/#maxLength-valid-restriction + if (simpleType->derivationMethod() == XsdSimpleType::DerivationRestriction) { + const XsdFacet::Hash baseFacets = m_context->facetsForType(simpleType->wxsSuperType()); + if (baseFacets.contains(XsdFacet::MaximumLength)) { + const DerivedInteger<TypeNonNegativeInteger>::Ptr baseValue(baseFacets.value(XsdFacet::MaximumLength)->value()); + if (maxLengthValue->toInteger() > baseValue->toInteger()) { + m_context->error(QtXmlPatterns::tr("%1 facet must be less than or equal to %2 facet of base type") + .arg(formatKeyword("maxLength")) + .arg(formatKeyword("maxLength")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + } + } + if (facets.contains(XsdFacet::Pattern)) { + // we keep the patterns in separated facets + // @see http://www.w3.org/TR/xmlschema-2/#src-multiple-patterns + + // @see http://www.w3.org/TR/xmlschema-2/#cvc-pattern-valid + const XsdFacet::Ptr patternFacet = facets.value(XsdFacet::Pattern); + const AtomicValue::List multiValue = patternFacet->multiValue(); + + for (int i = 0; i < multiValue.count(); ++i) { + const DerivedString<TypeString>::Ptr value = multiValue.at(i); + const QRegExp exp = PatternPlatform::parsePattern(value->stringValue(), m_context, &reflection); + if (!exp.isValid()) { + m_context->error(QtXmlPatterns::tr("%1 facet contains invalid regular expression").arg(formatKeyword("pattern")), XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + } + if (facets.contains(XsdFacet::Enumeration)) { + // @see http://www.w3.org/TR/xmlschema-2/#src-multiple-enumerations + + const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration); + + if (BuiltinTypes::xsNOTATION->wxsTypeMatches(simpleType)) { + const AtomicValue::List notationNames = facet->multiValue(); + for (int k = 0; k < notationNames.count(); ++k) { + const QNameValue::Ptr notationName = notationNames.at(k); + if (!m_schema->notation(notationName->qName())) { + m_context->error(QtXmlPatterns::tr("unknown notation %1 used in %2 facet") + .arg(formatKeyword(m_namePool, notationName->qName())) + .arg(formatKeyword("enumeration")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + } + } + } else if (BuiltinTypes::xsQName->wxsTypeMatches(simpleType)) { + } else { + const XsdTypeChecker checker(m_context, QVector<QXmlName>(), sourceLocation(simpleType)); + + const AnySimpleType::Ptr baseType = simpleType->wxsSuperType(); + const XsdFacet::Hash baseFacets = XsdTypeChecker::mergedFacetsForType(baseType, m_context); + + const AtomicValue::List multiValue = facet->multiValue(); + for (int k = 0; k < multiValue.count(); ++k) { + const QString stringValue = multiValue.at(k)->as<DerivedString<TypeString> >()->stringValue(); + const QString actualValue = XsdTypeChecker::normalizedValue(stringValue, baseFacets); + + QString errorMsg; + if (!checker.isValidString(actualValue, baseType, errorMsg)) { + m_context->error(QtXmlPatterns::tr("%1 facet contains invalid value %2: %3") + .arg(formatKeyword("enumeration")) + .arg(formatData(stringValue)) + .arg(errorMsg), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + } + } + if (facets.contains(XsdFacet::WhiteSpace)) { + const XsdFacet::Ptr whiteSpaceFacet = facets.value(XsdFacet::WhiteSpace); + const DerivedString<TypeString>::Ptr whiteSpaceValue = whiteSpaceFacet->value(); + + // @see http://www.w3.org/TR/xmlschema-2/#whiteSpace-valid-restriction + if (simpleType->derivationMethod() == XsdSimpleType::DerivationRestriction) { + const XsdFacet::Hash baseFacets = m_context->facetsForType(simpleType->wxsSuperType()); + if (baseFacets.contains(XsdFacet::WhiteSpace)) { + const QString value = whiteSpaceValue->stringValue(); + const QString baseValue = DerivedString<TypeString>::Ptr(baseFacets.value(XsdFacet::WhiteSpace)->value())->stringValue(); + if (value == XsdSchemaToken::toString(XsdSchemaToken::Replace) || value == XsdSchemaToken::toString(XsdSchemaToken::Preserve)) { + if (baseValue == XsdSchemaToken::toString(XsdSchemaToken::Collapse)) { + m_context->error(QtXmlPatterns::tr("%1 facet cannot be %2 or %3 if %4 facet of base type is %5") + .arg(formatKeyword("whiteSpace")) + .arg(formatData("replace")) + .arg(formatData("preserve")) + .arg(formatKeyword("whiteSpace")) + .arg(formatData("collapse")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + if (value == XsdSchemaToken::toString(XsdSchemaToken::Preserve) && baseValue == XsdSchemaToken::toString(XsdSchemaToken::Replace)) { + m_context->error(QtXmlPatterns::tr("%1 facet cannot be %2 if %3 facet of base type is %4") + .arg(formatKeyword("whiteSpace")) + .arg(formatData("preserve")) + .arg(formatKeyword("whiteSpace")) + .arg(formatData("replace")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + } + } + if (facets.contains(XsdFacet::MaximumInclusive)) { + const XsdFacet::Ptr maxFacet = facets.value(XsdFacet::MaximumInclusive); + + // @see http://www.w3.org/TR/xmlschema-2/#minInclusive-less-than-equal-to-maxInclusive + if (facets.contains(XsdFacet::MinimumInclusive)) { + const XsdFacet::Ptr minFacet = facets.value(XsdFacet::MinimumInclusive); + + if (comparableBaseType) { + if (XsdSchemaHelper::constructAndCompare(minFacet->value(), AtomicComparator::OperatorGreaterThan, maxFacet->value(), comparableBaseType, m_context, &reflection)) { + m_context->error(QtXmlPatterns::tr("%1 facet must be less than or equal to %2 facet") + .arg(formatKeyword("minInclusive")) + .arg(formatKeyword("maxInclusive")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + } + + // @see http://www.w3.org/TR/xmlschema-2/#maxInclusive-valid-restriction + if (simpleType->derivationMethod() == XsdSimpleType::DerivationRestriction) { + const XsdFacet::Hash baseFacets = m_context->facetsForType(simpleType->wxsSuperType()); + if (baseFacets.contains(XsdFacet::MaximumInclusive)) { + const XsdFacet::Ptr baseFacet = baseFacets.value(XsdFacet::MaximumInclusive); + if (comparableBaseType) { + if (XsdSchemaHelper::constructAndCompare(maxFacet->value(), AtomicComparator::OperatorGreaterThan, baseFacet->value(), comparableBaseType, m_context, &reflection)) { + m_context->error(QtXmlPatterns::tr("%1 facet must be less than or equal to %2 facet of base type") + .arg(formatKeyword("maxInclusive")) + .arg(formatKeyword("maxInclusive")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + } + if (baseFacets.contains(XsdFacet::MaximumExclusive)) { + const XsdFacet::Ptr baseFacet = baseFacets.value(XsdFacet::MaximumExclusive); + if (comparableBaseType) { + if (XsdSchemaHelper::constructAndCompare(maxFacet->value(), AtomicComparator::OperatorGreaterOrEqual, baseFacet->value(), comparableBaseType, m_context, &reflection)) { + m_context->error(QtXmlPatterns::tr("%1 facet must be less than %2 facet of base type") + .arg(formatKeyword("maxInclusive")) + .arg(formatKeyword("maxExclusive")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + } + } + } + if (facets.contains(XsdFacet::MaximumExclusive)) { + const XsdFacet::Ptr maxFacet = facets.value(XsdFacet::MaximumExclusive); + + // @see http://www.w3.org/TR/xmlschema-2/#maxInclusive-maxExclusive + if (facets.contains(XsdFacet::MaximumInclusive)) { + m_context->error(QtXmlPatterns::tr("%1 facet and %2 facet cannot appear together") + .arg(formatKeyword("maxExclusive")) + .arg(formatKeyword("maxInclusive")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + + // @see http://www.w3.org/TR/xmlschema-2/#minExclusive-less-than-equal-to-maxExclusive + if (facets.contains(XsdFacet::MinimumExclusive)) { + const XsdFacet::Ptr minFacet = facets.value(XsdFacet::MinimumExclusive); + if (comparableBaseType) { + if (XsdSchemaHelper::constructAndCompare(minFacet->value(), AtomicComparator::OperatorGreaterThan, maxFacet->value(), comparableBaseType, m_context, &reflection)) { + m_context->error(QtXmlPatterns::tr("%1 facet must be less than or equal to %2 facet") + .arg(formatKeyword("minExclusive")) + .arg(formatKeyword("maxExclusive")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + } + + // @see http://www.w3.org/TR/xmlschema-2/#maxExclusive-valid-restriction + if (simpleType->derivationMethod() == XsdSimpleType::DerivationRestriction) { + const XsdFacet::Hash baseFacets = m_context->facetsForType(simpleType->wxsSuperType()); + if (baseFacets.contains(XsdFacet::MaximumExclusive)) { + const XsdFacet::Ptr baseFacet = baseFacets.value(XsdFacet::MaximumExclusive); + if (comparableBaseType) { + if (XsdSchemaHelper::constructAndCompare(maxFacet->value(), AtomicComparator::OperatorGreaterThan, baseFacet->value(), comparableBaseType, m_context, &reflection)) { + m_context->error(QtXmlPatterns::tr("%1 facet must be less than or equal to %2 facet of base type") + .arg(formatKeyword("maxExclusive")) + .arg(formatKeyword("maxExclusive")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + } + if (baseFacets.contains(XsdFacet::MaximumInclusive)) { + const XsdFacet::Ptr baseFacet = baseFacets.value(XsdFacet::MaximumInclusive); + if (comparableBaseType) { + if (XsdSchemaHelper::constructAndCompare(maxFacet->value(), AtomicComparator::OperatorGreaterThan, baseFacet->value(), comparableBaseType, m_context, &reflection)) { + m_context->error(QtXmlPatterns::tr("%1 facet must be less than or equal to %2 facet of base type") + .arg(formatKeyword("maxExclusive")) + .arg(formatKeyword("maxInclusive")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + } + if (baseFacets.contains(XsdFacet::MinimumInclusive)) { + const XsdFacet::Ptr baseFacet = baseFacets.value(XsdFacet::MinimumInclusive); + if (comparableBaseType) { + if (XsdSchemaHelper::constructAndCompare(maxFacet->value(), AtomicComparator::OperatorLessOrEqual, baseFacet->value(), comparableBaseType, m_context, &reflection)) { + m_context->error(QtXmlPatterns::tr("%1 facet must be greater than %2 facet of base type") + .arg(formatKeyword("maxExclusive")) + .arg(formatKeyword("minInclusive")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + } + if (baseFacets.contains(XsdFacet::MinimumExclusive)) { + const XsdFacet::Ptr baseFacet = baseFacets.value(XsdFacet::MinimumExclusive); + if (comparableBaseType) { + if (XsdSchemaHelper::constructAndCompare(maxFacet->value(), AtomicComparator::OperatorLessOrEqual, baseFacet->value(), comparableBaseType, m_context, &reflection)) { + m_context->error(QtXmlPatterns::tr("%1 facet must be greater than %2 facet of base type") + .arg(formatKeyword("maxExclusive")) + .arg(formatKeyword("minExclusive")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + } + } + } + if (facets.contains(XsdFacet::MinimumExclusive)) { + const XsdFacet::Ptr minFacet = facets.value(XsdFacet::MinimumExclusive); + + // @see http://www.w3.org/TR/xmlschema-2/#minInclusive-minExclusive + if (facets.contains(XsdFacet::MinimumInclusive)) { + m_context->error(QtXmlPatterns::tr("%1 facet and %2 facet cannot appear together") + .arg(formatKeyword("minExclusive")) + .arg(formatKeyword("minInclusive")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + + // @see http://www.w3.org/TR/xmlschema-2/#minExclusive-less-than-maxInclusive + if (facets.contains(XsdFacet::MaximumInclusive)) { + const XsdFacet::Ptr maxFacet = facets.value(XsdFacet::MaximumInclusive); + if (comparableBaseType) { + if (XsdSchemaHelper::constructAndCompare(minFacet->value(), AtomicComparator::OperatorGreaterOrEqual, maxFacet->value(), comparableBaseType, m_context, &reflection)) { + m_context->error(QtXmlPatterns::tr("%1 facet must be less than %2 facet") + .arg(formatKeyword("minExclusive")) + .arg(formatKeyword("maxInclusive")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + } + + // @see http://www.w3.org/TR/xmlschema-2/#minExclusive-valid-restriction + if (simpleType->derivationMethod() == XsdSimpleType::DerivationRestriction) { + const XsdFacet::Hash baseFacets = m_context->facetsForType(simpleType->wxsSuperType()); + if (baseFacets.contains(XsdFacet::MinimumExclusive)) { + const XsdFacet::Ptr baseFacet = baseFacets.value(XsdFacet::MinimumExclusive); + if (comparableBaseType) { + if (XsdSchemaHelper::constructAndCompare(minFacet->value(), AtomicComparator::OperatorLessThan, baseFacet->value(), comparableBaseType, m_context, &reflection)) { + m_context->error(QtXmlPatterns::tr("%1 facet must be greater than or equal to %2 facet of base type") + .arg(formatKeyword("minExclusive")) + .arg(formatKeyword("minExclusive")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + } + if (baseFacets.contains(XsdFacet::MaximumExclusive)) { + const XsdFacet::Ptr baseFacet = baseFacets.value(XsdFacet::MaximumExclusive); + if (comparableBaseType) { + if (XsdSchemaHelper::constructAndCompare(minFacet->value(), AtomicComparator::OperatorGreaterOrEqual, baseFacet->value(), comparableBaseType, m_context, &reflection)) { + m_context->error(QtXmlPatterns::tr("%1 facet must be less than %2 facet of base type") + .arg(formatKeyword("minExclusive")) + .arg(formatKeyword("maxExclusive")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + } + if (baseFacets.contains(XsdFacet::MaximumInclusive)) { + const XsdFacet::Ptr baseFacet = baseFacets.value(XsdFacet::MaximumInclusive); + if (comparableBaseType) { + if (XsdSchemaHelper::constructAndCompare(minFacet->value(), AtomicComparator::OperatorGreaterThan, baseFacet->value(), comparableBaseType, m_context, &reflection)) { + m_context->error(QtXmlPatterns::tr("%1 facet must be less than or equal to %2 facet of base type") + .arg(formatKeyword("minExclusive")) + .arg(formatKeyword("maxInclusive")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + } + } + } + if (facets.contains(XsdFacet::MinimumInclusive)) { + const XsdFacet::Ptr minFacet = facets.value(XsdFacet::MinimumInclusive); + + // @see http://www.w3.org/TR/xmlschema-2/#minInclusive-less-than-maxExclusive + if (facets.contains(XsdFacet::MaximumExclusive)) { + const XsdFacet::Ptr maxFacet = facets.value(XsdFacet::MaximumExclusive); + if (comparableBaseType) { + if (XsdSchemaHelper::constructAndCompare(minFacet->value(), AtomicComparator::OperatorGreaterOrEqual, maxFacet->value(), comparableBaseType, m_context, &reflection)) { + m_context->error(QtXmlPatterns::tr("%1 facet must be less than %2 facet") + .arg(formatKeyword("minInclusive")) + .arg(formatKeyword("maxExclusive")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + } + + // @see http://www.w3.org/TR/xmlschema-2/#minInclusive-valid-restriction + if (simpleType->derivationMethod() == XsdSimpleType::DerivationRestriction) { + const XsdFacet::Hash baseFacets = m_context->facetsForType(simpleType->wxsSuperType()); + if (baseFacets.contains(XsdFacet::MinimumInclusive)) { + const XsdFacet::Ptr baseFacet = baseFacets.value(XsdFacet::MinimumInclusive); + if (comparableBaseType) { + if (XsdSchemaHelper::constructAndCompare(minFacet->value(), AtomicComparator::OperatorLessThan, baseFacet->value(), comparableBaseType, m_context, &reflection)) { + m_context->error(QtXmlPatterns::tr("%1 facet must be greater than or equal to %2 facet of base type") + .arg(formatKeyword("minInclusive")) + .arg(formatKeyword("minInclusive")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + } + if (baseFacets.contains(XsdFacet::MinimumExclusive)) { + const XsdFacet::Ptr baseFacet = baseFacets.value(XsdFacet::MinimumExclusive); + if (comparableBaseType) { + if (XsdSchemaHelper::constructAndCompare(minFacet->value(), AtomicComparator::OperatorLessOrEqual, baseFacet->value(), comparableBaseType, m_context, &reflection)) { + m_context->error(QtXmlPatterns::tr("%1 facet must be greater than %2 facet of base type") + .arg(formatKeyword("minInclusive")) + .arg(formatKeyword("minExclusive")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + } + if (baseFacets.contains(XsdFacet::MaximumInclusive)) { + const XsdFacet::Ptr baseFacet = baseFacets.value(XsdFacet::MaximumInclusive); + if (comparableBaseType) { + if (XsdSchemaHelper::constructAndCompare(minFacet->value(), AtomicComparator::OperatorGreaterThan, baseFacet->value(), comparableBaseType, m_context, &reflection)) { + m_context->error(QtXmlPatterns::tr("%1 facet must be less than or equal to %2 facet of base type") + .arg(formatKeyword("minInclusive")) + .arg(formatKeyword("maxInclusive")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + } + if (baseFacets.contains(XsdFacet::MaximumExclusive)) { + const XsdFacet::Ptr baseFacet = baseFacets.value(XsdFacet::MaximumExclusive); + if (comparableBaseType) { + if (XsdSchemaHelper::constructAndCompare(minFacet->value(), AtomicComparator::OperatorGreaterOrEqual, baseFacet->value(), comparableBaseType, m_context, &reflection)) { + m_context->error(QtXmlPatterns::tr("%1 facet must be less than %2 facet of base type") + .arg(formatKeyword("minInclusive")) + .arg(formatKeyword("maxExclusive")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + } + } + } + if (facets.contains(XsdFacet::TotalDigits)) { + const XsdFacet::Ptr totalDigitsFacet = facets.value(XsdFacet::TotalDigits); + const DerivedInteger<TypeNonNegativeInteger>::Ptr totalDigitsValue = totalDigitsFacet->value(); + + // @see http://www.w3.org/TR/xmlschema-2/#totalDigits-valid-restriction + if (simpleType->derivationMethod() == XsdSimpleType::DerivationRestriction) { + const XsdFacet::Hash baseFacets = m_context->facetsForType(simpleType->wxsSuperType()); + if (baseFacets.contains(XsdFacet::TotalDigits)) { + const XsdFacet::Ptr baseFacet = baseFacets.value(XsdFacet::TotalDigits); + const DerivedInteger<TypeNonNegativeInteger>::Ptr baseValue = baseFacet->value(); + + if (totalDigitsValue->toInteger() > baseValue->toInteger()) { + m_context->error(QtXmlPatterns::tr("%1 facet must be less than or equal to %2 facet of base type") + .arg(formatKeyword("totalDigits")) + .arg(formatKeyword("totalDigits")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + } + } + if (facets.contains(XsdFacet::FractionDigits)) { + const XsdFacet::Ptr fractionDigitsFacet = facets.value(XsdFacet::FractionDigits); + const DerivedInteger<TypeNonNegativeInteger>::Ptr fractionDigitsValue = fractionDigitsFacet->value(); + + // http://www.w3.org/TR/xmlschema-2/#fractionDigits-totalDigits + if (facets.contains(XsdFacet::TotalDigits)) { + const XsdFacet::Ptr totalDigitsFacet = facets.value(XsdFacet::TotalDigits); + const DerivedInteger<TypeNonNegativeInteger>::Ptr totalDigitsValue = totalDigitsFacet->value(); + + if (fractionDigitsValue->toInteger() > totalDigitsValue->toInteger()) { + m_context->error(QtXmlPatterns::tr("%1 facet must be less than or equal to %2 facet") + .arg(formatKeyword("fractionDigits")) + .arg(formatKeyword("totalDigits")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + + // @see http://www.w3.org/TR/xmlschema-2/#fractionDigits-valid-restriction + if (simpleType->derivationMethod() == XsdSimpleType::DerivationRestriction) { + const XsdFacet::Hash baseFacets = m_context->facetsForType(simpleType->wxsSuperType()); + if (baseFacets.contains(XsdFacet::FractionDigits)) { + const XsdFacet::Ptr baseFacet = baseFacets.value(XsdFacet::FractionDigits); + const DerivedInteger<TypeNonNegativeInteger>::Ptr baseValue = baseFacet->value(); + + if (fractionDigitsValue->toInteger() > baseValue->toInteger()) { + m_context->error(QtXmlPatterns::tr("%1 facet must be less than or equal to %2 facet of base type") + .arg(formatKeyword("fractionDigits")) + .arg(formatKeyword("fractionDigits")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + } + } + + + // check whether facets are allowed for simple types variety + if (simpleType->wxsSuperType()->category() == SchemaType::SimpleTypeAtomic) { + if (simpleType->primitiveType()) { + const QXmlName primitiveTypeName = simpleType->primitiveType()->name(m_namePool); + if (m_allowedAtomicFacets.contains(primitiveTypeName)) { + const QSet<XsdFacet::Type> allowedFacets = m_allowedAtomicFacets.value(primitiveTypeName); + QSet<XsdFacet::Type> availableFacets = facets.keys().toSet(); + + if (!availableFacets.subtract(allowedFacets).isEmpty()) { + m_context->error(QtXmlPatterns::tr("simple type contains not allowed facet %1") + .arg(formatKeyword(XsdFacet::typeName(availableFacets.toList().first()))), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + } + } else if (simpleType->wxsSuperType()->category() == SchemaType::SimpleTypeList) { + if (facets.contains(XsdFacet::MaximumInclusive) || facets.contains(XsdFacet::MinimumInclusive) || + facets.contains(XsdFacet::MaximumExclusive) || facets.contains(XsdFacet::MinimumExclusive) || + facets.contains(XsdFacet::TotalDigits) || facets.contains(XsdFacet::FractionDigits)) + { + m_context->error(QtXmlPatterns::tr("%1, %2, %3, %4, %5 and %6 facets are not allowed when derived by list") + .arg(formatKeyword("maxInclusive")) + .arg(formatKeyword("maxExclusive")) + .arg(formatKeyword("minInclusive")) + .arg(formatKeyword("minExclusive")) + .arg(formatKeyword("totalDigits")) + .arg(formatKeyword("fractionDigits")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + } + } else if (simpleType->wxsSuperType()->category() == SchemaType::SimpleTypeUnion) { + if (facets.contains(XsdFacet::MaximumInclusive) || facets.contains(XsdFacet::MinimumInclusive) || + facets.contains(XsdFacet::MaximumExclusive) || facets.contains(XsdFacet::MinimumExclusive) || + facets.contains(XsdFacet::TotalDigits) || facets.contains(XsdFacet::FractionDigits) || + facets.contains(XsdFacet::MinimumLength) || facets.contains(XsdFacet::MaximumLength) || + facets.contains(XsdFacet::Length) || facets.contains(XsdFacet::WhiteSpace)) + { + m_context->error(QtXmlPatterns::tr("only %1 and %2 facets are allowed when derived by union") + .arg(formatKeyword("pattern")) + .arg(formatKeyword("enumeration")), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + } + } + + // check whether value of facet matches the value space of the simple types base type + const SchemaType::Ptr baseType = simpleType->wxsSuperType(); + if (!baseType->isDefinedBySchema()) { + const XsdSchemaSourceLocationReflection reflection(sourceLocation(simpleType)); + + XsdFacet::HashIterator it(facets); + while (it.hasNext()) { + it.next(); + const XsdFacet::Ptr facet = it.value(); + if (facet->type() == XsdFacet::MaximumInclusive || + facet->type() == XsdFacet::MaximumExclusive || + facet->type() == XsdFacet::MinimumInclusive || + facet->type() == XsdFacet::MinimumExclusive) { + const DerivedString<TypeString>::Ptr stringValue = facet->value(); + const AtomicValue::Ptr value = ValueFactory::fromLexical(stringValue->stringValue(), baseType, m_context, &reflection); + if (value->hasError()) { + m_context->error(QtXmlPatterns::tr("%1 contains %2 facet with invalid data: %3") + .arg(formatType(m_namePool, simpleType)) + .arg(formatKeyword(XsdFacet::typeName(facet->type()))) + .arg(formatData(stringValue->stringValue())), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + + // @see http://www.w3.org/TR/xmlschema-2/#enumeration-valid-restriction + if (facet->type() == XsdFacet::Enumeration && baseType != BuiltinTypes::xsNOTATION) { + const AtomicValue::List multiValue = facet->multiValue(); + for (int j = 0; j < multiValue.count(); ++j) { + const QString stringValue = DerivedString<TypeString>::Ptr(multiValue.at(j))->stringValue(); + const AtomicValue::Ptr value = ValueFactory::fromLexical(stringValue, baseType, m_context, &reflection); + if (value->hasError()) { + m_context->error(QtXmlPatterns::tr("%1 contains %2 facet with invalid data: %3") + .arg(formatType(m_namePool, simpleType)) + .arg(formatKeyword(XsdFacet::typeName(XsdFacet::Enumeration))) + .arg(formatData(stringValue)), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + } + } + } + } +} + +void XsdSchemaChecker::checkDuplicatedAttributeUses() +{ + // first all global attribute groups + const XsdAttributeGroup::List attributeGroups = m_schema->attributeGroups(); + for (int i = 0; i < attributeGroups.count(); ++i) { + const XsdAttributeGroup::Ptr attributeGroup = attributeGroups.at(i); + const XsdAttributeUse::List uses = attributeGroup->attributeUses(); + + // @see http://www.w3.org/TR/xmlschema11-1/#ct-props-correct 4) + XsdAttribute::Ptr conflictingAttribute; + if (hasDuplicatedAttributeUses(uses, conflictingAttribute)) { + m_context->error(QtXmlPatterns::tr("attribute group %1 contains attribute %2 twice") + .arg(formatKeyword(attributeGroup->displayName(m_namePool))) + .arg(formatKeyword(conflictingAttribute->displayName(m_namePool))), + XsdSchemaContext::XSDError, sourceLocation(attributeGroup)); + return; + } + + // @see http://www.w3.org/TR/xmlschema11-1/#ct-props-correct 5) + if (hasMultipleIDAttributeUses(uses)) { + m_context->error(QtXmlPatterns::tr("attribute group %1 contains two different attributes that both have types derived from %2") + .arg(formatKeyword(attributeGroup->displayName(m_namePool))) + .arg(formatType(m_namePool, BuiltinTypes::xsID)), + XsdSchemaContext::XSDError, sourceLocation(attributeGroup)); + return; + } + + if (hasConstraintIDAttributeUse(uses, conflictingAttribute)) { + m_context->error(QtXmlPatterns::tr("attribute group %1 contains attribute %2 that has value constraint but type that inherits from %3") + .arg(formatKeyword(attributeGroup->displayName(m_namePool))) + .arg(formatKeyword(conflictingAttribute->displayName(m_namePool))) + .arg(formatType(m_namePool, BuiltinTypes::xsID)), + XsdSchemaContext::XSDError, sourceLocation(attributeGroup)); + return; + } + } + + // then the global and anonymous complex types + SchemaType::List types = m_schema->types(); + types << m_schema->anonymousTypes(); + + for (int i = 0; i < types.count(); ++i) { + if (!(types.at(i)->isComplexType()) || !types.at(i)->isDefinedBySchema()) + continue; + + const XsdComplexType::Ptr complexType = types.at(i); + const XsdAttributeUse::List attributeUses = complexType->attributeUses(); + + // @see http://www.w3.org/TR/xmlschema11-1/#ct-props-correct 4) + XsdAttribute::Ptr conflictingAttribute; + if (hasDuplicatedAttributeUses(attributeUses, conflictingAttribute)) { + m_context->error(QtXmlPatterns::tr("complex type %1 contains attribute %2 twice") + .arg(formatType(m_namePool, complexType)) + .arg(formatKeyword(conflictingAttribute->displayName(m_namePool))), + XsdSchemaContext::XSDError, sourceLocation(complexType)); + return; + } + + // @see http://www.w3.org/TR/xmlschema11-1/#ct-props-correct 5) + if (hasMultipleIDAttributeUses(attributeUses)) { + m_context->error(QtXmlPatterns::tr("complex type %1 contains two different attributes that both have types derived from %2") + .arg(formatType(m_namePool, complexType)) + .arg(formatType(m_namePool, BuiltinTypes::xsID)), + XsdSchemaContext::XSDError, sourceLocation(complexType)); + return; + } + + if (hasConstraintIDAttributeUse(attributeUses, conflictingAttribute)) { + m_context->error(QtXmlPatterns::tr("complex type %1 contains attribute %2 that has value constraint but type that inherits from %3") + .arg(formatType(m_namePool, complexType)) + .arg(formatKeyword(conflictingAttribute->displayName(m_namePool))) + .arg(formatType(m_namePool, BuiltinTypes::xsID)), + XsdSchemaContext::XSDError, sourceLocation(complexType)); + return; + } + } +} + +void XsdSchemaChecker::checkElementConstraints() +{ + const QSet<XsdElement::Ptr> elements = collectAllElements(m_schema); + QSetIterator<XsdElement::Ptr> it(elements); + while (it.hasNext()) { + const XsdElement::Ptr element = it.next(); + + // @see http://www.w3.org/TR/xmlschema11-1/#e-props-correct + + // 2 and xs:ID check + if (element->valueConstraint()) { + const SchemaType::Ptr type = element->type(); + + AnySimpleType::Ptr targetType; + if (type->isSimpleType() && type->category() == SchemaType::SimpleTypeAtomic) { + targetType = type; + + // if it is a XsdSimpleType, use its primitive type as target type + if (type->isDefinedBySchema()) + targetType = XsdSimpleType::Ptr(type)->primitiveType(); + + } else if (type->isComplexType() && type->isDefinedBySchema()) { + const XsdComplexType::Ptr complexType(type); + + if (complexType->contentType()->variety() == XsdComplexType::ContentType::Simple) { + const AnySimpleType::Ptr simpleType = complexType->contentType()->simpleType(); + if (simpleType->category() == AnySimpleType::SimpleTypeAtomic) { + targetType = simpleType; + + if (simpleType->isDefinedBySchema()) + targetType = XsdSimpleType::Ptr(simpleType)->primitiveType(); + } + } else if (complexType->contentType()->variety() != XsdComplexType::ContentType::Mixed) { + m_context->error(QtXmlPatterns::tr("element %1 is not allowed to have a value constraint if its base type is complex") + .arg(formatKeyword(element->displayName(m_namePool))), + XsdSchemaContext::XSDError, sourceLocation(element)); + return; + } + } + if ((targetType == BuiltinTypes::xsID) || BuiltinTypes::xsID->wxsTypeMatches(type)) { + m_context->error(QtXmlPatterns::tr("element %1 is not allowed to have a value constraint if its type is derived from %2") + .arg(formatKeyword(element->displayName(m_namePool))) + .arg(formatType(m_namePool, BuiltinTypes::xsID)), + XsdSchemaContext::XSDError, sourceLocation(element)); + return; + } + + if (type->isSimpleType()) { + QString errorMsg; + if (!isValidValue(element->valueConstraint()->value(), type, errorMsg)) { + m_context->error(QtXmlPatterns::tr("value constraint of element %1 is not of elements type: %2") + .arg(formatKeyword(element->displayName(m_namePool))) + .arg(errorMsg), + XsdSchemaContext::XSDError, sourceLocation(element)); + return; + } + } else if (type->isComplexType() && type->isDefinedBySchema()) { + const XsdComplexType::Ptr complexType(type); + if (complexType->contentType()->variety() == XsdComplexType::ContentType::Simple) { + QString errorMsg; + if (!isValidValue(element->valueConstraint()->value(), complexType->contentType()->simpleType(), errorMsg)) { + m_context->error(QtXmlPatterns::tr("value constraint of element %1 is not of elements type: %2") + .arg(formatKeyword(element->displayName(m_namePool))) + .arg(errorMsg), + XsdSchemaContext::XSDError, sourceLocation(element)); + return; + } + } + } + } + + if (!element->substitutionGroupAffiliations().isEmpty()) { + // 3 + if (!element->scope() || element->scope()->variety() != XsdElement::Scope::Global) { + m_context->error(QtXmlPatterns::tr("element %1 is not allowed to have substitution group affiliation as it is no global element").arg(formatKeyword(element->displayName(m_namePool))), + XsdSchemaContext::XSDError, sourceLocation(element)); + return; + } + + // 4 + const XsdElement::List affiliations = element->substitutionGroupAffiliations(); + for (int i = 0; i < affiliations.count(); ++i) { + const XsdElement::Ptr affiliation = affiliations.at(i); + + bool derivationOk = false; + if (element->type()->isComplexType() && affiliation->type()->isComplexType()) { + if (XsdSchemaHelper::isComplexDerivationOk(element->type(), affiliation->type(), affiliation->substitutionGroupExclusions())) { + derivationOk = true; + } + } + if (element->type()->isComplexType() && affiliation->type()->isSimpleType()) { + if (XsdSchemaHelper::isComplexDerivationOk(element->type(), affiliation->type(), affiliation->substitutionGroupExclusions())) { + derivationOk = true; + } + } + if (element->type()->isSimpleType()) { + if (XsdSchemaHelper::isSimpleDerivationOk(element->type(), affiliation->type(), affiliation->substitutionGroupExclusions())) { + derivationOk = true; + } + } + + if (!derivationOk) { + m_context->error(QtXmlPatterns::tr("type of element %1 cannot be derived from type of substitution group affiliation").arg(formatKeyword(element->displayName(m_namePool))), + XsdSchemaContext::XSDError, sourceLocation(element)); + return; + } + } + + // 5 was checked in XsdSchemaResolver::resolveSubstitutionGroupAffiliations() already + } + } +} + +void XsdSchemaChecker::checkAttributeConstraints() +{ + // all global attributes + XsdAttribute::List attributes = m_schema->attributes(); + + // and all local attributes + SchemaType::List types = m_schema->types(); + types << m_schema->anonymousTypes(); + + for (int i = 0; i < types.count(); ++i) { + if (!types.at(i)->isComplexType() || !types.at(i)->isDefinedBySchema()) + continue; + + const XsdComplexType::Ptr complexType(types.at(i)); + const XsdAttributeUse::List uses = complexType->attributeUses(); + for (int j = 0; j < uses.count(); ++j) + attributes.append(uses.at(j)->attribute()); + } + + for (int i = 0; i < attributes.count(); ++i) { + const XsdAttribute::Ptr attribute = attributes.at(i); + + if (!attribute->valueConstraint()) + continue; + + if (attribute->valueConstraint()->variety() == XsdAttribute::ValueConstraint::Default || attribute->valueConstraint()->variety() == XsdAttribute::ValueConstraint::Fixed) { + const SchemaType::Ptr type = attribute->type(); + + QString errorMsg; + if (!isValidValue(attribute->valueConstraint()->value(), attribute->type(), errorMsg)) { + m_context->error(QtXmlPatterns::tr("value constraint of attribute %1 is not of attributes type: %2") + .arg(formatKeyword(attribute->displayName(m_namePool))) + .arg(errorMsg), + XsdSchemaContext::XSDError, sourceLocation(attribute)); + return; + } + } + + if (BuiltinTypes::xsID->wxsTypeMatches(attribute->type())) { + m_context->error(QtXmlPatterns::tr("attribute %1 has value constraint but has type derived from %2") + .arg(formatKeyword(attribute->displayName(m_namePool))) + .arg(formatType(m_namePool, BuiltinTypes::xsID)), + XsdSchemaContext::XSDError, sourceLocation(attribute)); + return; + } + } +} + +bool XsdSchemaChecker::isValidValue(const QString &stringValue, const AnySimpleType::Ptr &type, QString &errorMsg) const +{ + if (BuiltinTypes::xsAnySimpleType->name(m_namePool) == type->name(m_namePool)) + return true; // no need to check xs:anyType content + + const XsdFacet::Hash facets = XsdTypeChecker::mergedFacetsForType(type, m_context); + const QString actualValue = XsdTypeChecker::normalizedValue(stringValue, facets); + + const XsdTypeChecker checker(m_context, QVector<QXmlName>(), QSourceLocation(QUrl(QLatin1String("http://dummy.org")), 1, 1)); + return checker.isValidString(actualValue, type, errorMsg); +} + +void XsdSchemaChecker::checkAttributeUseConstraints() +{ + XsdComplexType::List complexTypes; + + SchemaType::List types = m_schema->types(); + types << m_schema->anonymousTypes(); + + for (int i = 0; i < types.count(); ++i) { + const SchemaType::Ptr type = types.at(i); + if (type->isComplexType() && type->isDefinedBySchema()) + complexTypes.append(XsdComplexType::Ptr(type)); + } + + for (int i = 0; i < complexTypes.count(); ++i) { + const XsdComplexType::Ptr complexType(complexTypes.at(i)); + const SchemaType::Ptr baseType = complexType->wxsSuperType(); + if (!baseType || !baseType->isComplexType() || !baseType->isDefinedBySchema()) + continue; + + const XsdComplexType::Ptr complexBaseType(baseType); + + const XsdAttributeUse::List attributeUses = complexType->attributeUses(); + QHash<QXmlName, XsdAttributeUse::Ptr> lookupHash; + for (int j = 0; j < attributeUses.count(); ++j) + lookupHash.insert(attributeUses.at(j)->attribute()->name(m_namePool), attributeUses.at(j)); + + const XsdAttributeUse::List baseAttributeUses = complexBaseType->attributeUses(); + for (int j = 0; j < baseAttributeUses.count(); ++j) { + const XsdAttributeUse::Ptr baseAttributeUse = baseAttributeUses.at(j); + + if (lookupHash.contains(baseAttributeUse->attribute()->name(m_namePool))) { + const XsdAttributeUse::Ptr attributeUse = lookupHash.value(baseAttributeUse->attribute()->name(m_namePool)); + + if (baseAttributeUse->useType() == XsdAttributeUse::RequiredUse) { + if (attributeUse->useType() == XsdAttributeUse::OptionalUse || attributeUse->useType() == XsdAttributeUse::ProhibitedUse) { + m_context->error(QtXmlPatterns::tr("%1 attribute in derived complex type must be %2 like in base type") + .arg(formatAttribute("use")) + .arg(formatData("required")), + XsdSchemaContext::XSDError, sourceLocation(complexType)); + return; + } + } + + if (baseAttributeUse->valueConstraint()) { + if (baseAttributeUse->valueConstraint()->variety() == XsdAttributeUse::ValueConstraint::Fixed) { + if (!attributeUse->valueConstraint()) { + m_context->error(QtXmlPatterns::tr("attribute %1 in derived complex type must have %2 value constraint like in base type") + .arg(formatKeyword(attributeUse->attribute()->displayName(m_namePool))) + .arg(formatData("fixed")), + XsdSchemaContext::XSDError, sourceLocation(complexType)); + return; + } else { + if (attributeUse->valueConstraint()->variety() == XsdAttributeUse::ValueConstraint::Fixed) { + const XsdTypeChecker checker(m_context, QVector<QXmlName>(), sourceLocation(complexType)); + if (!checker.valuesAreEqual(attributeUse->valueConstraint()->value(), baseAttributeUse->valueConstraint()->value(), attributeUse->attribute()->type())) { + m_context->error(QtXmlPatterns::tr("attribute %1 in derived complex type must have the same %2 value constraint like in base type") + .arg(formatKeyword(attributeUse->attribute()->displayName(m_namePool))) + .arg(formatData("fixed")), + XsdSchemaContext::XSDError, sourceLocation(complexType)); + return; + } + } else { + m_context->error(QtXmlPatterns::tr("attribute %1 in derived complex type must have %2 value constraint") + .arg(formatKeyword(attributeUse->attribute()->displayName(m_namePool))) + .arg(formatData("fixed")), + XsdSchemaContext::XSDError, sourceLocation(complexType)); + return; + } + } + } + } + } + } + + // additional check that process content property of attribute wildcard in derived type is + // not weaker than the wildcard in base type + const XsdWildcard::Ptr baseWildcard(complexBaseType->attributeWildcard()); + const XsdWildcard::Ptr derivedWildcard(complexType->attributeWildcard()); + if (baseWildcard && derivedWildcard) { + if (!XsdSchemaHelper::checkWildcardProcessContents(baseWildcard, derivedWildcard)) { + m_context->error(QtXmlPatterns::tr("processContent of base wildcard must be weaker than derived wildcard"), XsdSchemaContext::XSDError, sourceLocation(complexType)); + return; + } + } + } +} + +void XsdSchemaChecker::checkElementDuplicates() +{ + // check all global types... + SchemaType::List types = m_schema->types(); + + // .. and anonymous types + types << m_schema->anonymousTypes(); + + for (int i = 0; i < types.count(); ++i) { + const SchemaType::Ptr type = types.at(i); + + if (!type->isComplexType() || !type->isDefinedBySchema()) + continue; + + const XsdComplexType::Ptr complexType(type); + + if ((complexType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly) || (complexType->contentType()->variety() == XsdComplexType::ContentType::Mixed)) { + DuplicatedElementMap elementMap; + DuplicatedWildcardMap wildcardMap; + + checkElementDuplicates(complexType->contentType()->particle(), elementMap, wildcardMap); + } + } +} + +void XsdSchemaChecker::checkElementDuplicates(const XsdParticle::Ptr &particle, DuplicatedElementMap &elementMap, DuplicatedWildcardMap &wildcardMap) +{ + if (particle->term()->isElement()) { + const XsdElement::Ptr element(particle->term()); + + if (elementMap.contains(element->name(m_namePool))) { + if (element->type() != elementMap.value(element->name(m_namePool))) { + m_context->error(QtXmlPatterns::tr("element %1 exists twice with different types") + .arg(formatKeyword(element->displayName(m_namePool))), + XsdSchemaContext::XSDError, sourceLocation(element)); + return; + } + } else { + elementMap.insert(element->name(m_namePool), element->type()); + } + + // check substitution group affiliation + const XsdElement::List substElements = element->substitutionGroupAffiliations(); + for (int i = 0; i < substElements.count(); ++i) { + const XsdElement::Ptr substElement = substElements.at(i); + if (elementMap.contains(substElement->name(m_namePool))) { + if (substElement->type() != elementMap.value(substElement->name(m_namePool))) { + m_context->error(QtXmlPatterns::tr("element %1 exists twice with different types") + .arg(formatKeyword(substElement->displayName(m_namePool))), + XsdSchemaContext::XSDError, sourceLocation(element)); + return; + } + } else { + elementMap.insert(substElement->name(m_namePool), substElement->type()); + } + } + } else if (particle->term()->isModelGroup()) { + const XsdModelGroup::Ptr group(particle->term()); + const XsdParticle::List particles = group->particles(); + for (int i = 0; i < particles.count(); ++i) + checkElementDuplicates(particles.at(i), elementMap, wildcardMap); + } else if (particle->term()->isWildcard()) { + const XsdWildcard::Ptr wildcard(particle->term()); + + bool error = false; + if (!wildcardMap.contains(wildcard->namespaceConstraint()->variety())) { + if (!wildcardMap.isEmpty()) + error = true; + } else { + const XsdWildcard::Ptr otherWildcard = wildcardMap.value(wildcard->namespaceConstraint()->variety()); + if ((wildcard->processContents() != otherWildcard->processContents()) || (wildcard->namespaceConstraint()->namespaces() != otherWildcard->namespaceConstraint()->namespaces())) + error = true; + } + + if (error) { + m_context->error(QtXmlPatterns::tr("particle contains non-deterministic wildcards"), XsdSchemaContext::XSDError, sourceLocation(wildcard)); + return; + } else { + wildcardMap.insert(wildcard->namespaceConstraint()->variety(), wildcard); + } + } +} + +QSourceLocation XsdSchemaChecker::sourceLocation(const NamedSchemaComponent::Ptr &component) const +{ + if (m_componentLocationHash.contains(component)) { + return m_componentLocationHash.value(component); + } else { + QSourceLocation location; + location.setLine(1); + location.setColumn(1); + location.setUri(QString::fromLatin1("dummyUri")); + + return location; + } +} + +QSourceLocation XsdSchemaChecker::sourceLocationForType(const SchemaType::Ptr &type) const +{ + if (type->isSimpleType()) + return sourceLocation(XsdSimpleType::Ptr(type)); + else + return sourceLocation(XsdComplexType::Ptr(type)); +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdschemachecker_helper.cpp b/src/xmlpatterns/schema/qxsdschemachecker_helper.cpp new file mode 100644 index 0000000..28957b7 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdschemachecker_helper.cpp @@ -0,0 +1,306 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +bool XsdSchemaChecker::hasDuplicatedAttributeUses(const XsdAttributeUse::List &list, XsdAttribute::Ptr &conflictingAttribute) const +{ + const int length = list.count(); + + for (int i = 0; i < length; ++i) { + for (int j = 0; j < length; ++j) { + if (i == j) + continue; + + if (list.at(i)->attribute()->name(m_namePool) == list.at(j)->attribute()->name(m_namePool)) { + conflictingAttribute = list.at(i)->attribute(); + return true; + } + } + } + + return false; +} + +bool XsdSchemaChecker::hasMultipleIDAttributeUses(const XsdAttributeUse::List &list) const +{ + const int length = list.count(); + + bool hasIdDerivedAttribute = false; + for (int i = 0; i < length; ++i) { + if (BuiltinTypes::xsID->wxsTypeMatches(list.at(i)->attribute()->type())) { + if (hasIdDerivedAttribute) + return true; + else + hasIdDerivedAttribute = true; + } + } + + return false; +} + +bool XsdSchemaChecker::hasConstraintIDAttributeUse(const XsdAttributeUse::List &list, XsdAttribute::Ptr &conflictingAttribute) const +{ + const int length = list.count(); + + for (int i = 0; i < length; ++i) { + const XsdAttributeUse::Ptr attributeUse(list.at(i)); + if (BuiltinTypes::xsID->wxsTypeMatches(attributeUse->attribute()->type())) { + if (attributeUse->valueConstraint()) { + conflictingAttribute = attributeUse->attribute(); + return true; + } + } + } + + return false; +} + +bool XsdSchemaChecker::particleEqualsRecursively(const XsdParticle::Ptr &particle, const XsdParticle::Ptr &otherParticle) const +{ + // @see http://www.w3.org/TR/xmlschema11-1/#cos-particle-extend + //TODO: find out what 'properties' of a particle should be checked here... + + if (particle->minimumOccurs() != otherParticle->minimumOccurs()) + return false; + + if (particle->maximumOccursUnbounded() != otherParticle->maximumOccursUnbounded()) + return false; + + if (particle->maximumOccurs() != otherParticle->maximumOccurs()) + return false; + + const XsdTerm::Ptr term = particle->term(); + const XsdTerm::Ptr otherTerm = otherParticle->term(); + + if (term->isElement() && !(otherTerm->isElement())) + return false; + + if (term->isModelGroup() && !(otherTerm->isModelGroup())) + return false; + + if (term->isWildcard() && !(otherTerm->isWildcard())) + return false; + + if (term->isElement()) { + const XsdElement::Ptr element = term; + const XsdElement::Ptr otherElement = otherTerm; + + if (element->name(m_namePool) != otherElement->name(m_namePool)) + return false; + + if (element->type()->name(m_namePool) != otherElement->type()->name(m_namePool)) + return false; + } + + if (term->isModelGroup()) { + const XsdModelGroup::Ptr group = term; + const XsdModelGroup::Ptr otherGroup = otherTerm; + + if (group->particles().count() != otherGroup->particles().count()) + return false; + + for (int i = 0; i < group->particles().count(); ++i) { + if (!particleEqualsRecursively(group->particles().at(i), otherGroup->particles().at(i))) + return false; + } + } + + if (term->isWildcard()) { + } + + return true; +} + +bool XsdSchemaChecker::isValidParticleExtension(const XsdParticle::Ptr &extension, const XsdParticle::Ptr &base) const +{ + // @see http://www.w3.org/TR/xmlschema11-1/#cos-particle-extend + + // 1 + if (extension == base) + return true; + + // 2 + if (extension->minimumOccurs() == 1 && extension->maximumOccurs() == 1 && extension->maximumOccursUnbounded() == false) { + if (extension->term()->isModelGroup()) { + const XsdModelGroup::Ptr modelGroup = extension->term(); + if (modelGroup->compositor() == XsdModelGroup::SequenceCompositor) { + if (particleEqualsRecursively(modelGroup->particles().first(), base)) + return true; + } + } + } + + // 3 + if (extension->minimumOccurs() == base->minimumOccurs()) { // 3.1 + if (extension->term()->isModelGroup() && base->term()->isModelGroup()) { + const XsdModelGroup::Ptr extensionGroup(extension->term()); + const XsdModelGroup::Ptr baseGroup(base->term()); + + if (extensionGroup->compositor() == XsdModelGroup::AllCompositor && baseGroup->compositor() == XsdModelGroup::AllCompositor) { + const XsdParticle::List extensionParticles = extensionGroup->particles(); + const XsdParticle::List baseParticles = baseGroup->particles(); + for (int i = 0; i < baseParticles.count() && i < extensionParticles.count(); ++i) { + if (baseParticles.at(i) != extensionParticles.at(i)) + return false; + } + } + } + } + + return false; +} + +QSet<XsdElement::Ptr> collectAllElements(const XsdParticle::Ptr &particle) +{ + QSet<XsdElement::Ptr> elements; + + const XsdTerm::Ptr term(particle->term()); + if (term->isElement()) { + elements.insert(XsdElement::Ptr(term)); + } else if (term->isModelGroup()) { + const XsdModelGroup::Ptr group(term); + + for (int i = 0; i < group->particles().count(); ++i) + elements.unite(collectAllElements(group->particles().at(i))); + } + + return elements; +} + +QSet<XsdElement::Ptr> collectAllElements(const XsdSchema::Ptr &schema) +{ + QSet<XsdElement::Ptr> elements; + + // collect global elements + const XsdElement::List elementList = schema->elements(); + for (int i = 0; i < elementList.count(); ++i) + elements.insert(elementList.at(i)); + + // collect all elements from global groups + const XsdModelGroup::List groupList = schema->elementGroups(); + for (int i = 0; i < groupList.count(); ++i) { + const XsdModelGroup::Ptr group(groupList.at(i)); + + for (int j = 0; j < group->particles().count(); ++j) + elements.unite(collectAllElements(group->particles().at(j))); + } + + // collect all elements from complex type definitions + SchemaType::List types; + types << schema->types() << schema->anonymousTypes(); + + for (int i = 0; i < types.count(); ++i) { + if (types.at(i)->isComplexType() && types.at(i)->isDefinedBySchema()) { + const XsdComplexType::Ptr complexType(types.at(i)); + if (complexType->contentType()->particle()) + elements.unite(collectAllElements(complexType->contentType()->particle())); + } + } + + return elements; +} + +bool XsdSchemaChecker::elementSequenceAccepted(const XsdModelGroup::Ptr &sequence, const XsdParticle::Ptr &particle) const +{ + // @see http://www.w3.org/TR/xmlschema11-1/#cvc-accept + + if (particle->term()->isWildcard()) { // 1 + const XsdWildcard::Ptr wildcard(particle->term()); + + // 1.1 + if ((unsigned int)sequence->particles().count() < particle->minimumOccurs()) + return false; + + // 1.2 + if (!particle->maximumOccursUnbounded()) { + if ((unsigned int)sequence->particles().count() > particle->maximumOccurs()) + return false; + } + + // 1.3 + const XsdParticle::List particles(sequence->particles()); + for (int i = 0; i < particles.count(); ++i) { + if (particles.at(i)->term()->isElement()) { + if (!XsdSchemaHelper::wildcardAllowsExpandedName(XsdElement::Ptr(particles.at(i)->term())->name(m_namePool), wildcard, m_namePool)) + return false; + } + } + } else if (particle->term()->isElement()) { // 2 + const XsdElement::Ptr element(particle->term()); + + // 2.1 + if ((unsigned int)sequence->particles().count() < particle->minimumOccurs()) + return false; + + // 2.2 + if (!particle->maximumOccursUnbounded()) { + if ((unsigned int)sequence->particles().count() > particle->maximumOccurs()) + return false; + } + + // 2.3 + const XsdParticle::List particles(sequence->particles()); + for (int i = 0; i < particles.count(); ++i) { + bool isValid = false; + if (particles.at(i)->term()->isElement()) { + const XsdElement::Ptr seqElement(particles.at(i)->term()); + + // 2.3.1 + if (element->name(m_namePool) == seqElement->name(m_namePool)) + isValid = true; + + // 2.3.2 + if (element->scope() && element->scope()->variety() == XsdElement::Scope::Global) { + if (!(element->disallowedSubstitutions() & NamedSchemaComponent::SubstitutionConstraint)) { + //TODO: continue + } + } + } + } + } + + return true; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdschemachecker_p.h b/src/xmlpatterns/schema/qxsdschemachecker_p.h new file mode 100644 index 0000000..843f909 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdschemachecker_p.h @@ -0,0 +1,284 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdSchemaChecker_H +#define Patternist_XsdSchemaChecker_H + +#include "qschematype_p.h" +#include "qxsdattribute_p.h" +#include "qxsdattributegroup_p.h" +#include "qxsdelement_p.h" +#include "qxsdmodelgroup_p.h" +#include "qxsdnotation_p.h" +#include "qxsdschema_p.h" +#include "qxsdsimpletype_p.h" + +#include <QtCore/QExplicitlySharedDataPointer> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + class XsdSchemaContext; + class XsdSchemaParserContext; + + /** + * @short Encapsulates the checking of schema valitity after reference resolving has finished. + * + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdSchemaChecker : public QSharedData + { + public: + typedef QExplicitlySharedDataPointer<XsdSchemaChecker> Ptr; + + /** + * Creates a new schema checker. + * + * @param context The context that is used for customization. + * @param parserContext The context that contains all the data structures. + */ + XsdSchemaChecker(const QExplicitlySharedDataPointer<XsdSchemaContext> &context, const XsdSchemaParserContext *parserContext); + + /** + * Destroys the schema checker. + */ + ~XsdSchemaChecker(); + + /** + * Starts a basic check process. + * + * This check only validates the basic super type inheritance + * of simple and complex types. + */ + void basicCheck(); + + /** + * Starts the real check process. + */ + void check(); + + /** + * Checks the constraining facets of all global and anonymous simple types for validity. + */ + void checkConstrainingFacets(); + + /** + * Adds the component location hash, so the checker is able to report meaning full + * error messages. + */ + void addComponentLocationHash(const QHash<NamedSchemaComponent::Ptr, QSourceLocation> &hash); + + private: + void checkSimpleRestrictionBaseType(); + + /** + * Checks that no simple or complex type inherits itself. + */ + void checkBasicCircularInheritances(); + + /** + * Checks the advanced circular inheritance. + */ + void checkCircularInheritances(); + + /** + * Checks for inheritance restrictions given by final or finalDefault + * attributes. + */ + void checkInheritanceRestrictions(); + + /** + * Checks for various constraints for simple types defined by schema. + */ + void checkBasicSimpleTypeConstraints(); + void checkSimpleTypeConstraints(); + + /** + * Checks for various constraints for complex types defined by schema. + */ + void checkBasicComplexTypeConstraints(); + void checkComplexTypeConstraints(); + + /** + * Checks for list and union derivation restrictions given by final or finalDefault + * attributes. + */ + void checkSimpleDerivationRestrictions(); + + /** + * Checks the set of constraining @p facets that belongs to @p simpleType for validity. + */ + void checkConstrainingFacets(const XsdFacet::Hash &facets, const XsdSimpleType::Ptr &simpleType); + + /** + * Checks for duplicated attribute uses (attributes with the same name) inside a complex type. + */ + void checkDuplicatedAttributeUses(); + + /** + * Check the element constraints. + */ + void checkElementConstraints(); + + /** + * Check the attribute constraints. + */ + void checkAttributeConstraints(); + + /** + * Check the attribute use constraints. + */ + void checkAttributeUseConstraints(); + + /** + * A map used to find duplicated elements inside a model group. + */ + typedef QHash<QXmlName, SchemaType::Ptr> DuplicatedElementMap; + + /** + * A map used to find duplicated wildcards inside a model group. + */ + typedef QHash<XsdWildcard::NamespaceConstraint::Variety, XsdWildcard::Ptr> DuplicatedWildcardMap; + + /** + * Check for duplicated elements and element wildcards in all complex type particles. + */ + void checkElementDuplicates(); + + /** + * Check for duplicated elements and element wildcards in the given @p particle. + * + * @param particle The particle to check. + * @param elementMap A map to find the duplicated elements. + * @param wildcardMap A map to find the duplicated element wildcards. + */ + void checkElementDuplicates(const XsdParticle::Ptr &particle, DuplicatedElementMap &elementMap, DuplicatedWildcardMap &wildcardMap); + + /** + * Setup fast lookup list for allowed facets of atomic simple types. + */ + void setupAllowedAtomicFacets(); + + /** + * Returns the source location of the given schema @p component or a dummy + * source location if the component is not found in the component location hash. + */ + QSourceLocation sourceLocation(const NamedSchemaComponent::Ptr &component) const; + + /** + * Returns the source location of the given schema @p type or a dummy + * source location if the type is not found in the component location hash. + */ + QSourceLocation sourceLocationForType(const SchemaType::Ptr &type) const; + + /** + * Checks that the string @p value is valid according the value space of @p type + * for the given @p component. + */ + bool isValidValue(const QString &value, const AnySimpleType::Ptr &type, QString &errorMsg) const; + + /** + * Returns the list of facets for the given @p type. + */ + XsdFacet::Hash facetsForType(const SchemaType::Ptr &type) const; + + /** + * Returns whether the given @p list of attribute uses contains two (or more) attribute + * uses that point to attributes with the same name. @p conflictingAttribute + * will contain the conflicting attribute in that case. + */ + bool hasDuplicatedAttributeUses(const XsdAttributeUse::List &list, XsdAttribute::Ptr &conflictingAttribute) const; + + /** + * Returns whether the given @p list of attribute uses contains two (or more) attribute + * uses that have a type inherited by xs:ID. + */ + bool hasMultipleIDAttributeUses(const XsdAttributeUse::List &list) const; + + /** + * Returns whether the given @p list of attribute uses contains an attribute + * uses that has a type inherited by xs:ID with a value constraint. @p conflictingAttribute + * will contain the conflicting attribute in that case. + */ + bool hasConstraintIDAttributeUse(const XsdAttributeUse::List &list, XsdAttribute::Ptr &conflictingAttribute) const; + + /** + * Checks whether the @p particle equals the @p otherParticle recursively. + */ + bool particleEqualsRecursively(const XsdParticle::Ptr &particle, const XsdParticle::Ptr &otherParticle) const; + + /** + * Checks whether the @p extension particle is a valid extension of the @p base particle. + */ + bool isValidParticleExtension(const XsdParticle::Ptr &extension, const XsdParticle::Ptr &base) const; + + /** + * Checks whether the @p sequence of elements is accepted by the given @p particle. + */ + bool elementSequenceAccepted(const XsdModelGroup::Ptr &sequence, const XsdParticle::Ptr &particle) const; + + QExplicitlySharedDataPointer<XsdSchemaContext> m_context; + NamePool::Ptr m_namePool; + XsdSchema::Ptr m_schema; + QHash<QXmlName, QSet<XsdFacet::Type> > m_allowedAtomicFacets; + QHash<NamedSchemaComponent::Ptr, QSourceLocation> m_componentLocationHash; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdschemachecker_setup.cpp b/src/xmlpatterns/schema/qxsdschemachecker_setup.cpp new file mode 100644 index 0000000..a36ecc2 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdschemachecker_setup.cpp @@ -0,0 +1,327 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdschemachecker_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +void XsdSchemaChecker::setupAllowedAtomicFacets() +{ + // string + { + QSet<XsdFacet::Type> facets; + facets << XsdFacet::Length + << XsdFacet::MinimumLength + << XsdFacet::MaximumLength + << XsdFacet::Pattern + << XsdFacet::Enumeration + << XsdFacet::WhiteSpace + << XsdFacet::Assertion; + + m_allowedAtomicFacets.insert(BuiltinTypes::xsString->name(m_namePool), facets); + } + + // boolean + { + QSet<XsdFacet::Type> facets; + facets << XsdFacet::Pattern + << XsdFacet::WhiteSpace + << XsdFacet::Assertion; + + m_allowedAtomicFacets.insert(BuiltinTypes::xsBoolean->name(m_namePool), facets); + } + + // float + { + QSet<XsdFacet::Type> facets; + facets << XsdFacet::Pattern + << XsdFacet::Enumeration + << XsdFacet::WhiteSpace + << XsdFacet::MaximumInclusive + << XsdFacet::MaximumExclusive + << XsdFacet::MinimumInclusive + << XsdFacet::MinimumExclusive + << XsdFacet::Assertion; + + m_allowedAtomicFacets.insert(BuiltinTypes::xsFloat->name(m_namePool), facets); + } + + // double + { + QSet<XsdFacet::Type> facets; + facets << XsdFacet::Pattern + << XsdFacet::Enumeration + << XsdFacet::WhiteSpace + << XsdFacet::MaximumInclusive + << XsdFacet::MaximumExclusive + << XsdFacet::MinimumInclusive + << XsdFacet::MinimumExclusive + << XsdFacet::Assertion; + + m_allowedAtomicFacets.insert(BuiltinTypes::xsDouble->name(m_namePool), facets); + } + + // decimal + { + QSet<XsdFacet::Type> facets; + facets << XsdFacet::TotalDigits + << XsdFacet::FractionDigits + << XsdFacet::Pattern + << XsdFacet::Enumeration + << XsdFacet::WhiteSpace + << XsdFacet::MaximumInclusive + << XsdFacet::MaximumExclusive + << XsdFacet::MinimumInclusive + << XsdFacet::MinimumExclusive + << XsdFacet::Assertion; + + m_allowedAtomicFacets.insert(BuiltinTypes::xsDecimal->name(m_namePool), facets); + } + + // duration + { + QSet<XsdFacet::Type> facets; + facets << XsdFacet::Pattern + << XsdFacet::Enumeration + << XsdFacet::WhiteSpace + << XsdFacet::MaximumInclusive + << XsdFacet::MaximumExclusive + << XsdFacet::MinimumInclusive + << XsdFacet::MinimumExclusive + << XsdFacet::Assertion; + + m_allowedAtomicFacets.insert(BuiltinTypes::xsDuration->name(m_namePool), facets); + } + + // dateTime + { + QSet<XsdFacet::Type> facets; + facets << XsdFacet::Pattern + << XsdFacet::Enumeration + << XsdFacet::WhiteSpace + << XsdFacet::MaximumInclusive + << XsdFacet::MaximumExclusive + << XsdFacet::MinimumInclusive + << XsdFacet::MinimumExclusive + << XsdFacet::Assertion; + + m_allowedAtomicFacets.insert(BuiltinTypes::xsDateTime->name(m_namePool), facets); + } + + // time + { + QSet<XsdFacet::Type> facets; + facets << XsdFacet::Pattern + << XsdFacet::Enumeration + << XsdFacet::WhiteSpace + << XsdFacet::MaximumInclusive + << XsdFacet::MaximumExclusive + << XsdFacet::MinimumInclusive + << XsdFacet::MinimumExclusive + << XsdFacet::Assertion; + + m_allowedAtomicFacets.insert(BuiltinTypes::xsTime->name(m_namePool), facets); + } + + // date + { + QSet<XsdFacet::Type> facets; + facets << XsdFacet::Pattern + << XsdFacet::Enumeration + << XsdFacet::WhiteSpace + << XsdFacet::MaximumInclusive + << XsdFacet::MaximumExclusive + << XsdFacet::MinimumInclusive + << XsdFacet::MinimumExclusive + << XsdFacet::Assertion; + + m_allowedAtomicFacets.insert(BuiltinTypes::xsDate->name(m_namePool), facets); + } + + // gYearMonth + { + QSet<XsdFacet::Type> facets; + facets << XsdFacet::Pattern + << XsdFacet::Enumeration + << XsdFacet::WhiteSpace + << XsdFacet::MaximumInclusive + << XsdFacet::MaximumExclusive + << XsdFacet::MinimumInclusive + << XsdFacet::MinimumExclusive + << XsdFacet::Assertion; + + m_allowedAtomicFacets.insert(BuiltinTypes::xsGYearMonth->name(m_namePool), facets); + } + + // gYear + { + QSet<XsdFacet::Type> facets; + facets << XsdFacet::Pattern + << XsdFacet::Enumeration + << XsdFacet::WhiteSpace + << XsdFacet::MaximumInclusive + << XsdFacet::MaximumExclusive + << XsdFacet::MinimumInclusive + << XsdFacet::MinimumExclusive + << XsdFacet::Assertion; + + m_allowedAtomicFacets.insert(BuiltinTypes::xsGYear->name(m_namePool), facets); + } + + // gMonthDay + { + QSet<XsdFacet::Type> facets; + facets << XsdFacet::Pattern + << XsdFacet::Enumeration + << XsdFacet::WhiteSpace + << XsdFacet::MaximumInclusive + << XsdFacet::MaximumExclusive + << XsdFacet::MinimumInclusive + << XsdFacet::MinimumExclusive + << XsdFacet::Assertion; + + m_allowedAtomicFacets.insert(BuiltinTypes::xsGMonthDay->name(m_namePool), facets); + } + + // gDay + { + QSet<XsdFacet::Type> facets; + facets << XsdFacet::Pattern + << XsdFacet::Enumeration + << XsdFacet::WhiteSpace + << XsdFacet::MaximumInclusive + << XsdFacet::MaximumExclusive + << XsdFacet::MinimumInclusive + << XsdFacet::MinimumExclusive + << XsdFacet::Assertion; + + m_allowedAtomicFacets.insert(BuiltinTypes::xsGDay->name(m_namePool), facets); + } + + // gMonth + { + QSet<XsdFacet::Type> facets; + facets << XsdFacet::Pattern + << XsdFacet::Enumeration + << XsdFacet::WhiteSpace + << XsdFacet::MaximumInclusive + << XsdFacet::MaximumExclusive + << XsdFacet::MinimumInclusive + << XsdFacet::MinimumExclusive + << XsdFacet::Assertion; + + m_allowedAtomicFacets.insert(BuiltinTypes::xsGMonth->name(m_namePool), facets); + } + + // hexBinary + { + QSet<XsdFacet::Type> facets; + facets << XsdFacet::Length + << XsdFacet::MinimumLength + << XsdFacet::MaximumLength + << XsdFacet::Pattern + << XsdFacet::Enumeration + << XsdFacet::WhiteSpace + << XsdFacet::Assertion; + + m_allowedAtomicFacets.insert(BuiltinTypes::xsHexBinary->name(m_namePool), facets); + } + + // base64Binary + { + QSet<XsdFacet::Type> facets; + facets << XsdFacet::Length + << XsdFacet::MinimumLength + << XsdFacet::MaximumLength + << XsdFacet::Pattern + << XsdFacet::Enumeration + << XsdFacet::WhiteSpace + << XsdFacet::Assertion; + + m_allowedAtomicFacets.insert(BuiltinTypes::xsBase64Binary->name(m_namePool), facets); + } + + // anyURI + { + QSet<XsdFacet::Type> facets; + facets << XsdFacet::Length + << XsdFacet::MinimumLength + << XsdFacet::MaximumLength + << XsdFacet::Pattern + << XsdFacet::Enumeration + << XsdFacet::WhiteSpace + << XsdFacet::Assertion; + + m_allowedAtomicFacets.insert(BuiltinTypes::xsAnyURI->name(m_namePool), facets); + } + + // QName + { + QSet<XsdFacet::Type> facets; + facets << XsdFacet::Length + << XsdFacet::MinimumLength + << XsdFacet::MaximumLength + << XsdFacet::Pattern + << XsdFacet::Enumeration + << XsdFacet::WhiteSpace + << XsdFacet::Assertion; + + m_allowedAtomicFacets.insert(BuiltinTypes::xsQName->name(m_namePool), facets); + } + + // NOTATION + { + QSet<XsdFacet::Type> facets; + facets << XsdFacet::Length + << XsdFacet::MinimumLength + << XsdFacet::MaximumLength + << XsdFacet::Pattern + << XsdFacet::Enumeration + << XsdFacet::WhiteSpace + << XsdFacet::Assertion; + + m_allowedAtomicFacets.insert(BuiltinTypes::xsNOTATION->name(m_namePool), facets); + } +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdschemacontext.cpp b/src/xmlpatterns/schema/qxsdschemacontext.cpp new file mode 100644 index 0000000..6d646bc --- /dev/null +++ b/src/xmlpatterns/schema/qxsdschemacontext.cpp @@ -0,0 +1,528 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdschemacontext_p.h" + +#include "qderivedinteger_p.h" +#include "qderivedstring_p.h" +#include "qxsdschematypesfactory_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +XsdSchemaContext::XsdSchemaContext(const NamePool::Ptr &namePool) + : m_namePool(namePool) + , m_networkAccessManager(0) + , m_uriResolver(0) + , m_messageHandler(0) +{ +} + +NamePool::Ptr XsdSchemaContext::namePool() const +{ + return m_namePool; +} + +QUrl XsdSchemaContext::baseURI() const +{ + return m_baseURI; +} + +void XsdSchemaContext::setBaseURI(const QUrl &uri) +{ + m_baseURI = uri; +} + +void XsdSchemaContext::setNetworkAccessManager(QNetworkAccessManager *accessManager) +{ + m_networkAccessManager = accessManager; +} + +QNetworkAccessManager* XsdSchemaContext::networkAccessManager() const +{ + return m_networkAccessManager; +} + +void XsdSchemaContext::setMessageHandler(QAbstractMessageHandler *handler) +{ + m_messageHandler = handler; +} + +QAbstractMessageHandler* XsdSchemaContext::messageHandler() const +{ + return m_messageHandler; +} + +QSourceLocation XsdSchemaContext::locationFor(const SourceLocationReflection *const) const +{ + return QSourceLocation(); +} + +void XsdSchemaContext::setUriResolver(const QAbstractUriResolver *uriResolver) +{ + m_uriResolver = uriResolver; +} + +const QAbstractUriResolver* XsdSchemaContext::uriResolver() const +{ + return m_uriResolver; +} + +XsdFacet::Hash XsdSchemaContext::facetsForType(const AnySimpleType::Ptr &type) const +{ + if (type->isDefinedBySchema()) + return XsdSimpleType::Ptr(type)->facets(); + else { + if (m_builtinTypesFacetList.isEmpty()) + m_builtinTypesFacetList = setupBuiltinTypesFacetList(); + + return m_builtinTypesFacetList.value(type); + } +} + +SchemaTypeFactory::Ptr XsdSchemaContext::schemaTypeFactory() const +{ + if (!m_schemaTypeFactory) + m_schemaTypeFactory = SchemaTypeFactory::Ptr(new XsdSchemaTypesFactory(m_namePool)); + + return m_schemaTypeFactory; +} + +QHash<SchemaType::Ptr, XsdFacet::Hash> XsdSchemaContext::setupBuiltinTypesFacetList() const +{ + QHash<SchemaType::Ptr, XsdFacet::Hash> hash; + + const XsdFacet::Ptr fixedCollapseWhiteSpace(new XsdFacet()); + fixedCollapseWhiteSpace->setType(XsdFacet::WhiteSpace); + fixedCollapseWhiteSpace->setValue(DerivedString<TypeString>::fromLexical(m_namePool, XsdSchemaToken::toString(XsdSchemaToken::Collapse))); + fixedCollapseWhiteSpace->setFixed(true); + + const XsdFacet::Ptr collapseWhiteSpace(new XsdFacet()); + collapseWhiteSpace->setType(XsdFacet::WhiteSpace); + collapseWhiteSpace->setValue(DerivedString<TypeString>::fromLexical(m_namePool, XsdSchemaToken::toString(XsdSchemaToken::Collapse))); + collapseWhiteSpace->setFixed(false); + + const XsdFacet::Ptr preserveWhiteSpace(new XsdFacet()); + preserveWhiteSpace->setType(XsdFacet::WhiteSpace); + preserveWhiteSpace->setValue(DerivedString<TypeString>::fromLexical(m_namePool, XsdSchemaToken::toString(XsdSchemaToken::Preserve))); + preserveWhiteSpace->setFixed(false); + + const XsdFacet::Ptr replaceWhiteSpace(new XsdFacet()); + replaceWhiteSpace->setType(XsdFacet::WhiteSpace); + replaceWhiteSpace->setValue(DerivedString<TypeString>::fromLexical(m_namePool, XsdSchemaToken::toString(XsdSchemaToken::Replace))); + replaceWhiteSpace->setFixed(false); + + const XsdFacet::Ptr fixedZeroFractionDigits(new XsdFacet()); + fixedZeroFractionDigits->setType(XsdFacet::FractionDigits); + fixedZeroFractionDigits->setValue(DerivedInteger<TypeNonNegativeInteger>::fromValue(m_namePool, 0)); + fixedZeroFractionDigits->setFixed(true); + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsString]; + facets.insert(preserveWhiteSpace->type(), preserveWhiteSpace); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsBoolean]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsDecimal]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsFloat]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsDouble]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsDuration]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsDateTime]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsTime]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsDate]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsGYearMonth]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsGYear]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsGMonthDay]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsGDay]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsGMonth]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsHexBinary]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsBase64Binary]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsAnyURI]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsQName]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsNOTATION]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsNormalizedString]; + facets.insert(replaceWhiteSpace->type(), replaceWhiteSpace); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsToken]; + facets.insert(collapseWhiteSpace->type(), collapseWhiteSpace); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsLanguage]; + facets.insert(collapseWhiteSpace->type(), collapseWhiteSpace); + + const XsdFacet::Ptr pattern(new XsdFacet()); + pattern->setType(XsdFacet::Pattern); + pattern->setMultiValue(AtomicValue::List() << DerivedString<TypeString>::fromLexical(m_namePool, QString::fromLatin1("[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*"))); + facets.insert(pattern->type(), pattern); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsNMTOKEN]; + facets.insert(collapseWhiteSpace->type(), collapseWhiteSpace); + + const XsdFacet::Ptr pattern(new XsdFacet()); + pattern->setType(XsdFacet::Pattern); + pattern->setMultiValue(AtomicValue::List() << DerivedString<TypeString>::fromLexical(m_namePool, QString::fromLatin1("\\c+"))); + facets.insert(pattern->type(), pattern); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsName]; + facets.insert(collapseWhiteSpace->type(), collapseWhiteSpace); + + const XsdFacet::Ptr pattern(new XsdFacet()); + pattern->setType(XsdFacet::Pattern); + pattern->setMultiValue(AtomicValue::List() << DerivedString<TypeString>::fromLexical(m_namePool, QString::fromLatin1("\\i\\c*"))); + facets.insert(pattern->type(), pattern); + } + + const XsdFacet::Ptr ncNamePattern(new XsdFacet()); + { + ncNamePattern->setType(XsdFacet::Pattern); + AtomicValue::List patterns; + patterns << DerivedString<TypeString>::fromLexical(m_namePool, QString::fromLatin1("\\i\\c*")); + patterns << DerivedString<TypeString>::fromLexical(m_namePool, QString::fromLatin1("[\\i-[:]][\\c-[:]]*")); + ncNamePattern->setMultiValue(patterns); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsNCName]; + facets.insert(collapseWhiteSpace->type(), collapseWhiteSpace); + facets.insert(ncNamePattern->type(), ncNamePattern); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsID]; + facets.insert(collapseWhiteSpace->type(), collapseWhiteSpace); + facets.insert(ncNamePattern->type(), ncNamePattern); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsIDREF]; + facets.insert(collapseWhiteSpace->type(), collapseWhiteSpace); + facets.insert(ncNamePattern->type(), ncNamePattern); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsENTITY]; + facets.insert(collapseWhiteSpace->type(), collapseWhiteSpace); + facets.insert(ncNamePattern->type(), ncNamePattern); + } + + const XsdFacet::Ptr integerPattern(new XsdFacet()); + integerPattern->setType(XsdFacet::Pattern); + integerPattern->setMultiValue(AtomicValue::List() << DerivedString<TypeString>::fromLexical(m_namePool, QString::fromLatin1("[\\-+]?[0-9]+"))); + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsInteger]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + facets.insert(fixedZeroFractionDigits->type(), fixedZeroFractionDigits); + facets.insert(integerPattern->type(), integerPattern); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsNonPositiveInteger]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + facets.insert(fixedZeroFractionDigits->type(), fixedZeroFractionDigits); + facets.insert(integerPattern->type(), integerPattern); + + const XsdFacet::Ptr maxInclusive(new XsdFacet()); + maxInclusive->setType(XsdFacet::MaximumInclusive); + maxInclusive->setValue(DerivedString<TypeString>::fromLexical(m_namePool, QString::fromLatin1("0"))); + facets.insert(maxInclusive->type(), maxInclusive); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsNegativeInteger]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + facets.insert(fixedZeroFractionDigits->type(), fixedZeroFractionDigits); + facets.insert(integerPattern->type(), integerPattern); + + const XsdFacet::Ptr maxInclusive(new XsdFacet()); + maxInclusive->setType(XsdFacet::MaximumInclusive); + maxInclusive->setValue(DerivedString<TypeString>::fromLexical(m_namePool, QString::fromLatin1("-1"))); + facets.insert(maxInclusive->type(), maxInclusive); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsLong]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + facets.insert(fixedZeroFractionDigits->type(), fixedZeroFractionDigits); + facets.insert(integerPattern->type(), integerPattern); + + const XsdFacet::Ptr maxInclusive(new XsdFacet()); + maxInclusive->setType(XsdFacet::MaximumInclusive); + maxInclusive->setValue(DerivedString<TypeString>::fromLexical(m_namePool, QString::fromLatin1("9223372036854775807"))); + facets.insert(maxInclusive->type(), maxInclusive); + + const XsdFacet::Ptr minInclusive(new XsdFacet()); + minInclusive->setType(XsdFacet::MinimumInclusive); + minInclusive->setValue(DerivedString<TypeString>::fromLexical(m_namePool, QString::fromLatin1("-9223372036854775808"))); + facets.insert(minInclusive->type(), minInclusive); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsInt]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + facets.insert(fixedZeroFractionDigits->type(), fixedZeroFractionDigits); + facets.insert(integerPattern->type(), integerPattern); + + const XsdFacet::Ptr maxInclusive(new XsdFacet()); + maxInclusive->setType(XsdFacet::MaximumInclusive); + maxInclusive->setValue(DerivedString<TypeString>::fromLexical(m_namePool, QString::fromLatin1("2147483647"))); + facets.insert(maxInclusive->type(), maxInclusive); + + const XsdFacet::Ptr minInclusive(new XsdFacet()); + minInclusive->setType(XsdFacet::MinimumInclusive); + minInclusive->setValue(DerivedString<TypeString>::fromLexical(m_namePool, QString::fromLatin1("-2147483648"))); + facets.insert(minInclusive->type(), minInclusive); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsShort]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + facets.insert(fixedZeroFractionDigits->type(), fixedZeroFractionDigits); + facets.insert(integerPattern->type(), integerPattern); + + const XsdFacet::Ptr maxInclusive(new XsdFacet()); + maxInclusive->setType(XsdFacet::MaximumInclusive); + maxInclusive->setValue(DerivedString<TypeString>::fromLexical(m_namePool, QString::fromLatin1("32767"))); + facets.insert(maxInclusive->type(), maxInclusive); + + const XsdFacet::Ptr minInclusive(new XsdFacet()); + minInclusive->setType(XsdFacet::MinimumInclusive); + minInclusive->setValue(DerivedString<TypeString>::fromLexical(m_namePool, QString::fromLatin1("-32768"))); + facets.insert(minInclusive->type(), minInclusive); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsByte]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + facets.insert(fixedZeroFractionDigits->type(), fixedZeroFractionDigits); + facets.insert(integerPattern->type(), integerPattern); + + const XsdFacet::Ptr maxInclusive(new XsdFacet()); + maxInclusive->setType(XsdFacet::MaximumInclusive); + maxInclusive->setValue(DerivedString<TypeString>::fromLexical(m_namePool, QString::fromLatin1("127"))); + facets.insert(maxInclusive->type(), maxInclusive); + + const XsdFacet::Ptr minInclusive(new XsdFacet()); + minInclusive->setType(XsdFacet::MinimumInclusive); + minInclusive->setValue(DerivedString<TypeString>::fromLexical(m_namePool, QString::fromLatin1("-128"))); + facets.insert(minInclusive->type(), minInclusive); + } + + const XsdFacet::Ptr unsignedMinInclusive(new XsdFacet()); + unsignedMinInclusive->setType(XsdFacet::MinimumInclusive); + unsignedMinInclusive->setValue(DerivedString<TypeString>::fromLexical(m_namePool, QString::fromLatin1("0"))); + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsNonNegativeInteger]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + facets.insert(fixedZeroFractionDigits->type(), fixedZeroFractionDigits); + facets.insert(integerPattern->type(), integerPattern); + facets.insert(unsignedMinInclusive->type(), unsignedMinInclusive); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsUnsignedLong]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + facets.insert(fixedZeroFractionDigits->type(), fixedZeroFractionDigits); + facets.insert(integerPattern->type(), integerPattern); + facets.insert(unsignedMinInclusive->type(), unsignedMinInclusive); + + const XsdFacet::Ptr maxInclusive(new XsdFacet()); + maxInclusive->setType(XsdFacet::MaximumInclusive); + maxInclusive->setValue(DerivedString<TypeString>::fromLexical(m_namePool, QString::fromLatin1("18446744073709551615"))); + facets.insert(maxInclusive->type(), maxInclusive); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsUnsignedInt]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + facets.insert(fixedZeroFractionDigits->type(), fixedZeroFractionDigits); + facets.insert(integerPattern->type(), integerPattern); + facets.insert(unsignedMinInclusive->type(), unsignedMinInclusive); + + const XsdFacet::Ptr maxInclusive(new XsdFacet()); + maxInclusive->setType(XsdFacet::MaximumInclusive); + maxInclusive->setValue(DerivedString<TypeString>::fromLexical(m_namePool, QString::fromLatin1("4294967295"))); + facets.insert(maxInclusive->type(), maxInclusive); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsUnsignedShort]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + facets.insert(fixedZeroFractionDigits->type(), fixedZeroFractionDigits); + facets.insert(integerPattern->type(), integerPattern); + facets.insert(unsignedMinInclusive->type(), unsignedMinInclusive); + + const XsdFacet::Ptr maxInclusive(new XsdFacet()); + maxInclusive->setType(XsdFacet::MaximumInclusive); + maxInclusive->setValue(DerivedString<TypeString>::fromLexical(m_namePool, QString::fromLatin1("65535"))); + facets.insert(maxInclusive->type(), maxInclusive); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsUnsignedByte]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + facets.insert(fixedZeroFractionDigits->type(), fixedZeroFractionDigits); + facets.insert(integerPattern->type(), integerPattern); + facets.insert(unsignedMinInclusive->type(), unsignedMinInclusive); + + const XsdFacet::Ptr maxInclusive(new XsdFacet()); + maxInclusive->setType(XsdFacet::MaximumInclusive); + maxInclusive->setValue(DerivedString<TypeString>::fromLexical(m_namePool, QString::fromLatin1("255"))); + facets.insert(maxInclusive->type(), maxInclusive); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsPositiveInteger]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + facets.insert(fixedZeroFractionDigits->type(), fixedZeroFractionDigits); + + const XsdFacet::Ptr minInclusive(new XsdFacet()); + minInclusive->setType(XsdFacet::MinimumInclusive); + minInclusive->setValue(DerivedString<TypeString>::fromLexical(m_namePool, QString::fromLatin1("1"))); + facets.insert(minInclusive->type(), minInclusive); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsYearMonthDuration]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + + const XsdFacet::Ptr pattern(new XsdFacet()); + pattern->setType(XsdFacet::Pattern); + pattern->setMultiValue(AtomicValue::List() << DerivedString<TypeString>::fromLexical(m_namePool, QString::fromLatin1("[^DT]*"))); + facets.insert(pattern->type(), pattern); + } + + { + XsdFacet::Hash &facets = hash[BuiltinTypes::xsDayTimeDuration]; + facets.insert(fixedCollapseWhiteSpace->type(), fixedCollapseWhiteSpace); + + const XsdFacet::Ptr pattern(new XsdFacet()); + pattern->setType(XsdFacet::Pattern); + pattern->setMultiValue(AtomicValue::List() << DerivedString<TypeString>::fromLexical(m_namePool, QString::fromLatin1("[^YM]*(T.*)?"))); + facets.insert(pattern->type(), pattern); + } + + return hash; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdschemacontext_p.h b/src/xmlpatterns/schema/qxsdschemacontext_p.h new file mode 100644 index 0000000..9c00964 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdschemacontext_p.h @@ -0,0 +1,187 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdSchemaContext_H +#define Patternist_XsdSchemaContext_H + +#include "qnamedschemacomponent_p.h" +#include "qreportcontext_p.h" +#include "qschematypefactory_p.h" +#include "qxsdschematoken_p.h" +#include "qxsdschema_p.h" +#include "qxsdschemachecker_p.h" +#include "qxsdschemaresolver_p.h" + +#include <QtCore/QUrl> +#include <QtNetwork/QNetworkAccessManager> +#include <QtXmlPatterns/QAbstractMessageHandler> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short A context for schema parsing and validation. + * + * This class provides the infrastructure for error reporting and + * network access. Additionally it stores objects that are used by + * both, the parser and the validator. + * + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdSchemaContext : public ReportContext + { + public: + /** + * A smart pointer wrapping XsdSchemaContext instances. + */ + typedef QExplicitlySharedDataPointer<XsdSchemaContext> Ptr; + + /** + * Creates a new schema context object. + * + * @param namePool The name pool all names belong to. + */ + XsdSchemaContext(const NamePool::Ptr &namePool); + + /** + * Returns the name pool of the schema context. + */ + virtual NamePool::Ptr namePool() const; + + /** + * Sets the base URI for the main schema. + * + * The main schema is the one that includes resp. imports + * all the other schema files. + */ + virtual void setBaseURI(const QUrl &uri); + + /** + * Returns the base URI of the main schema. + */ + virtual QUrl baseURI() const; + + /** + * Sets the network access manager that should be used + * to access referenced schema definitions. + */ + void setNetworkAccessManager(QNetworkAccessManager *accessManager); + + /** + * Returns the network access manager that is used to + * access referenced schema definitions. + */ + virtual QNetworkAccessManager* networkAccessManager() const; + + /** + * Sets the message @p handler used by the context for error reporting. + */ + void setMessageHandler(QAbstractMessageHandler *handler); + + /** + * Returns the message handler used by the context for + * error reporting. + */ + virtual QAbstractMessageHandler* messageHandler() const; + + /** + * Always returns an empty source location. + */ + virtual QSourceLocation locationFor(const SourceLocationReflection *const reflection) const; + + /** + * Sets the uri @p resolver that is used for resolving URIs in the + * schema parser. + */ + void setUriResolver(const QAbstractUriResolver *resolver); + + /** + * Returns the uri resolver that is used for resolving URIs in the + * schema parser. + */ + virtual const QAbstractUriResolver* uriResolver() const; + + /** + * Returns the list of facets for the given simple @p type. + */ + XsdFacet::Hash facetsForType(const AnySimpleType::Ptr &type) const; + + /** + * Returns a schema type factory that contains some predefined schema types. + */ + SchemaTypeFactory::Ptr schemaTypeFactory() const; + + /** + * The following variables should not be accessed directly. + */ + mutable SchemaTypeFactory::Ptr m_schemaTypeFactory; + mutable QHash<SchemaType::Ptr, XsdFacet::Hash> m_builtinTypesFacetList; + + private: + QHash<SchemaType::Ptr, XsdFacet::Hash> setupBuiltinTypesFacetList() const; + + NamePool::Ptr m_namePool; + QNetworkAccessManager* m_networkAccessManager; + QUrl m_baseURI; + const QAbstractUriResolver* m_uriResolver; + QAbstractMessageHandler* m_messageHandler; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdschemadebugger.cpp b/src/xmlpatterns/schema/qxsdschemadebugger.cpp new file mode 100644 index 0000000..5d2d6f0 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdschemadebugger.cpp @@ -0,0 +1,226 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdschemadebugger_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +XsdSchemaDebugger::XsdSchemaDebugger(const NamePool::Ptr &namePool) + : m_namePool(namePool) +{ +} + +void XsdSchemaDebugger::dumpParticle(const XsdParticle::Ptr &particle, int level) +{ + QString prefix; prefix.fill(QLatin1Char(' '), level); + + qDebug("%s min=%s max=%s", qPrintable(prefix), qPrintable(QString::number(particle->minimumOccurs())), + qPrintable(particle->maximumOccursUnbounded() ? QLatin1String("unbounded") : QString::number(particle->maximumOccurs()))); + + if (particle->term()->isElement()) { + qDebug("%selement (%s)", qPrintable(prefix), qPrintable(XsdElement::Ptr(particle->term())->displayName(m_namePool))); + } else if (particle->term()->isModelGroup()) { + const XsdModelGroup::Ptr group(particle->term()); + if (group->compositor() == XsdModelGroup::SequenceCompositor) { + qDebug("%ssequence", qPrintable(prefix)); + } else if (group->compositor() == XsdModelGroup::AllCompositor) { + qDebug("%sall", qPrintable(prefix)); + } else if (group->compositor() == XsdModelGroup::ChoiceCompositor) { + qDebug("%schoice", qPrintable(prefix)); + } + + for (int i = 0; i < group->particles().count(); ++i) + dumpParticle(group->particles().at(i), level + 5); + } else if (particle->term()->isWildcard()) { + XsdWildcard::Ptr wildcard(particle->term()); + qDebug("%swildcard (process=%d)", qPrintable(prefix), wildcard->processContents()); + } +} + +void XsdSchemaDebugger::dumpInheritance(const SchemaType::Ptr &type, int level) +{ + QString prefix; prefix.fill(QLatin1Char(' '), level); + qDebug("%s-->%s", qPrintable(prefix), qPrintable(type->displayName(m_namePool))); + if (type->wxsSuperType()) + dumpInheritance(type->wxsSuperType(), ++level); +} + +void XsdSchemaDebugger::dumpWildcard(const XsdWildcard::Ptr &wildcard) +{ + QVector<QString> varietyNames; + varietyNames.append(QLatin1String("Any")); + varietyNames.append(QLatin1String("Enumeration")); + varietyNames.append(QLatin1String("Not")); + + QVector<QString> processContentsNames; + processContentsNames.append(QLatin1String("Strict")); + processContentsNames.append(QLatin1String("Lax")); + processContentsNames.append(QLatin1String("Skip")); + + qDebug(" processContents: %s", qPrintable(processContentsNames.at((int)wildcard->processContents()))); + const XsdWildcard::NamespaceConstraint::Ptr constraint = wildcard->namespaceConstraint(); + qDebug(" variety: %s", qPrintable(varietyNames.at((int)constraint->variety()))); + if (constraint->variety() != XsdWildcard::NamespaceConstraint::Any) + qDebug() << " namespaces:" << constraint->namespaces(); +} + +void XsdSchemaDebugger::dumpType(const SchemaType::Ptr &type) +{ + if (type->isComplexType()) { + const XsdComplexType::Ptr complexType(type); + qDebug("\n+++ Complex Type +++"); + qDebug("Name: %s (abstract: %s)", qPrintable(complexType->displayName(m_namePool)), complexType->isAbstract() ? "yes" : "no"); + if (complexType->wxsSuperType()) + qDebug(" base type: %s", qPrintable(complexType->wxsSuperType()->displayName(m_namePool))); + else + qDebug(" base type: (none)"); + if (complexType->contentType()->variety() == XsdComplexType::ContentType::Empty) + qDebug(" content type: empty"); + if (complexType->contentType()->variety() == XsdComplexType::ContentType::Simple) + qDebug(" content type: simple"); + if (complexType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly) + qDebug(" content type: element-only"); + if (complexType->contentType()->variety() == XsdComplexType::ContentType::Mixed) + qDebug(" content type: mixed"); + if (complexType->contentType()->variety() == XsdComplexType::ContentType::Simple) { + if (complexType->contentType()->simpleType()) + qDebug(" simple type: %s", qPrintable(complexType->contentType()->simpleType()->displayName(m_namePool))); + else + qDebug(" simple type: (none)"); + } + + const XsdAttributeUse::List uses = complexType->attributeUses(); + qDebug(" %d attributes", uses.count()); + for (int i = 0; i < uses.count(); ++i) { + qDebug(" attr: %s", qPrintable(uses.at(i)->attribute()->displayName(m_namePool))); + } + qDebug(" has attribute wildcard: %s", complexType->attributeWildcard() ? "yes" : "no"); + if (complexType->attributeWildcard()) { + dumpWildcard(complexType->attributeWildcard()); + } + + if (complexType->contentType()->particle()) { + dumpParticle(complexType->contentType()->particle(), 5); + } + } else { + qDebug("\n+++ Simple Type +++"); + qDebug("Name: %s", qPrintable(type->displayName(m_namePool))); + if (type->isDefinedBySchema()) { + const XsdSimpleType::Ptr simpleType(type); + if (simpleType->primitiveType()) + qDebug(" primitive type: %s", qPrintable(simpleType->primitiveType()->displayName(m_namePool))); + else + qDebug(" primitive type: (none)"); + } + dumpInheritance(type, 0); + } +} + + +void XsdSchemaDebugger::dumpElement(const XsdElement::Ptr &element) +{ + QStringList disallowedSubstGroup; + if (element->disallowedSubstitutions() & XsdElement::RestrictionConstraint) + disallowedSubstGroup << QLatin1String("restriction"); + if (element->disallowedSubstitutions() & XsdElement::ExtensionConstraint) + disallowedSubstGroup << QLatin1String("extension"); + if (element->disallowedSubstitutions() & XsdElement::SubstitutionConstraint) + disallowedSubstGroup << QLatin1String("substitution"); + + + qDebug() << "Name:" << element->displayName(m_namePool); + qDebug() << "IsAbstract:" << (element->isAbstract() ? "yes" : "no"); + qDebug() << "Type:" << element->type()->displayName(m_namePool); + qDebug() << "DisallowedSubstitutionGroups:" << disallowedSubstGroup.join(QLatin1String("' ")); +} + +void XsdSchemaDebugger::dumpAttribute(const XsdAttribute::Ptr &attribute) +{ + qDebug() << "Name:" << attribute->displayName(m_namePool); + qDebug() << "Type:" << attribute->type()->displayName(m_namePool); +} + +void XsdSchemaDebugger::dumpSchema(const XsdSchema::Ptr &schema) +{ + qDebug() << "------------------------------ Schema -------------------------------"; + + // elements + { + qDebug() << "Global Elements:"; + const XsdElement::List elements = schema->elements(); + for (int i = 0; i < elements.count(); ++i) { + dumpElement(elements.at(i)); + } + } + + // attributes + { + qDebug() << "Global Attributes:"; + const XsdAttribute::List attributes = schema->attributes(); + for (int i = 0; i < attributes.count(); ++i) { + dumpAttribute(attributes.at(i)); + } + } + + // types + { + qDebug() << "Global Types:"; + const SchemaType::List types = schema->types(); + for (int i = 0; i < types.count(); ++i) { + dumpType(types.at(i)); + } + } + + // anonymous types + { + qDebug() << "Anonymous Types:"; + const SchemaType::List types = schema->anonymousTypes(); + for (int i = 0; i < types.count(); ++i) { + dumpType(types.at(i)); + } + } + + qDebug() << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdschemadebugger_p.h b/src/xmlpatterns/schema/qxsdschemadebugger_p.h new file mode 100644 index 0000000..cc3f7de --- /dev/null +++ b/src/xmlpatterns/schema/qxsdschemadebugger_p.h @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdSchemaDebugger_H +#define Patternist_XsdSchemaDebugger_H + +#include "qxsdschema_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * A helper class to print out the structure of a compiled schema. + */ + class XsdSchemaDebugger + { + public: + /** + * Creates a new schema debugger. + * + * @param namePool The name pool that the schema uses. + */ + XsdSchemaDebugger(const NamePool::Ptr &namePool); + + /** + * Dumps the structure of the given @p particle. + * + * @param particle The particle to dump. + * @param level The level of indention. + */ + void dumpParticle(const XsdParticle::Ptr &particle, int level = 0); + + /** + * Dumps the inheritance path of the given @p type. + * + * @param type The type to dump. + * @param level The level of indention. + */ + void dumpInheritance(const SchemaType::Ptr &type, int level = 0); + + /** + * Dumps the structure of the given @p wildcard. + */ + void dumpWildcard(const XsdWildcard::Ptr &wildcard); + + /** + * Dumps the structure of the given @p type. + */ + void dumpType(const SchemaType::Ptr &type); + + /** + * Dumps the structure of the given @p element. + */ + void dumpElement(const XsdElement::Ptr &element); + + /** + * Dumps the structure of the given @p attribute. + */ + void dumpAttribute(const XsdAttribute::Ptr &attribute); + + /** + * Dumps the structure of the complete @p schema. + */ + void dumpSchema(const XsdSchema::Ptr &schema); + + private: + const NamePool::Ptr m_namePool; + }; + +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdschemahelper.cpp b/src/xmlpatterns/schema/qxsdschemahelper.cpp new file mode 100644 index 0000000..70812b2 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdschemahelper.cpp @@ -0,0 +1,821 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdschemahelper_p.h" + +#include "qbuiltintypes_p.h" +#include "qvaluefactory_p.h" +#include "qxsdcomplextype_p.h" +#include "qxsdmodelgroup_p.h" +#include "qxsdsimpletype_p.h" +#include "qxsdtypechecker_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +/* + * Calculates the effective total range minimum of the given @p particle as + * described by the algorithm in the schema spec. + */ +static inline unsigned int effectiveTotalRangeMinimum(const XsdParticle::Ptr &particle) +{ + const XsdModelGroup::Ptr group = particle->term(); + + if (group->compositor() == XsdModelGroup::ChoiceCompositor) { + // @see http://www.w3.org/TR/xmlschema11-1/# cos-choice-range + + int minValue = -1; + + const XsdParticle::List particles = group->particles(); + if (particles.isEmpty()) + minValue = 0; + + for (int i = 0; i < particles.count(); ++i) { + const XsdParticle::Ptr particle = particles.at(i); + + if (particle->term()->isElement() || particle->term()->isWildcard()) { + if (minValue == -1) { + minValue = particle->minimumOccurs(); + } else { + minValue = qMin((unsigned int)minValue, particle->minimumOccurs()); + } + } else if (particle->term()->isModelGroup()) { + if (minValue == -1) { + minValue = effectiveTotalRangeMinimum(particle); + } else { + minValue = qMin((unsigned int)minValue, effectiveTotalRangeMinimum(particle)); + } + } + } + + return (particle->minimumOccurs() * minValue); + + } else { + // @see http://www.w3.org/TR/xmlschema11-1/# cos-seq-range + + unsigned int sum = 0; + const XsdParticle::List particles = group->particles(); + for (int i = 0; i < particles.count(); ++i) { + const XsdParticle::Ptr particle = particles.at(i); + + if (particle->term()->isElement() || particle->term()->isWildcard()) + sum += particle->minimumOccurs(); + else if (particle->term()->isModelGroup()) + sum += effectiveTotalRangeMinimum(particle); + } + + return (particle->minimumOccurs() * sum); + } +} + +bool XsdSchemaHelper::isParticleEmptiable(const XsdParticle::Ptr &particle) +{ + // @see http://www.w3.org/TR/xmlschema11-1/#cos-group-emptiable + + if (particle->minimumOccurs() == 0) + return true; + + if (!(particle->term()->isModelGroup())) + return false; + + return (effectiveTotalRangeMinimum(particle) == 0); +} + +bool XsdSchemaHelper::wildcardAllowsNamespaceName(const QString &nameSpace, const XsdWildcard::NamespaceConstraint::Ptr &constraint) +{ + // @see http://www.w3.org/TR/xmlschema11-1/#cvc-wildcard-namespace + + // 1 + if (constraint->variety() == XsdWildcard::NamespaceConstraint::Any) + return true; + + // 2 + if (constraint->variety() == XsdWildcard::NamespaceConstraint::Not) { // 2.1 + if (!constraint->namespaces().contains(nameSpace)) // 2.2 + if (nameSpace != XsdWildcard::absentNamespace()) // 2.3 + return true; + } + + // 3 + if (constraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration) { + if (constraint->namespaces().contains(nameSpace)) + return true; + } + + return false; +} + +bool XsdSchemaHelper::wildcardAllowsExpandedName(const QXmlName &name, const XsdWildcard::Ptr &wildcard, const NamePool::Ptr &namePool) +{ + // @see http://www.w3.org/TR/xmlschema11-1/#cvc-wildcard-name + + // 1 + if (!wildcardAllowsNamespaceName(namePool->stringForNamespace(name.namespaceURI()), wildcard->namespaceConstraint())) + return false; + + // 2, 3, 4 + //TODO: we have no disallowed namespace yet + + return true; +} + +// small helper function that should be available in Qt 4.6 +template<class T> +static inline bool containsSet(const QSet<T> &super, const QSet<T> &sub) +{ + QSetIterator<T> it(sub); + while (it.hasNext()) { + if (!super.contains(it.next())) + return false; + } + + return true; +} + +bool XsdSchemaHelper::isWildcardSubset(const XsdWildcard::Ptr &wildcard, const XsdWildcard::Ptr &otherWildcard) +{ + // @see http://www.w3.org/TR/xmlschema11-1/#cos-ns-subset + // wildcard =^ sub + // otherWildcard =^ super + + const XsdWildcard::NamespaceConstraint::Ptr constraint(wildcard->namespaceConstraint()); + const XsdWildcard::NamespaceConstraint::Ptr otherConstraint(otherWildcard->namespaceConstraint()); + + // 1 + if (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Any) + return true; + + // 2 + if ((constraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration) && (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration)) { + if (containsSet<QString>(otherConstraint->namespaces(), constraint->namespaces())) + return true; + } + + // 3 + if ((constraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration) && (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Not)) { + if (constraint->namespaces().intersect(otherConstraint->namespaces()).isEmpty()) + return true; + } + + // 4 + if ((constraint->variety() == XsdWildcard::NamespaceConstraint::Not) && (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Not)) { + if (containsSet<QString>(constraint->namespaces(), otherConstraint->namespaces())) + return true; + } + + return false; +} + +XsdWildcard::Ptr XsdSchemaHelper::wildcardUnion(const XsdWildcard::Ptr &wildcard, const XsdWildcard::Ptr &otherWildcard) +{ + // @see http://www.w3.org/TR/xmlschema11-1/#cos-aw-union + + XsdWildcard::Ptr unionWildcard(new XsdWildcard()); + + const XsdWildcard::NamespaceConstraint::Ptr constraint(wildcard->namespaceConstraint()); + const XsdWildcard::NamespaceConstraint::Ptr otherConstraint(otherWildcard->namespaceConstraint()); + + // 1 + if ((constraint->variety() == otherConstraint->variety()) && + (constraint->namespaces() == otherConstraint->namespaces())) { + unionWildcard->namespaceConstraint()->setVariety(constraint->variety()); + unionWildcard->namespaceConstraint()->setNamespaces(constraint->namespaces()); + return unionWildcard; + } + + // 2 + if ((constraint->variety() == XsdWildcard::NamespaceConstraint::Any) || (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Any)) { + unionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Any); + return unionWildcard; + } + + // 3 + if ((constraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration) && (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration)) { + unionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Enumeration); + unionWildcard->namespaceConstraint()->setNamespaces(constraint->namespaces() + otherConstraint->namespaces()); + return unionWildcard; + } + + // 4 + if ((constraint->variety() == XsdWildcard::NamespaceConstraint::Not) && (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Not)) { + if (constraint->namespaces() != otherConstraint->namespaces()) { + unionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Not); + unionWildcard->namespaceConstraint()->setNamespaces(QSet<QString>() << XsdWildcard::absentNamespace()); + return unionWildcard; + } + } + + // 5 + QSet<QString> sSet, negatedSet; + bool matches5 = false; + if (((constraint->variety() == XsdWildcard::NamespaceConstraint::Not) && !constraint->namespaces().contains(XsdWildcard::absentNamespace())) + && (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration)) { + + negatedSet = constraint->namespaces(); + sSet = otherConstraint->namespaces(); + matches5 = true; + } else if (((otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Not) && !otherConstraint->namespaces().contains(XsdWildcard::absentNamespace())) + && (constraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration)) { + + negatedSet = otherConstraint->namespaces(); + sSet = constraint->namespaces(); + matches5 = true; + } + + if (matches5) { + if (sSet.contains(negatedSet.values().first()) && sSet.contains(XsdWildcard::absentNamespace())) { // 5.1 + unionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Any); + return unionWildcard; + } + if (sSet.contains(negatedSet.values().first()) && !sSet.contains(XsdWildcard::absentNamespace())) { // 5.2 + unionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Not); + unionWildcard->namespaceConstraint()->setNamespaces(QSet<QString>() << XsdWildcard::absentNamespace()); + return unionWildcard; + } + if (!sSet.contains(negatedSet.values().first()) && sSet.contains(XsdWildcard::absentNamespace())) { // 5.3 + return XsdWildcard::Ptr(); // not expressible + } + if (!sSet.contains(negatedSet.values().first()) && !sSet.contains(XsdWildcard::absentNamespace())) { // 5.4 + unionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Not); + unionWildcard->namespaceConstraint()->setNamespaces(negatedSet); + return unionWildcard; + } + } + + // 6 + bool matches6 = false; + if (((constraint->variety() == XsdWildcard::NamespaceConstraint::Not) && constraint->namespaces().contains(XsdWildcard::absentNamespace())) + && (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration)) { + + negatedSet = constraint->namespaces(); + sSet = otherConstraint->namespaces(); + matches6 = true; + } else if (((otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Not) && otherConstraint->namespaces().contains(XsdWildcard::absentNamespace())) + && (constraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration)) { + + negatedSet = otherConstraint->namespaces(); + sSet = constraint->namespaces(); + matches6 = true; + } + + if (matches6) { + if (sSet.contains(XsdWildcard::absentNamespace())) { // 6.1 + unionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Any); + return unionWildcard; + } + if (!sSet.contains(XsdWildcard::absentNamespace())) { // 6.2 + unionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Not); + unionWildcard->namespaceConstraint()->setNamespaces(QSet<QString>() += XsdWildcard::absentNamespace()); + return unionWildcard; + } + } + + return XsdWildcard::Ptr(); +} + +XsdWildcard::Ptr XsdSchemaHelper::wildcardIntersection(const XsdWildcard::Ptr &wildcard, const XsdWildcard::Ptr &otherWildcard) +{ + // @see http://www.w3.org/TR/xmlschema11-1/#cos-aw-intersect + + const XsdWildcard::NamespaceConstraint::Ptr constraint(wildcard->namespaceConstraint()); + const XsdWildcard::NamespaceConstraint::Ptr otherConstraint(otherWildcard->namespaceConstraint()); + + const XsdWildcard::Ptr intersectionWildcard(new XsdWildcard()); + + // 1 + if ((constraint->variety() == otherConstraint->variety()) && + (constraint->namespaces() == otherConstraint->namespaces())) { + intersectionWildcard->namespaceConstraint()->setVariety(constraint->variety()); + intersectionWildcard->namespaceConstraint()->setNamespaces(constraint->namespaces()); + return intersectionWildcard; + } + + // 2 + if ((constraint->variety() == XsdWildcard::NamespaceConstraint::Any) && + (otherConstraint->variety() != XsdWildcard::NamespaceConstraint::Any)) { + intersectionWildcard->namespaceConstraint()->setVariety(otherConstraint->variety()); + intersectionWildcard->namespaceConstraint()->setNamespaces(otherConstraint->namespaces()); + return intersectionWildcard; + } + + // 2 + if ((constraint->variety() != XsdWildcard::NamespaceConstraint::Any) && + (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Any)) { + intersectionWildcard->namespaceConstraint()->setVariety(constraint->variety()); + intersectionWildcard->namespaceConstraint()->setNamespaces(constraint->namespaces()); + return intersectionWildcard; + } + + // 3 + if ((constraint->variety() == XsdWildcard::NamespaceConstraint::Not) && + (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration)) { + + QSet<QString> set = otherConstraint->namespaces(); + set.subtract(constraint->namespaces()); + set.remove(XsdWildcard::absentNamespace()); + + intersectionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Enumeration); + intersectionWildcard->namespaceConstraint()->setNamespaces(set); + + return intersectionWildcard; + } + + // 3 + if ((otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Not) && + (constraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration)) { + + QSet<QString> set = constraint->namespaces(); + set.subtract(otherConstraint->namespaces()); + set.remove(XsdWildcard::absentNamespace()); + + intersectionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Enumeration); + intersectionWildcard->namespaceConstraint()->setNamespaces(set); + + return intersectionWildcard; + } + + // 4 + if ((constraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration) && + (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration)) { + + QSet<QString> set = constraint->namespaces(); + set.intersect(otherConstraint->namespaces()); + + intersectionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Enumeration); + intersectionWildcard->namespaceConstraint()->setNamespaces(set); + + return intersectionWildcard; + } + + // 6 + if ((constraint->variety() == XsdWildcard::NamespaceConstraint::Not) && + (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Not)) { + if (!(constraint->namespaces().contains(XsdWildcard::absentNamespace())) && otherConstraint->namespaces().contains(XsdWildcard::absentNamespace())) { + return wildcard; + } + if (constraint->namespaces().contains(XsdWildcard::absentNamespace()) && !(otherConstraint->namespaces().contains(XsdWildcard::absentNamespace()))) { + return otherWildcard; + } + } + + // 5 as not expressible return empty wildcard + return XsdWildcard::Ptr(); +} + +static SchemaType::DerivationConstraints convertBlockingConstraints(const NamedSchemaComponent::BlockingConstraints &constraints) +{ + SchemaType::DerivationConstraints result = 0; + + if (constraints & NamedSchemaComponent::RestrictionConstraint) + result |= SchemaType::RestrictionConstraint; + if (constraints & NamedSchemaComponent::ExtensionConstraint) + result |= SchemaType::ExtensionConstraint; + + return result; +} + +bool XsdSchemaHelper::isValidlySubstitutable(const SchemaType::Ptr &type, const SchemaType::Ptr &otherType, const SchemaType::DerivationConstraints &constraints) +{ + // @see http://www.w3.org/TR/xmlschema11-1/#key-val-sub-type + + // 1 + if (type->isComplexType() && otherType->isComplexType()) { + SchemaType::DerivationConstraints keywords = constraints; + if (otherType->isDefinedBySchema()) + keywords |= convertBlockingConstraints(XsdComplexType::Ptr(otherType)->prohibitedSubstitutions()); + + return isComplexDerivationOk(type, otherType, keywords); + } + + // 2 + if (type->isComplexType() && otherType->isSimpleType()) { + return isComplexDerivationOk(type, otherType, constraints); + } + + // 3 + if (type->isSimpleType() && otherType->isSimpleType()) { + return isSimpleDerivationOk(type, otherType, constraints); + } + + return false; +} + +bool XsdSchemaHelper::isSimpleDerivationOk(const SchemaType::Ptr &derivedType, const SchemaType::Ptr &baseType, const SchemaType::DerivationConstraints &constraints) +{ + // @see http://www.w3.org/TR/xmlschema11-1/#cos-st-derived-ok + + // 1 + if (derivedType == baseType) + return true; + + // 2.1 + if ((constraints & SchemaType::RestrictionConstraint) || derivedType->wxsSuperType()->derivationConstraints() & SchemaType::RestrictionConstraint) { + return false; + } + + // 2.2.1 + if (derivedType->wxsSuperType() == baseType) + return true; + + // 2.2.2 + if (derivedType->wxsSuperType() != BuiltinTypes::xsAnyType) { + if (isSimpleDerivationOk(derivedType->wxsSuperType(), baseType, constraints)) + return true; + } + + // 2.2.3 + if (derivedType->category() == SchemaType::SimpleTypeList || derivedType->category() == SchemaType::SimpleTypeUnion) { + if (baseType == BuiltinTypes::xsAnySimpleType) + return true; + } + + // 2.2.4 + if (baseType->category() == SchemaType::SimpleTypeUnion && baseType->isDefinedBySchema()) { // 2.2.4.1 + const AnySimpleType::List memberTypes = XsdSimpleType::Ptr(baseType)->memberTypes(); + for (int i = 0; i < memberTypes.count(); ++i) { + if (isSimpleDerivationOk(derivedType, memberTypes.at(i), constraints)) { // 2.2.4.2 + if (XsdSimpleType::Ptr(baseType)->facets().isEmpty()) { // 2.2.4.3 + return true; + } + } + } + } + + return false; +} + +bool XsdSchemaHelper::isComplexDerivationOk(const SchemaType::Ptr &derivedType, const SchemaType::Ptr &baseType, const SchemaType::DerivationConstraints &constraints) +{ + if (!derivedType) + return false; + + // @see http://www.w3.org/TR/xmlschema11-1/#cos-ct-derived-ok + + // 1 + if (derivedType != baseType) { + if ((derivedType->derivationMethod() == SchemaType::DerivationRestriction) && (constraints & SchemaType::RestrictionConstraint)) + return false; + if ((derivedType->derivationMethod() == SchemaType::DerivationExtension) && (constraints & SchemaType::ExtensionConstraint)) + return false; + } + + // 2.1 + if (derivedType == baseType) + return true; + + // 2.2 + if (derivedType->wxsSuperType() == baseType) + return true; + + // 2.3 + bool isOk = true; + if (derivedType->wxsSuperType() == BuiltinTypes::xsAnyType) { // 2.3.1 + isOk = false; + } else { // 2.3.2 + if (!derivedType->wxsSuperType()) + return false; + + if (derivedType->wxsSuperType()->isComplexType()) { // 2.3.2.1 + isOk = isComplexDerivationOk(derivedType->wxsSuperType(), baseType, constraints); + } else { // 2.3.2.2 + isOk = isSimpleDerivationOk(derivedType->wxsSuperType(), baseType, constraints); + } + } + if (isOk) + return true; + + return false; +} + +bool XsdSchemaHelper::constructAndCompare(const DerivedString<TypeString>::Ptr &operand1, + const AtomicComparator::Operator op, + const DerivedString<TypeString>::Ptr &operand2, + const SchemaType::Ptr &type, + const ReportContext::Ptr &context, + const SourceLocationReflection *const sourceLocationReflection) +{ + Q_ASSERT_X(type->category() == SchemaType::SimpleTypeAtomic, Q_FUNC_INFO, + "We can only compare atomic values."); + + // we can not cast a xs:String to a xs:QName, so lets go the safe way + if (type->name(context->namePool()) == BuiltinTypes::xsQName->name(context->namePool())) + return false; + + const AtomicValue::Ptr value1 = ValueFactory::fromLexical(operand1->stringValue(), type, context, sourceLocationReflection); + if (value1->hasError()) + return false; + + const AtomicValue::Ptr value2 = ValueFactory::fromLexical(operand2->stringValue(), type, context, sourceLocationReflection); + if (value2->hasError()) + return false; + + return ComparisonFactory::compare(value1, op, value2, type, context, sourceLocationReflection); +} + +bool XsdSchemaHelper::checkWildcardProcessContents(const XsdWildcard::Ptr &baseWildcard, const XsdWildcard::Ptr &derivedWildcard) +{ + if (baseWildcard->processContents() == XsdWildcard::Strict) { + if (derivedWildcard->processContents() == XsdWildcard::Lax || derivedWildcard->processContents() == XsdWildcard::Skip) { + return false; + } + } else if (baseWildcard->processContents() == XsdWildcard::Lax) { + if (derivedWildcard->processContents() == XsdWildcard::Skip) + return false; + } + + return true; +} + +bool XsdSchemaHelper::foundSubstitutionGroupTransitive(const XsdElement::Ptr &head, const XsdElement::Ptr &member, QSet<XsdElement::Ptr> &visitedElements) +{ + if (visitedElements.contains(member)) + return false; + else + visitedElements.insert(member); + + if (member->substitutionGroupAffiliations().isEmpty()) + return false; + + if (member->substitutionGroupAffiliations().contains(head)) { + return true; + } else { + const XsdElement::List affiliations = member->substitutionGroupAffiliations(); + for (int i = 0; i < affiliations.count(); ++i) { + if (foundSubstitutionGroupTransitive(head, affiliations.at(i), visitedElements)) + return true; + } + + return false; + } +} + +void XsdSchemaHelper::foundSubstitutionGroupTypeInheritance(const SchemaType::Ptr &headType, const SchemaType::Ptr &memberType, + QSet<SchemaType::DerivationMethod> &derivationSet, NamedSchemaComponent::BlockingConstraints &blockSet) +{ + if (!memberType) + return; + + if (memberType == headType) + return; + + derivationSet.insert(memberType->derivationMethod()); + + if (memberType->isComplexType()) { + const XsdComplexType::Ptr complexType(memberType); + blockSet |= complexType->prohibitedSubstitutions(); + } + + foundSubstitutionGroupTypeInheritance(headType, memberType->wxsSuperType(), derivationSet, blockSet); +} + +bool XsdSchemaHelper::substitutionGroupOkTransitive(const XsdElement::Ptr &head, const XsdElement::Ptr &member, const NamePool::Ptr &namePool) +{ + // @see http://www.w3.org/TR/xmlschema11-1/#cos-equiv-derived-ok-rec + + // 1 + if ((member->name(namePool) == head->name(namePool)) && (member->type() == head->type())) + return true; + + // 2.1 + if (head->disallowedSubstitutions() & NamedSchemaComponent::SubstitutionConstraint) + return false; + + // 2.2 + { + QSet<XsdElement::Ptr> visitedElements; + if (!foundSubstitutionGroupTransitive(head, member, visitedElements)) + return false; + } + + // 2.3 + { + QSet<SchemaType::DerivationMethod> derivationSet; + NamedSchemaComponent::BlockingConstraints blockSet; + + foundSubstitutionGroupTypeInheritance(head->type(), member->type(), derivationSet, blockSet); + + NamedSchemaComponent::BlockingConstraints checkSet(blockSet); + checkSet |= head->disallowedSubstitutions(); + if (head->type()->isComplexType()) { + const XsdComplexType::Ptr complexType(head->type()); + checkSet |= complexType->prohibitedSubstitutions(); + } + + if ((checkSet & NamedSchemaComponent::RestrictionConstraint) && derivationSet.contains(SchemaType::DerivationRestriction)) + return false; + if ((checkSet & NamedSchemaComponent::ExtensionConstraint) && derivationSet.contains(SchemaType::DerivationExtension)) + return false; + if (checkSet & NamedSchemaComponent::SubstitutionConstraint) + return false; + } + + return true; +} + +bool XsdSchemaHelper::isValidAttributeGroupRestriction(const XsdAttributeGroup::Ptr &derivedAttributeGroup, const XsdAttributeGroup::Ptr &attributeGroup, const XsdSchemaContext::Ptr &context, QString &errorMsg) +{ + // @see http://www.w3.org/TR/xmlschema-1/#derivation-ok-restriction + + const XsdAttributeUse::List derivedAttributeUses = derivedAttributeGroup->attributeUses(); + const XsdAttributeUse::List baseAttributeUses = attributeGroup->attributeUses(); + + return isValidAttributeUsesRestriction(derivedAttributeUses, baseAttributeUses, + derivedAttributeGroup->wildcard(), attributeGroup->wildcard(), context, errorMsg); +} + +bool XsdSchemaHelper::isValidAttributeUsesRestriction(const XsdAttributeUse::List &derivedAttributeUses, const XsdAttributeUse::List &baseAttributeUses, + const XsdWildcard::Ptr &derivedWildcard, const XsdWildcard::Ptr &wildcard, const XsdSchemaContext::Ptr &context, QString &errorMsg) +{ + const NamePool::Ptr namePool(context->namePool()); + + QHash<QXmlName, XsdAttributeUse::Ptr> baseAttributeUsesLookup; + for (int i = 0; i < baseAttributeUses.count(); ++i) + baseAttributeUsesLookup.insert(baseAttributeUses.at(i)->attribute()->name(namePool), baseAttributeUses.at(i)); + + QHash<QXmlName, XsdAttributeUse::Ptr> derivedAttributeUsesLookup; + for (int i = 0; i < derivedAttributeUses.count(); ++i) + derivedAttributeUsesLookup.insert(derivedAttributeUses.at(i)->attribute()->name(namePool), derivedAttributeUses.at(i)); + + // 2 + for (int i = 0; i < derivedAttributeUses.count(); ++i) { + const XsdAttributeUse::Ptr derivedAttributeUse = derivedAttributeUses.at(i); + + // prohibited attributes are no real attributes, so skip them in that test here + if (derivedAttributeUse->useType() == XsdAttributeUse::ProhibitedUse) + continue; + + if (baseAttributeUsesLookup.contains(derivedAttributeUse->attribute()->name(namePool))) { + const XsdAttributeUse::Ptr baseAttributeUse(baseAttributeUsesLookup.value(derivedAttributeUse->attribute()->name(namePool))); + + // 2.1.1 + if (baseAttributeUse->isRequired() == true && derivedAttributeUse->isRequired() == false) { + errorMsg = QtXmlPatterns::tr("base attribute %1 is required but derived attribute is not").arg(formatAttribute(baseAttributeUse->attribute()->displayName(namePool))); + return false; + } + + // 2.1.2 + if (!isSimpleDerivationOk(derivedAttributeUse->attribute()->type(), baseAttributeUse->attribute()->type(), SchemaType::DerivationConstraints())) { + errorMsg = QtXmlPatterns::tr("type of derived attribute %1 cannot be validly derived from type of base attribute").arg(formatAttribute(derivedAttributeUse->attribute()->displayName(namePool))); + return false; + } + + // 2.1.3 + XsdAttributeUse::ValueConstraint::Ptr derivedConstraint; + if (derivedAttributeUse->valueConstraint()) + derivedConstraint = derivedAttributeUse->valueConstraint(); + else if (derivedAttributeUse->attribute()->valueConstraint()) + derivedConstraint = XsdAttributeUse::ValueConstraint::fromAttributeValueConstraint(derivedAttributeUse->attribute()->valueConstraint()); + + XsdAttributeUse::ValueConstraint::Ptr baseConstraint; + if (baseAttributeUse->valueConstraint()) + baseConstraint = baseAttributeUse->valueConstraint(); + else if (baseAttributeUse->attribute()->valueConstraint()) + baseConstraint = XsdAttributeUse::ValueConstraint::fromAttributeValueConstraint(baseAttributeUse->attribute()->valueConstraint()); + + bool ok = false; + if (!baseConstraint || baseConstraint->variety() == XsdAttributeUse::ValueConstraint::Default) + ok = true; + + if (derivedConstraint && baseConstraint) { + const XsdTypeChecker checker(context, QVector<QXmlName>(), QSourceLocation(QUrl(QLatin1String("http://dummy.org")), 1, 1)); + if (derivedConstraint->variety() == XsdAttributeUse::ValueConstraint::Fixed && checker.valuesAreEqual(derivedConstraint->value(), baseConstraint->value(), baseAttributeUse->attribute()->type())) + ok = true; + } + + if (!ok) { + errorMsg = QtXmlPatterns::tr("value constraint of derived attribute %1 does not match value constraint of base attribute").arg(formatAttribute(derivedAttributeUse->attribute()->displayName(namePool))); + return false; + } + } else { + if (!wildcard) { + errorMsg = QtXmlPatterns::tr("derived attribute %1 does not exists in the base definition").arg(formatAttribute(derivedAttributeUse->attribute()->displayName(namePool))); + return false; + } + + QXmlName name = derivedAttributeUse->attribute()->name(namePool); + + // wildcards using XsdWildcard::absentNamespace, so we have to fix that here + if (name.namespaceURI() == StandardNamespaces::empty) + name.setNamespaceURI(namePool->allocateNamespace(XsdWildcard::absentNamespace())); + + if (!wildcardAllowsExpandedName(name, wildcard, namePool)) { + errorMsg = QtXmlPatterns::tr("derived attribute %1 does not match the wildcard in the base definition").arg(formatAttribute(derivedAttributeUse->attribute()->displayName(namePool))); + return false; + } + } + } + + // 3 + for (int i = 0; i < baseAttributeUses.count(); ++i) { + const XsdAttributeUse::Ptr baseAttributeUse = baseAttributeUses.at(i); + + if (baseAttributeUse->isRequired()) { + if (derivedAttributeUsesLookup.contains(baseAttributeUse->attribute()->name(namePool))) { + if (!derivedAttributeUsesLookup.value(baseAttributeUse->attribute()->name(namePool))->isRequired()) { + errorMsg = QtXmlPatterns::tr("base attribute %1 is required but derived attribute is not").arg(formatAttribute(baseAttributeUse->attribute()->displayName(namePool))); + return false; + } + } else { + errorMsg = QtXmlPatterns::tr("base attribute %1 is required but missing in derived definition").arg(formatAttribute(baseAttributeUse->attribute()->displayName(namePool))); + return false; + } + } + } + + // 4 + if (derivedWildcard) { + if (!wildcard) { + errorMsg = QtXmlPatterns::tr("derived definition contains an %1 element that does not exists in the base definition").arg(formatElement("anyAttribute")); + return false; + } + + if (!isWildcardSubset(derivedWildcard, wildcard)) { + errorMsg = QtXmlPatterns::tr("derived wildcard is not a subset of the base wildcard"); + return false; + } + + if (!checkWildcardProcessContents(wildcard, derivedWildcard)) { + errorMsg = QtXmlPatterns::tr("%1 of derived wildcard is not a valid restriction of %2 of base wildcard").arg(formatKeyword("processContents")).arg(formatKeyword("processContents")); + return false; + } + } + + return true; +} + +bool XsdSchemaHelper::isValidAttributeUsesExtension(const XsdAttributeUse::List &derivedAttributeUses, const XsdAttributeUse::List &attributeUses, + const XsdWildcard::Ptr &derivedWildcard, const XsdWildcard::Ptr &wildcard, const XsdSchemaContext::Ptr &context, QString &errorMsg) +{ + // @see http://www.w3.org/TR/xmlschema11-1/#cos-ct-extends + + const NamePool::Ptr namePool(context->namePool()); + + // 1.2 + QHash<QXmlName, XsdAttribute::Ptr> lookupHash; + for (int i = 0; i < derivedAttributeUses.count(); ++i) + lookupHash.insert(derivedAttributeUses.at(i)->attribute()->name(namePool), derivedAttributeUses.at(i)->attribute()); + + for (int i = 0; i < attributeUses.count(); ++i) { + const QXmlName attributeName = attributeUses.at(i)->attribute()->name(namePool); + if (!lookupHash.contains(attributeName)) { + errorMsg = QtXmlPatterns::tr("attribute %1 from base type is missing in derived type").arg(formatKeyword(namePool->displayName(attributeName))); + return false; + } + + if (lookupHash.value(attributeName)->type() != attributeUses.at(i)->attribute()->type()) { + errorMsg = QtXmlPatterns::tr("type of derived attribute %1 differs from type of base attribute").arg(formatKeyword(namePool->displayName(attributeName))); + return false; + } + } + + // 1.3 + if (wildcard) { + if (!derivedWildcard) { + errorMsg = QtXmlPatterns::tr("base definition contains an %1 element that is missing in the derived definition").arg(formatElement("anyAttribute")); + return false; + } + } + + return true; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdschemahelper_p.h b/src/xmlpatterns/schema/qxsdschemahelper_p.h new file mode 100644 index 0000000..71fdfe7 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdschemahelper_p.h @@ -0,0 +1,217 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdSchemaHelper_H +#define Patternist_XsdSchemaHelper_H + +#include "qcomparisonfactory_p.h" +#include "qschematype_p.h" +#include "qxsdattributegroup_p.h" +#include "qxsdelement_p.h" +#include "qxsdparticle_p.h" +#include "qxsdschemacontext_p.h" +#include "qxsdwildcard_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + + /** + * @short Contains helper methods that are used by XsdSchemaParser, XsdSchemaResolver and XsdSchemaChecker. + * + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdSchemaHelper + { + public: + /** + * Checks whether the given @p particle is emptiable as defined by the + * algorithm in the schema spec. + */ + static bool isParticleEmptiable(const XsdParticle::Ptr &particle); + + /** + * Checks whether the given @p nameSpace is allowed by the given namespace @p constraint. + */ + static bool wildcardAllowsNamespaceName(const QString &nameSpace, + const XsdWildcard::NamespaceConstraint::Ptr &constraint); + + /** + * Checks whether the given @p name is allowed by the namespace constraint of the given @p wildcard. + */ + static bool wildcardAllowsExpandedName(const QXmlName &name, + const XsdWildcard::Ptr &wildcard, + const NamePool::Ptr &namePool); + + /** + * Checks whether the @p wildcard is a subset of @p otherWildcard. + */ + static bool isWildcardSubset(const XsdWildcard::Ptr &wildcard, const XsdWildcard::Ptr &otherWildcard); + + /** + * Returns the union of the given @p wildcard and @p otherWildcard. + */ + static XsdWildcard::Ptr wildcardUnion(const XsdWildcard::Ptr &wildcard, const XsdWildcard::Ptr &otherWildcard); + + /** + * Returns the intersection of the given @p wildcard and @p otherWildcard. + */ + static XsdWildcard::Ptr wildcardIntersection(const XsdWildcard::Ptr &wildcard, + const XsdWildcard::Ptr &otherWildcard); + + /** + * Returns whether the given @p type is validly substitutable for an @p otherType + * under the given @p constraints. + */ + static bool isValidlySubstitutable(const SchemaType::Ptr &type, + const SchemaType::Ptr &otherType, + const SchemaType::DerivationConstraints &constraints); + + /** + * Returns whether the simple @p derivedType can be derived from the simple @p baseType + * under the given @p constraints. + */ + static bool isSimpleDerivationOk(const SchemaType::Ptr &derivedType, + const SchemaType::Ptr &baseType, + const SchemaType::DerivationConstraints &constraints); + + /** + * Returns whether the complex @p derivedType can be derived from the complex @p baseType + * under the given @p constraints. + */ + static bool isComplexDerivationOk(const SchemaType::Ptr &derivedType, + const SchemaType::Ptr &baseType, + const SchemaType::DerivationConstraints &constraints); + + /** + * This method takes the two string based operands @p operand1 and @p operand2 and converts them to instances of type @p type. + * If the conversion fails, @c false is returned, otherwise the instances are compared by the given operator @p op and the + * result of the comparison is returned. + */ + static bool constructAndCompare(const DerivedString<TypeString>::Ptr &operand1, + const AtomicComparator::Operator op, + const DerivedString<TypeString>::Ptr &operand2, + const SchemaType::Ptr &type, + const ReportContext::Ptr &context, + const SourceLocationReflection *const sourceLocationReflection); + + /** + * Returns whether the process content property of the @p derivedWildcard is valid + * according to the process content property of its @p baseWildcard. + */ + static bool checkWildcardProcessContents(const XsdWildcard::Ptr &baseWildcard, + const XsdWildcard::Ptr &derivedWildcard); + + /** + * Checks whether @[ member is a member of the substitution group with the given @p head. + */ + static bool foundSubstitutionGroupTransitive(const XsdElement::Ptr &head, + const XsdElement::Ptr &member, + QSet<XsdElement::Ptr> &visitedElements); + + /** + * A helper method that iterates over the type hierarchy from @p memberType up to @p headType and collects all + * @p derivationSet and @p blockSet constraints that exists on the way there. + */ + static void foundSubstitutionGroupTypeInheritance(const SchemaType::Ptr &headType, + const SchemaType::Ptr &memberType, + QSet<SchemaType::DerivationMethod> &derivationSet, + NamedSchemaComponent::BlockingConstraints &blockSet); + + /** + * Checks if the @p member is transitive to @p head. + */ + static bool substitutionGroupOkTransitive(const XsdElement::Ptr &head, + const XsdElement::Ptr &member, + const NamePool::Ptr &namePool); + + /** + * Checks if @p derivedAttributeGroup is a valid restriction for @p attributeGroup. + */ + static bool isValidAttributeGroupRestriction(const XsdAttributeGroup::Ptr &derivedAttributeGroup, + const XsdAttributeGroup::Ptr &attributeGroup, + const XsdSchemaContext::Ptr &context, + QString &errorMsg); + + /** + * Checks if @p derivedAttributeUses are a valid restriction for @p attributeUses. + */ + static bool isValidAttributeUsesRestriction(const XsdAttributeUse::List &derivedAttributeUses, + const XsdAttributeUse::List &attributeUses, + const XsdWildcard::Ptr &derivedWildcard, + const XsdWildcard::Ptr &wildcard, + const XsdSchemaContext::Ptr &context, + QString &errorMsg); + + /** + * Checks if @p derivedAttributeUses are a valid extension for @p attributeUses. + */ + static bool isValidAttributeUsesExtension(const XsdAttributeUse::List &derivedAttributeUses, + const XsdAttributeUse::List &attributeUses, + const XsdWildcard::Ptr &derivedWildcard, + const XsdWildcard::Ptr &wildcard, + const XsdSchemaContext::Ptr &context, + QString &errorMsg); + + private: + Q_DISABLE_COPY(XsdSchemaHelper) + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdschemamerger.cpp b/src/xmlpatterns/schema/qxsdschemamerger.cpp new file mode 100644 index 0000000..1714068 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdschemamerger.cpp @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdschemamerger_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +XsdSchemaMerger::XsdSchemaMerger(const XsdSchema::Ptr &schema, const XsdSchema::Ptr &otherSchema) +{ + merge(schema, otherSchema); +} + +XsdSchema::Ptr XsdSchemaMerger::mergedSchema() const +{ + return m_mergedSchema; +} + +void XsdSchemaMerger::merge(const XsdSchema::Ptr &schema, const XsdSchema::Ptr &otherSchema) +{ + m_mergedSchema = XsdSchema::Ptr(new XsdSchema(otherSchema->namePool())); + + // first fill the merged schema with the values from schema + if (schema) { + const XsdElement::List elements = schema->elements(); + for (int i = 0; i < elements.count(); ++i) { + m_mergedSchema->addElement(elements.at(i)); + } + + const XsdAttribute::List attributes = schema->attributes(); + for (int i = 0; i < attributes.count(); ++i) { + m_mergedSchema->addAttribute(attributes.at(i)); + } + + const SchemaType::List types = schema->types(); + for (int i = 0; i < types.count(); ++i) { + m_mergedSchema->addType(types.at(i)); + } + + const SchemaType::List anonymousTypes = schema->anonymousTypes(); + for (int i = 0; i < anonymousTypes.count(); ++i) { + m_mergedSchema->addAnonymousType(anonymousTypes.at(i)); + } + + const XsdModelGroup::List elementGroups = schema->elementGroups(); + for (int i = 0; i < elementGroups.count(); ++i) { + m_mergedSchema->addElementGroup(elementGroups.at(i)); + } + + const XsdAttributeGroup::List attributeGroups = schema->attributeGroups(); + for (int i = 0; i < attributeGroups.count(); ++i) { + m_mergedSchema->addAttributeGroup(attributeGroups.at(i)); + } + + const XsdNotation::List notations = schema->notations(); + for (int i = 0; i < notations.count(); ++i) { + m_mergedSchema->addNotation(notations.at(i)); + } + + const XsdIdentityConstraint::List identityConstraints = schema->identityConstraints(); + for (int i = 0; i < identityConstraints.count(); ++i) { + m_mergedSchema->addIdentityConstraint(identityConstraints.at(i)); + } + } + + // then merge in the values from the otherSchema + { + const XsdElement::List elements = otherSchema->elements(); + for (int i = 0; i < elements.count(); ++i) { + if (!m_mergedSchema->element(elements.at(i)->name(otherSchema->namePool()))) + m_mergedSchema->addElement(elements.at(i)); + } + + const XsdAttribute::List attributes = otherSchema->attributes(); + for (int i = 0; i < attributes.count(); ++i) { + if (!m_mergedSchema->attribute(attributes.at(i)->name(otherSchema->namePool()))) + m_mergedSchema->addAttribute(attributes.at(i)); + } + + const SchemaType::List types = otherSchema->types(); + for (int i = 0; i < types.count(); ++i) { + if (!m_mergedSchema->type(types.at(i)->name(otherSchema->namePool()))) + m_mergedSchema->addType(types.at(i)); + } + + const SchemaType::List anonymousTypes = otherSchema->anonymousTypes(); + for (int i = 0; i < anonymousTypes.count(); ++i) { + // add anonymous type as they are + m_mergedSchema->addAnonymousType(anonymousTypes.at(i)); + } + + const XsdModelGroup::List elementGroups = otherSchema->elementGroups(); + for (int i = 0; i < elementGroups.count(); ++i) { + if (!m_mergedSchema->elementGroup(elementGroups.at(i)->name(otherSchema->namePool()))) + m_mergedSchema->addElementGroup(elementGroups.at(i)); + } + + const XsdAttributeGroup::List attributeGroups = otherSchema->attributeGroups(); + for (int i = 0; i < attributeGroups.count(); ++i) { + if (!m_mergedSchema->attributeGroup(attributeGroups.at(i)->name(otherSchema->namePool()))) + m_mergedSchema->addAttributeGroup(attributeGroups.at(i)); + } + + const XsdNotation::List notations = otherSchema->notations(); + for (int i = 0; i < notations.count(); ++i) { + if (!m_mergedSchema->notation(notations.at(i)->name(otherSchema->namePool()))) + m_mergedSchema->addNotation(notations.at(i)); + } + + const XsdIdentityConstraint::List identityConstraints = otherSchema->identityConstraints(); + for (int i = 0; i < identityConstraints.count(); ++i) { + if (!m_mergedSchema->identityConstraint(identityConstraints.at(i)->name(otherSchema->namePool()))) + m_mergedSchema->addIdentityConstraint(identityConstraints.at(i)); + } + } +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdschemamerger_p.h b/src/xmlpatterns/schema/qxsdschemamerger_p.h new file mode 100644 index 0000000..8b522c5 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdschemamerger_p.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdSchemaMerger_H +#define Patternist_XsdSchemaMerger_H + +#include "qxsdschema_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short A helper class that merges two schemas into one. + * + * This class is used in XsdValidatingInstanceReader to merge the schema + * given in the constructor with a schema defined in the instance document + * via xsi:schemaLocation or xsi:noNamespaceSchema location. + * + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdSchemaMerger : public QSharedData + { + public: + typedef QExplicitlySharedDataPointer<XsdSchemaMerger> Ptr; + + /** + * Creates a new schema merger object that merges @p schema with @p otherSchema. + */ + XsdSchemaMerger(const XsdSchema::Ptr &schema, const XsdSchema::Ptr &otherSchema); + + /** + * Returns the merged schema. + */ + XsdSchema::Ptr mergedSchema() const; + + private: + void merge(const XsdSchema::Ptr &schema, const XsdSchema::Ptr &otherSchema); + + XsdSchema::Ptr m_mergedSchema; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdschemaparser.cpp b/src/xmlpatterns/schema/qxsdschemaparser.cpp new file mode 100644 index 0000000..4e6a643 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdschemaparser.cpp @@ -0,0 +1,6078 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdschemaparser_p.h" + +#include "private/qxmlutils_p.h" +#include "qacceltreeresourceloader_p.h" +#include "qautoptr_p.h" +#include "qboolean_p.h" +#include "qcommonnamespaces_p.h" +#include "qderivedinteger_p.h" +#include "qderivedstring_p.h" +#include "qqnamevalue_p.h" +#include "qxmlquery_p.h" +#include "qxpathhelper_p.h" +#include "qxsdattributereference_p.h" +#include "qxsdreference_p.h" +#include "qxsdschematoken_p.h" + +#include <QtCore/QFile> +#include <QtXmlPatterns/QXmlQuery> + +QT_BEGIN_NAMESPACE + +/** + * @page schema_overview Overview + * @section structure_and_components Structure and Components + * + * The schema validator code consists of 4 major components + * + * <dl> + * <dt>The schema parser (QPatternist::XsdSchemaParser)</dt> + * <dd>This component parses a XML document that is supplied via a QIODevice. It creates + * a so called (incomplete) 'compiled schema', which is a representation of the XML Schema + * structure as C++ objects. + * As the parser is a streaming parser, it can't resolve references to types or elements/attributes + * in place, therefor it creates resolver tasks which are passed to the schema resolver component + * for resolving at a later point in time. + * The parser does furthermore the basic XML structure constraint checking, e.g. if all required + * attributes are available or the order of the elements is correct.</dd> + * + * <dt>The schema resolver (QPatternist::XsdSchemaResolver)</dt> + * <dd>This component is activated after the schema parser component has been finished the parsing + * of all schemas. The resolver has been supplied with resolve tasks by the schema parser that + * it will resolve in this step now. Between working on the single resolver tasks, the resolver + * calls check methods from the schema checker component to make sure that some assertions are + * valid (e.g. no circular inheritance of types), so that the resolver can work without hassle. + * During resoving references to attribute or element groups it also checks for circular references + * of these groups. + * At the end of that phase we have a compiled schema that is fully resolved (not necessarily valid though).</dd> + * + * <dt>The schema checker (QPatternist::XsdSchemaChecker)</dt> + * <dd>This component does all the schema constraint checking as given by the Schema specification. + * At the end of that phase we have fully resolved and valid compiled schema that can be used for validation + * of instance documents.</dd> + * + * <dt>The validator (QPatternist::XsdValidatingInstanceReader)</dt> + * <dd>This component is responsible for validating a XML instance document, provided via a QIODevice, against + * a valid compiled schema.</dd> + * </dl> + * + * @ingroup Patternist_schema + */ + +using namespace QPatternist; + +namespace QPatternist +{ + +/** + * @short A helper class for automatically handling namespace scopes of elements. + * + * This class should be instantiated at the beginning of each parse XYZ method. + */ +class ElementNamespaceHandler +{ + public: + /** + * Creates a new element namespace handler object. + * + * It checks whether the @p parser is on the right @p tag and it creates a new namespace + * context that contains the inherited and local namespace declarations. + */ + ElementNamespaceHandler(const XsdSchemaToken::NodeName &tag, XsdSchemaParser *parser) + : m_parser(parser) + { + Q_ASSERT(m_parser->isStartElement() && (XsdSchemaToken::toToken(m_parser->name()) == tag) && (XsdSchemaToken::toToken(m_parser->namespaceUri()) == XsdSchemaToken::XML_NS_SCHEMA_URI)); + m_parser->m_namespaceSupport.pushContext(); + m_parser->m_namespaceSupport.setPrefixes(m_parser->namespaceDeclarations()); + } + + /** + * Destroys the element namespace handler object. + * + * It destroys the local namespace context. + */ + ~ElementNamespaceHandler() + { + m_parser->m_namespaceSupport.popContext(); + } + + private: + XsdSchemaParser *m_parser; +}; + +/** + * A helper class that checks for the right occurrence of + * xml tags with the help of a DFA. + */ +class TagValidationHandler +{ + public: + TagValidationHandler(XsdTagScope::Type tag, XsdSchemaParser *parser, const NamePool::Ptr &namePool) + : m_parser(parser), m_machine(namePool) + { + Q_ASSERT(m_parser->m_stateMachines.contains(tag)); + + m_machine = m_parser->m_stateMachines.value(tag); + m_machine.reset(); + } + + void validate(XsdSchemaToken::NodeName token) + { + if (token == XsdSchemaToken::NoKeyword) { + const QList<XsdSchemaToken::NodeName> tokens = m_machine.possibleTransitions(); + + QStringList elementNames; + for (int i = 0; i < tokens.count(); ++i) + elementNames.append(formatElement(XsdSchemaToken::toString(tokens.at(i)))); + + m_parser->error(QtXmlPatterns::tr("can not process unknown element %1, expected elements are: %2") + .arg(formatElement(m_parser->name().toString())) + .arg(elementNames.join(QLatin1String(", ")))); + return; + } + + if (!m_machine.proceed(token)) { + const QList<XsdSchemaToken::NodeName> tokens = m_machine.possibleTransitions(); + + QStringList elementNames; + for (int i = 0; i < tokens.count(); ++i) + elementNames.append(formatElement(XsdSchemaToken::toString(tokens.at(i)))); + + m_parser->error(QtXmlPatterns::tr("element %1 is not allowed in this scope, possible elements are: %2") + .arg(formatElement(XsdSchemaToken::toString(token))) + .arg(elementNames.join(QLatin1String(", ")))); + return; + } + } + + void finalize() const + { + if (!m_machine.inEndState()) { + const QList<XsdSchemaToken::NodeName> tokens = m_machine.possibleTransitions(); + + QStringList elementNames; + for (int i = 0; i < tokens.count(); ++i) + elementNames.append(formatElement(XsdSchemaToken::toString(tokens.at(i)))); + + m_parser->error(QtXmlPatterns::tr("child element is missing in that scope, possible child elements are: %1") + .arg(elementNames.join(QLatin1String(", ")))); + } + } + + private: + XsdSchemaParser *m_parser; + XsdStateMachine<XsdSchemaToken::NodeName> m_machine; +}; + +} + +/** + * Returns a list of all particles with group references that appear at any level of + * the given unresolved @p group. + */ +static XsdParticle::List collectGroupRef(const XsdModelGroup::Ptr &group) +{ + XsdParticle::List refParticles; + + XsdParticle::List particles = group->particles(); + for (int i = 0; i < particles.count(); ++i) { + if (particles.at(i)->term()->isReference()) { + const XsdReference::Ptr reference(particles.at(i)->term()); + if (reference->type() == XsdReference::ModelGroup) + refParticles.append(particles.at(i)); + } + if (particles.at(i)->term()->isModelGroup()) { + refParticles << collectGroupRef(XsdModelGroup::Ptr(particles.at(i)->term())); + } + } + + return refParticles; +} + +/** + * Helper function that works around the limited facilities of + * QUrl/AnyURI::fromLexical to detect invalid URIs + */ +inline static bool isValidUri(const QString &string) +{ + // an empty URI points to the current document as defined in RFC 2396 (4.2) + if (string.isEmpty()) + return true; + + // explicit check as that is not checked by the code below + if (string.startsWith(QLatin1String("##"))) + return false; + + const AnyURI::Ptr uri = AnyURI::fromLexical(string); + return (!(uri->hasError())); +} + +XsdSchemaParser::XsdSchemaParser(const XsdSchemaContext::Ptr &context, const XsdSchemaParserContext::Ptr &parserContext, QIODevice *device) + : MaintainingReader<XsdSchemaToken, XsdTagScope::Type>(parserContext->elementDescriptions(), QSet<XsdSchemaToken::NodeName>(), context, device) + , m_context(context) + , m_parserContext(parserContext) + , m_namePool(m_parserContext->namePool()) + , m_namespaceSupport(m_namePool) +{ + m_schema = m_parserContext->schema(); + m_schemaResolver = m_parserContext->resolver(); + m_idCache = XsdIdCache::Ptr(new XsdIdCache()); + + setupStateMachines(); + setupBuiltinTypeNames(); +} + +void XsdSchemaParser::setIncludedSchemas(const NamespaceSet &schemas) +{ + m_includedSchemas = schemas; +} + +void XsdSchemaParser::setImportedSchemas(const NamespaceSet &schemas) +{ + m_importedSchemas = schemas; +} + +void XsdSchemaParser::setRedefinedSchemas(const NamespaceSet &schemas) +{ + m_redefinedSchemas = schemas; +} + +void XsdSchemaParser::setTargetNamespace(const QString &targetNamespace) +{ + m_targetNamespace = targetNamespace; +} + +void XsdSchemaParser::setTargetNamespaceExtended(const QString &targetNamespace) +{ + m_targetNamespace = targetNamespace; + m_namespaceSupport.setTargetNamespace(m_namePool->allocateNamespace(m_targetNamespace)); +} + +void XsdSchemaParser::setDocumentURI(const QUrl &uri) +{ + m_documentURI = uri; + + // prevent to get included/imported/redefined twice + m_includedSchemas.insert(uri); + m_importedSchemas.insert(uri); +} + +QUrl XsdSchemaParser::documentURI() const +{ + return m_documentURI; +} + +bool XsdSchemaParser::isAnyAttributeAllowed() const +{ + return false; +} + +bool XsdSchemaParser::parse(ParserType parserType) +{ + m_componentLocationHash.clear(); + + while (!atEnd()) { + readNext(); + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + if (isSchemaTag(XsdSchemaToken::Schema, token, namespaceToken)) { + parseSchema(parserType); + } else { + error(QtXmlPatterns::tr("document is not a XML schema")); + } + } + } + + m_schemaResolver->addComponentLocationHash(m_componentLocationHash); + m_schemaResolver->setDefaultOpenContent(m_defaultOpenContent, m_defaultOpenContentAppliesToEmpty); + + if (QXmlStreamReader::error() != QXmlStreamReader::NoError) + error(errorString()); + + return true; +} + +void XsdSchemaParser::error(const QString &msg) +{ + MaintainingReader<XsdSchemaToken, XsdTagScope::Type>::error(msg, XsdSchemaContext::XSDError); +} + +void XsdSchemaParser::attributeContentError(const char *attributeName, const char *elementName, const QString &value, const SchemaType::Ptr &type) +{ + if (type) { + error(QtXmlPatterns::tr("%1 attribute of %2 element contains invalid content: {%3} is not a value of type %4") + .arg(formatAttribute(attributeName)) + .arg(formatElement(elementName)) + .arg(formatData(value)) + .arg(formatType(m_namePool, type))); + } else { + error(QtXmlPatterns::tr("%1 attribute of %2 element contains invalid content: {%3}") + .arg(formatAttribute(attributeName)) + .arg(formatElement(elementName)) + .arg(formatData(value))); + } +} + +void XsdSchemaParser::parseSchema(ParserType parserType) +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Schema, this); + + validateElement(XsdTagScope::Schema); + + // parse attributes + + if (parserType == TopLevelParser) { + if (hasAttribute(QString::fromLatin1("targetNamespace"))) { + m_targetNamespace = readNamespaceAttribute(QString::fromLatin1("targetNamespace"), "schema"); + } + } else if (parserType == IncludeParser) { + // m_targetNamespace is set to the target namespace of the including schema at this point + + if (hasAttribute(QString::fromLatin1("targetNamespace"))) { + const QString targetNamespace = readNamespaceAttribute(QString::fromLatin1("targetNamespace"), "schema"); + + if (m_targetNamespace != targetNamespace) { + error(QtXmlPatterns::tr("target namespace %1 of included schema is different from the target namespace %2 as defined by the including schema") + .arg(formatURI(targetNamespace)).arg(formatURI(m_targetNamespace))); + return; + } + } + } else if (parserType == ImportParser) { + // m_targetNamespace is set to the target namespace from the namespace attribute of the <import> tag at this point + + QString targetNamespace; + if (hasAttribute(QString::fromLatin1("targetNamespace"))) { + targetNamespace = readNamespaceAttribute(QString::fromLatin1("targetNamespace"), "schema"); + } + + if (m_targetNamespace != targetNamespace) { + error(QtXmlPatterns::tr("target namespace %1 of imported schema is different from the target namespace %2 as defined by the importing schema") + .arg(formatURI(targetNamespace)).arg(formatURI(m_targetNamespace))); + return; + } + } else if (parserType == RedefineParser) { + // m_targetNamespace is set to the target namespace of the redefining schema at this point + + if (hasAttribute(QString::fromLatin1("targetNamespace"))) { + const QString targetNamespace = readNamespaceAttribute(QString::fromLatin1("targetNamespace"), "schema"); + + if (m_targetNamespace != targetNamespace) { + error(QtXmlPatterns::tr("target namespace %1 of imported schema is different from the target namespace %2 as defined by the importing schema") + .arg(formatURI(targetNamespace)).arg(formatURI(m_targetNamespace))); + return; + } + } + } + + if (hasAttribute(QString::fromLatin1("attributeFormDefault"))) { + const QString value = readAttribute(QString::fromLatin1("attributeFormDefault")); + if (value != QString::fromLatin1("qualified") && value != QString::fromLatin1("unqualified")) { + attributeContentError("attributeFormDefault", "schema", value); + return; + } + + m_attributeFormDefault = value; + } else { + m_attributeFormDefault = QString::fromLatin1("unqualified"); + } + + if (hasAttribute(QString::fromLatin1("elementFormDefault"))) { + const QString value = readAttribute(QString::fromLatin1("elementFormDefault")); + if (value != QString::fromLatin1("qualified") && value != QString::fromLatin1("unqualified")) { + attributeContentError("elementFormDefault", "schema", value); + return; + } + + m_elementFormDefault = value; + } else { + m_elementFormDefault = QString::fromLatin1("unqualified"); + } + + if (hasAttribute(QString::fromLatin1("blockDefault"))) { + const QString blockDefault = readAttribute(QString::fromLatin1("blockDefault")); + const QStringList blockDefaultList = blockDefault.split(QLatin1Char(' '), QString::SkipEmptyParts); + for (int i = 0; i < blockDefaultList.count(); ++i) { + const QString value = blockDefaultList.at(i); + if (value != QString::fromLatin1("#all") && + value != QString::fromLatin1("extension") && + value != QString::fromLatin1("restriction") && + value != QString::fromLatin1("substitution")) { + attributeContentError("blockDefault", "schema", value); + return; + } + } + + m_blockDefault = blockDefault; + } + + if (hasAttribute(QString::fromLatin1("finalDefault"))) { + const QString finalDefault = readAttribute(QString::fromLatin1("finalDefault")); + const QStringList finalDefaultList = finalDefault.split(QLatin1Char(' '), QString::SkipEmptyParts); + for (int i = 0; i < finalDefaultList.count(); ++i) { + const QString value = finalDefaultList.at(i); + if (value != QString::fromLatin1("#all") && + value != QString::fromLatin1("extension") && + value != QString::fromLatin1("restriction") && + value != QString::fromLatin1("list") && + value != QString::fromLatin1("union")) { + attributeContentError("finalDefault", "schema", value); + return; + } + } + + m_finalDefault = finalDefault; + } + + if (hasAttribute(QString::fromLatin1("xpathDefaultNamespace"))) { + const QString xpathDefaultNamespace = readAttribute(QString::fromLatin1("xpathDefaultNamespace")); + if (xpathDefaultNamespace != QString::fromLatin1("##defaultNamespace") && + xpathDefaultNamespace != QString::fromLatin1("##targetNamespace") && + xpathDefaultNamespace != QString::fromLatin1("##local")) { + if (!isValidUri(xpathDefaultNamespace)) { + attributeContentError("xpathDefaultNamespace", "schema", xpathDefaultNamespace); + return; + } + } + m_xpathDefaultNamespace = xpathDefaultNamespace; + } else { + m_xpathDefaultNamespace = QString::fromLatin1("##local"); + } + + if (hasAttribute(QString::fromLatin1("defaultAttributes"))) { + const QString attrGroupName = readQNameAttribute(QString::fromLatin1("defaultAttributes"), "schema"); + convertName(attrGroupName, NamespaceSupport::ElementName, m_defaultAttributes); // translate qualified name into QXmlName + } + + if (hasAttribute(QString::fromLatin1("version"))) { + const QString version = readAttribute(QString::fromLatin1("version")); + } + + if (hasAttribute(CommonNamespaces::XML, QString::fromLatin1("lang"))) { + const QString value = readAttribute(QString::fromLatin1("lang"), CommonNamespaces::XML); + + const QRegExp exp(QString::fromLatin1("[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*")); + if (!exp.exactMatch(value)) { + attributeContentError("xml:lang", "schema", value); + return; + } + } + + validateIdAttribute("schema"); + + TagValidationHandler tagValidator(XsdTagScope::Schema, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Include, token, namespaceToken)) { + parseInclude(); + } else if (isSchemaTag(XsdSchemaToken::Import, token, namespaceToken)) { + parseImport(); + } else if (isSchemaTag(XsdSchemaToken::Redefine, token, namespaceToken)) { + parseRedefine(); + } else if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + m_schema->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::DefaultOpenContent, token, namespaceToken)) { + parseDefaultOpenContent(); + } else if (isSchemaTag(XsdSchemaToken::SimpleType, token, namespaceToken)) { + const XsdSimpleType::Ptr type = parseGlobalSimpleType(); + addType(type); + } else if (isSchemaTag(XsdSchemaToken::ComplexType, token, namespaceToken)) { + const XsdComplexType::Ptr type = parseGlobalComplexType(); + addType(type); + } else if (isSchemaTag(XsdSchemaToken::Group, token, namespaceToken)) { + const XsdModelGroup::Ptr group = parseNamedGroup(); + addElementGroup(group); + } else if (isSchemaTag(XsdSchemaToken::AttributeGroup, token, namespaceToken)) { + XsdAttributeGroup::Ptr attributeGroup = parseNamedAttributeGroup(); + addAttributeGroup(attributeGroup); + } else if (isSchemaTag(XsdSchemaToken::Element, token, namespaceToken)) { + const XsdElement::Ptr element = parseGlobalElement(); + addElement(element); + } else if (isSchemaTag(XsdSchemaToken::Attribute, token, namespaceToken)) { + const XsdAttribute::Ptr attribute = parseGlobalAttribute(); + addAttribute(attribute); + } else if (isSchemaTag(XsdSchemaToken::Notation, token, namespaceToken)) { + const XsdNotation::Ptr notation = parseNotation(); + addNotation(notation); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + m_schema->setTargetNamespace(m_targetNamespace); +} + +void XsdSchemaParser::parseInclude() +{ + Q_ASSERT(isStartElement() && XsdSchemaToken::toToken(name()) == XsdSchemaToken::Include && + XsdSchemaToken::toToken(namespaceUri()) == XsdSchemaToken::XML_NS_SCHEMA_URI); + + validateElement(XsdTagScope::Include); + + // parse attributes + const QString schemaLocation = readAttribute(QString::fromLatin1("schemaLocation")); + + QUrl url(schemaLocation); + if (url.isRelative()) { + Q_ASSERT(m_documentURI.isValid()); + + url = m_documentURI.resolved(url); + } + + if (m_includedSchemas.contains(url)) { + // we have included that file already, according to the schema spec we are + // allowed to silently skip it. + } else { + m_includedSchemas.insert(url); + + const AutoPtr<QNetworkReply> reply(AccelTreeResourceLoader::load(url, m_context->networkAccessManager(), + m_context, AccelTreeResourceLoader::ContinueOnError)); + if (reply) { + // parse the included schema by a different parser but with the same context + XsdSchemaParser parser(m_context, m_parserContext, reply.data()); + parser.setDocumentURI(url); + parser.setTargetNamespaceExtended(m_targetNamespace); + parser.setIncludedSchemas(m_includedSchemas); + parser.setImportedSchemas(m_importedSchemas); + parser.setRedefinedSchemas(m_redefinedSchemas); + if (!parser.parse(XsdSchemaParser::IncludeParser)) + return; + } + } + + validateIdAttribute("include"); + + TagValidationHandler tagValidator(XsdTagScope::Include, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + m_schema->addAnnotation(annotation); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); +} + +void XsdSchemaParser::parseImport() +{ + Q_ASSERT(isStartElement() && XsdSchemaToken::toToken(name()) == XsdSchemaToken::Import && + XsdSchemaToken::toToken(namespaceUri()) == XsdSchemaToken::XML_NS_SCHEMA_URI); + + validateElement(XsdTagScope::Import); + + // parse attributes + QString importNamespace; + if (hasAttribute(QString::fromLatin1("namespace"))) { + importNamespace = readAttribute(QString::fromLatin1("namespace")); + if (importNamespace == m_targetNamespace) { + error(QtXmlPatterns::tr("%1 element is not allowed to have the same %2 attribute value as the target namespace %3") + .arg(formatElement("import")) + .arg(formatAttribute("namespace")) + .arg(formatURI(m_targetNamespace))); + return; + } + } else { + if (m_targetNamespace.isEmpty()) { + error(QtXmlPatterns::tr("%1 element without %2 attribute is not allowed inside schema without target namespace") + .arg(formatElement("import")) + .arg(formatAttribute("namespace"))); + return; + } + } + + if (hasAttribute(QString::fromLatin1("schemaLocation"))) { + const QString schemaLocation = readAttribute(QString::fromLatin1("schemaLocation")); + + QUrl url(schemaLocation); + if (url.isRelative()) { + Q_ASSERT(m_documentURI.isValid()); + + url = m_documentURI.resolved(url); + } + + if (m_importedSchemas.contains(url)) { + // we have imported that file already, according to the schema spec we are + // allowed to silently skip it. + } else { + m_importedSchemas.insert(url); + + // as it is possible that well known schemas (e.g. XSD for XML) are only referenced by + // namespace we should add it as well + m_importedSchemas.insert(importNamespace); + + AutoPtr<QNetworkReply> reply(AccelTreeResourceLoader::load(url, m_context->networkAccessManager(), + m_context, AccelTreeResourceLoader::ContinueOnError)); + if (reply) { + // parse the included schema by a different parser but with the same context + XsdSchemaParser parser(m_context, m_parserContext, reply.data()); + parser.setDocumentURI(url); + parser.setTargetNamespace(importNamespace); + parser.setIncludedSchemas(m_includedSchemas); + parser.setImportedSchemas(m_importedSchemas); + parser.setRedefinedSchemas(m_redefinedSchemas); + if (!parser.parse(XsdSchemaParser::ImportParser)) + return; + } + } + } else { + // check whether it is a known namespace we have a builtin schema for + if (!importNamespace.isEmpty()) { + if (!m_importedSchemas.contains(importNamespace)) { + m_importedSchemas.insert(importNamespace); + + QFile file(QString::fromLatin1(":") + importNamespace); + if (file.open(QIODevice::ReadOnly)) { + XsdSchemaParser parser(m_context, m_parserContext, &file); + parser.setDocumentURI(importNamespace); + parser.setTargetNamespace(importNamespace); + parser.setIncludedSchemas(m_includedSchemas); + parser.setImportedSchemas(m_importedSchemas); + parser.setRedefinedSchemas(m_redefinedSchemas); + if (!parser.parse(XsdSchemaParser::ImportParser)) + return; + } + } + } else { + // we don't import anything... that is valid according to the schema + } + } + + validateIdAttribute("import"); + + TagValidationHandler tagValidator(XsdTagScope::Import, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + m_schema->addAnnotation(annotation); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); +} + +void XsdSchemaParser::parseRedefine() +{ + Q_ASSERT(isStartElement() && XsdSchemaToken::toToken(name()) == XsdSchemaToken::Redefine && + XsdSchemaToken::toToken(namespaceUri()) == XsdSchemaToken::XML_NS_SCHEMA_URI); + + validateElement(XsdTagScope::Redefine); + + // parse attributes + validateIdAttribute("redefine"); + + const QString schemaLocation = readAttribute(QString::fromLatin1("schemaLocation")); + + TagValidationHandler tagValidator(XsdTagScope::Redefine, this, m_namePool); + + XsdSimpleType::List redefinedSimpleTypes; + XsdComplexType::List redefinedComplexTypes; + XsdModelGroup::List redefinedGroups; + XsdAttributeGroup::List redefinedAttributeGroups; + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + m_schema->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::SimpleType, token, namespaceToken)) { + const XsdSimpleType::Ptr type = parseGlobalSimpleType(); + redefinedSimpleTypes.append(type); + + const QXmlName baseTypeName = m_parserContext->resolver()->baseTypeNameOfType(type); + if (baseTypeName != type->name(m_namePool)) { + error(QString::fromLatin1("redefined simple type %1 must have itself as base type").arg(formatType(m_namePool, type))); + return; + } + } else if (isSchemaTag(XsdSchemaToken::ComplexType, token, namespaceToken)) { + const XsdComplexType::Ptr type = parseGlobalComplexType(); + redefinedComplexTypes.append(type); + + // @see http://www.w3.org/TR/xmlschema11-1/#src-redefine + + // 5 + const QXmlName baseTypeName = m_parserContext->resolver()->baseTypeNameOfType(type); + if (baseTypeName != type->name(m_namePool)) { + error(QString::fromLatin1("redefined complex type %1 must have itself as base type").arg(formatType(m_namePool, type))); + return; + } + } else if (isSchemaTag(XsdSchemaToken::Group, token, namespaceToken)) { + const XsdModelGroup::Ptr group = parseNamedGroup(); + redefinedGroups.append(group); + } else if (isSchemaTag(XsdSchemaToken::AttributeGroup, token, namespaceToken)) { + const XsdAttributeGroup::Ptr group = parseNamedAttributeGroup(); + redefinedAttributeGroups.append(group); + + } else { + parseUnknown(); + } + } + } + + bool locationMustResolve = false; + if (!redefinedSimpleTypes.isEmpty() || !redefinedComplexTypes.isEmpty() || + !redefinedGroups.isEmpty() || !redefinedAttributeGroups.isEmpty()) { + locationMustResolve = true; + } + + QUrl url(schemaLocation); + if (url.isRelative()) { + Q_ASSERT(m_documentURI.isValid()); + + url = m_documentURI.resolved(url); + } + + // we parse the schema given in the redefine tag into its own context + const XsdSchemaParserContext::Ptr redefinedContext(new XsdSchemaParserContext(m_namePool, m_context)); + + if (m_redefinedSchemas.contains(url)) { + // we have redefined that file already, according to the schema spec we are + // allowed to silently skip it. + } else { + m_redefinedSchemas.insert(url); + QNetworkReply *reply = AccelTreeResourceLoader::load(url, m_context->networkAccessManager(), + m_context, + (locationMustResolve ? AccelTreeResourceLoader::FailOnError : AccelTreeResourceLoader::ContinueOnError)); + if (reply) { + // parse the included schema by a different parser but with the same context + XsdSchemaParser parser(m_context, redefinedContext, reply); + parser.setDocumentURI(url); + parser.setTargetNamespaceExtended(m_targetNamespace); + parser.setIncludedSchemas(m_includedSchemas); + parser.setImportedSchemas(m_importedSchemas); + parser.setRedefinedSchemas(m_redefinedSchemas); + if (!parser.parse(XsdSchemaParser::RedefineParser)) + return; + + delete reply; + } + } + + XsdSimpleType::List contextSimpleTypes = redefinedContext->schema()->simpleTypes(); + XsdComplexType::List contextComplexTypes = redefinedContext->schema()->complexTypes(); + XsdModelGroup::List contextGroups = redefinedContext->schema()->elementGroups(); + XsdAttributeGroup::List contextAttributeGroups = redefinedContext->schema()->attributeGroups(); + + // now we do the actual redefinition: + + // iterate over all redefined simple types + for (int i = 0; i < redefinedSimpleTypes.count(); ++i) { + XsdSimpleType::Ptr redefinedType = redefinedSimpleTypes.at(i); + + //TODONEXT: validation + + // search the definition they override in the context types + bool found = false; + for (int j = 0; j < contextSimpleTypes.count(); ++j) { + XsdSimpleType::Ptr contextType = contextSimpleTypes.at(j); + + if (redefinedType->name(m_namePool) == contextType->name(m_namePool)) { // we found the right type + found = true; + + // 1) set name of context type to empty name + contextType->setName(m_parserContext->createAnonymousName(QString())); + + // 2) set the context type as base type for the redefined type + redefinedType->setWxsSuperType(contextType); + + // 3) remove the base type resolving job from the resolver as + // we have set the base type here explicitely + m_parserContext->resolver()->removeSimpleRestrictionBase(redefinedType); + + // 4) add the redefined type to the schema + addType(redefinedType); + + // 5) add the context type as anonymous type, so the resolver + // can resolve it further. + addAnonymousType(contextType); + + // 6) remove the context type from the list + contextSimpleTypes.removeAt(j); + + break; + } + } + + if (!found) { + error(QString::fromLatin1("no matching type found to redefine simple type %1").arg(formatType(m_namePool, redefinedType))); + return; + } + } + + // add all remaining context simple types to the schema + for (int i = 0; i < contextSimpleTypes.count(); ++i) { + addType(contextSimpleTypes.at(i)); + } + + // iterate over all redefined complex types + for (int i = 0; i < redefinedComplexTypes.count(); ++i) { + XsdComplexType::Ptr redefinedType = redefinedComplexTypes.at(i); + + //TODONEXT: validation + + // search the definition they override in the context types + bool found = false; + for (int j = 0; j < contextComplexTypes.count(); ++j) { + XsdComplexType::Ptr contextType = contextComplexTypes.at(j); + + if (redefinedType->name(m_namePool) == contextType->name(m_namePool)) { // we found the right type + found = true; + + // 1) set name of context type to empty name + contextType->setName(m_parserContext->createAnonymousName(QString())); + + // 2) set the context type as base type for the redefined type + redefinedType->setWxsSuperType(contextType); + + // 3) remove the base type resolving job from the resolver as + // we have set the base type here explicitely + m_parserContext->resolver()->removeComplexBaseType(redefinedType); + + // 4) add the redefined type to the schema + addType(redefinedType); + + // 5) add the context type as anonymous type, so the resolver + // can resolve its attribute uses etc. + addAnonymousType(contextType); + + // 6) remove the context type from the list + contextComplexTypes.removeAt(j); + + break; + } + } + + if (!found) { + error(QString::fromLatin1("no matching type found to redefine complex type %1").arg(formatType(m_namePool, redefinedType))); + return; + } + } + + // iterate over all redefined element groups + for (int i = 0; i < redefinedGroups.count(); ++i) { + const XsdModelGroup::Ptr group(redefinedGroups.at(i)); + + // @see http://www.w3.org/TR/xmlschema11-1/#src-redefine + + // 6 + const XsdParticle::List particles = collectGroupRef(group); + XsdParticle::Ptr referencedParticle; + int sameNameCounter = 0; + for (int i = 0; i < particles.count(); ++i) { + const XsdReference::Ptr ref(particles.at(i)->term()); + if (ref->referenceName() == group->name(m_namePool)) { + referencedParticle = particles.at(i); + + if (referencedParticle->minimumOccurs() != 1 || referencedParticle->maximumOccurs() != 1 || referencedParticle->maximumOccursUnbounded()) { // 6.1.2 + error(QString::fromLatin1("redefined group %1 can not contain reference to itself with minOccurs or maxOccurs != 1").arg(formatKeyword(group->displayName(m_namePool)))); + return; + } + sameNameCounter++; + } + } + + // 6.1.1 + if (sameNameCounter > 1) { + error(QString::fromLatin1("redefined group %1 can not contain multiple references to itself").arg(formatKeyword(group->displayName(m_namePool)))); + return; + } + + // search the group definition in the included schema (S2) + XsdModelGroup::Ptr contextGroup; + for (int j = 0; j < contextGroups.count(); ++j) { + if (group->name(m_namePool) == contextGroups.at(j)->name(m_namePool)) { + contextGroup = contextGroups.at(j); + break; + } + } + + if (!contextGroup) { // 6.2.1 + error(QString::fromLatin1("redefined group %1 has no occurrence in included schema").arg(formatKeyword(group->displayName(m_namePool)))); + return; + } + + if (sameNameCounter == 1) { + // there was a self reference in the redefined group, so use the + // group from the included schema + + // set a anonymous name to the group of the included schema + contextGroup->setName(m_parserContext->createAnonymousName(m_namePool->stringForNamespace(contextGroup->name(m_namePool).namespaceURI()))); + + // replace the self-reference with the group from the included schema + referencedParticle->setTerm(contextGroup); + + addElementGroup(group); + + addElementGroup(contextGroup); + contextGroups.removeAll(contextGroup); + } else { + // there was no self reference in the redefined group + + // just add the redefined group... + addElementGroup(group); + + // we have to add them, otherwise it is not resolved and we can't validate it later + contextGroup->setName(m_parserContext->createAnonymousName(m_namePool->stringForNamespace(contextGroup->name(m_namePool).namespaceURI()))); + addElementGroup(contextGroup); + + m_schemaResolver->addRedefinedGroups(group, contextGroup); + + // ...and forget about the group from the included schema + contextGroups.removeAll(contextGroup); + } + } + + // iterate over all redefined attribute groups + for (int i = 0; i < redefinedAttributeGroups.count(); ++i) { + const XsdAttributeGroup::Ptr group(redefinedAttributeGroups.at(i)); + + // @see http://www.w3.org/TR/xmlschema11-1/#src-redefine + + // 7 + + // 7.1 + int sameNameCounter = 0; + for (int j = 0; j < group->attributeUses().count(); ++j) { + const XsdAttributeUse::Ptr attributeUse(group->attributeUses().at(j)); + if (attributeUse->isReference()) { + const XsdAttributeReference::Ptr reference(attributeUse); + if (reference->type() == XsdAttributeReference::AttributeGroup) { + if (group->name(m_namePool) == reference->referenceName()) + sameNameCounter++; + } + } + } + if (sameNameCounter > 1) { + error(QString::fromLatin1("redefined attribute group %1 can not contain multiple references to itself").arg(formatKeyword(group->displayName(m_namePool)))); + return; + } + + // search the attribute group definition in the included schema (S2) + XsdAttributeGroup::Ptr baseGroup; + for (int j = 0; j < contextAttributeGroups.count(); ++j) { + const XsdAttributeGroup::Ptr contextGroup(contextAttributeGroups.at(j)); + if (group->name(m_namePool) == contextGroup->name(m_namePool)) { + baseGroup = contextGroup; + break; + } + } + + if (!baseGroup) { // 7.2.1 + error(QString::fromLatin1("redefined attribute group %1 has no occurrence in included schema").arg(formatKeyword(group->displayName(m_namePool)))); + return; + } + + if (sameNameCounter == 1) { + + // first set an anonymous name to the attribute group from the included + // schema + baseGroup->setName(m_parserContext->createAnonymousName(m_namePool->stringForNamespace(baseGroup->name(m_namePool).namespaceURI()))); + + // iterate over the attribute uses of the redefined attribute group + // and replace the self-reference with the attribute group from the + // included schema + for (int j = 0; j < group->attributeUses().count(); ++j) { + const XsdAttributeUse::Ptr attributeUse(group->attributeUses().at(j)); + if (attributeUse->isReference()) { + const XsdAttributeReference::Ptr reference(attributeUse); + if (reference->type() == XsdAttributeReference::AttributeGroup) { + if (group->name(m_namePool) == reference->referenceName()) { + reference->setReferenceName(baseGroup->name(m_namePool)); + break; + } + } + } + } + + // add both groups to the target schema + addAttributeGroup(baseGroup); + addAttributeGroup(group); + + contextAttributeGroups.removeAll(baseGroup); + } + + if (sameNameCounter == 0) { // 7.2 + + // we have to add them, otherwise it is not resolved and we can't validate it later + baseGroup->setName(m_parserContext->createAnonymousName(m_namePool->stringForNamespace(baseGroup->name(m_namePool).namespaceURI()))); + addAttributeGroup(baseGroup); + + m_schemaResolver->addRedefinedAttributeGroups(group, baseGroup); + + // just add the redefined attribute group to the target schema... + addAttributeGroup(group); + + // ... and forget about the one from the included schema + contextAttributeGroups.removeAll(baseGroup); + } + } + + // add all remaining context complex types to the schema + for (int i = 0; i < contextComplexTypes.count(); ++i) { + addType(contextComplexTypes.at(i)); + } + + // add all remaining context element groups to the schema + for (int i = 0; i < contextGroups.count(); ++i) { + addElementGroup(contextGroups.at(i)); + } + + // add all remaining context attribute groups to the schema + for (int i = 0; i < contextAttributeGroups.count(); ++i) { + addAttributeGroup(contextAttributeGroups.at(i)); + } + + // copy all elements, attributes and notations + const XsdElement::List contextElements = redefinedContext->schema()->elements(); + for (int i = 0; i < contextElements.count(); ++i) { + addElement(contextElements.at(i)); + } + + const XsdAttribute::List contextAttributes = redefinedContext->schema()->attributes(); + for (int i = 0; i < contextAttributes.count(); ++i) { + addAttribute(contextAttributes.at(i)); + } + + const XsdNotation::List contextNotations = redefinedContext->schema()->notations(); + for (int i = 0; i < contextNotations.count(); ++i) { + addNotation(contextNotations.at(i)); + } + + // push all data to resolve from the context resolver to our resolver + redefinedContext->resolver()->copyDataTo(m_parserContext->resolver()); + + tagValidator.finalize(); +} + +XsdAnnotation::Ptr XsdSchemaParser::parseAnnotation() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Annotation, this); + + validateElement(XsdTagScope::Annotation); + + // parse attributes + validateIdAttribute("annotation"); + + TagValidationHandler tagValidator(XsdTagScope::Annotation, this, m_namePool); + + const XsdAnnotation::Ptr annotation(new XsdAnnotation()); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Appinfo, token, namespaceToken)) { + const XsdApplicationInformation::Ptr info = parseAppInfo(); + annotation->addApplicationInformation(info); + } else if (isSchemaTag(XsdSchemaToken::Documentation, token, namespaceToken)) { + const XsdDocumentation::Ptr documentation = parseDocumentation(); + annotation->addDocumentation(documentation); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + return annotation; +} + +XsdApplicationInformation::Ptr XsdSchemaParser::parseAppInfo() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Appinfo, this); + + validateElement(XsdTagScope::AppInfo); + + const XsdApplicationInformation::Ptr info(new XsdApplicationInformation()); + + // parse attributes + if (hasAttribute(QString::fromLatin1("source"))) { + const QString value = readAttribute(QString::fromLatin1("source")); + + if (!isValidUri(value)) { + attributeContentError("source", "appinfo", value, BuiltinTypes::xsAnyURI); + return info; + } + + if (!value.isEmpty()) { + const AnyURI::Ptr source = AnyURI::fromLexical(value); + info->setSource(source); + } + } + + while (!atEnd()) { //EVAL: can be anything... what to do? + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) + parseUnknownDocumentation(); + } + + return info; +} + +XsdDocumentation::Ptr XsdSchemaParser::parseDocumentation() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Documentation, this); + + validateElement(XsdTagScope::Documentation); + + const XsdDocumentation::Ptr documentation(new XsdDocumentation()); + + // parse attributes + if (hasAttribute(QString::fromLatin1("source"))) { + const QString value = readAttribute(QString::fromLatin1("source")); + + if (!isValidUri(value)) { + attributeContentError("source", "documentation", value, BuiltinTypes::xsAnyURI); + return documentation; + } + + if (!value.isEmpty()) { + const AnyURI::Ptr source = AnyURI::fromLexical(value); + documentation->setSource(source); + } + } + + if (hasAttribute(CommonNamespaces::XML, QString::fromLatin1("lang"))) { + const QString value = readAttribute(QString::fromLatin1("lang"), CommonNamespaces::XML); + + const QRegExp exp(QString::fromLatin1("[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*")); + if (!exp.exactMatch(value)) { + attributeContentError("xml:lang", "documentation", value); + return documentation; + } + } + + while (!atEnd()) { //EVAL: can by any... what to do? + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) + parseUnknownDocumentation(); + } + + return documentation; +} + +void XsdSchemaParser::parseDefaultOpenContent() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::DefaultOpenContent, this); + + validateElement(XsdTagScope::DefaultOpenContent); + + m_defaultOpenContent = XsdComplexType::OpenContent::Ptr(new XsdComplexType::OpenContent()); + + if (hasAttribute(QString::fromLatin1("appliesToEmpty"))) { + const QString value = readAttribute(QString::fromLatin1("appliesToEmpty")); + const Boolean::Ptr appliesToEmpty = Boolean::fromLexical(value); + if (appliesToEmpty->hasError()) { + attributeContentError("appliesToEmpty", "defaultOpenContent", value, BuiltinTypes::xsBoolean); + return; + } + + m_defaultOpenContentAppliesToEmpty = appliesToEmpty->as<Boolean>()->value(); + } else { + m_defaultOpenContentAppliesToEmpty = false; + } + + if (hasAttribute(QString::fromLatin1("mode"))) { + const QString mode = readAttribute(QString::fromLatin1("mode")); + + if (mode == QString::fromLatin1("interleave")) { + m_defaultOpenContent->setMode(XsdComplexType::OpenContent::Interleave); + } else if (mode == QString::fromLatin1("suffix")) { + m_defaultOpenContent->setMode(XsdComplexType::OpenContent::Suffix); + } else { + attributeContentError("mode", "defaultOpenContent", mode); + return; + } + } else { + m_defaultOpenContent->setMode(XsdComplexType::OpenContent::Interleave); + } + + validateIdAttribute("defaultOpenContent"); + + TagValidationHandler tagValidator(XsdTagScope::DefaultOpenContent, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + m_defaultOpenContent->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::Any, token, namespaceToken)) { + const XsdParticle::Ptr particle; + const XsdWildcard::Ptr wildcard = parseAny(particle); + m_defaultOpenContent->setWildcard(wildcard); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); +} + +XsdSimpleType::Ptr XsdSchemaParser::parseGlobalSimpleType() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::SimpleType, this); + + validateElement(XsdTagScope::GlobalSimpleType); + + const XsdSimpleType::Ptr simpleType(new XsdSimpleType()); + simpleType->setCategory(XsdSimpleType::SimpleTypeAtomic); // just to make sure it's not invalid + + // parse attributes + const SchemaType::DerivationConstraints allowedConstraints(SchemaType::ExtensionConstraint | SchemaType::RestrictionConstraint | SchemaType::ListConstraint | SchemaType::UnionConstraint); + simpleType->setDerivationConstraints(readDerivationConstraintAttribute(allowedConstraints, "simpleType")); + + const QXmlName objectName = m_namePool->allocateQName(m_targetNamespace, readNameAttribute("simpleType")); + simpleType->setName(objectName); + + validateIdAttribute("simpleType"); + + TagValidationHandler tagValidator(XsdTagScope::GlobalSimpleType, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + simpleType->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::Restriction, token, namespaceToken)) { + parseSimpleRestriction(simpleType); + } else if (isSchemaTag(XsdSchemaToken::List, token, namespaceToken)) { + parseList(simpleType); + } else if (isSchemaTag(XsdSchemaToken::Union, token, namespaceToken)) { + parseUnion(simpleType); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + return simpleType; +} + +XsdSimpleType::Ptr XsdSchemaParser::parseLocalSimpleType() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::SimpleType, this); + + validateElement(XsdTagScope::LocalSimpleType); + + const XsdSimpleType::Ptr simpleType(new XsdSimpleType()); + simpleType->setCategory(XsdSimpleType::SimpleTypeAtomic); // just to make sure it's not invalid + simpleType->setName(m_parserContext->createAnonymousName(m_targetNamespace)); + + validateIdAttribute("simpleType"); + + TagValidationHandler tagValidator(XsdTagScope::LocalSimpleType, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + simpleType->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::Restriction, token, namespaceToken)) { + parseSimpleRestriction(simpleType); + } else if (isSchemaTag(XsdSchemaToken::List, token, namespaceToken)) { + parseList(simpleType); + } else if (isSchemaTag(XsdSchemaToken::Union, token, namespaceToken)) { + parseUnion(simpleType); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + return simpleType; +} + +void XsdSchemaParser::parseSimpleRestriction(const XsdSimpleType::Ptr &ptr) +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Restriction, this); + + validateElement(XsdTagScope::SimpleRestriction); + + ptr->setDerivationMethod(XsdSimpleType::DerivationRestriction); + + // The base attribute and simpleType member are mutually exclusive, + // so we keep track of that + bool hasBaseAttribute = false; + bool hasBaseTypeSpecified = false; + + QXmlName baseName; + if (hasAttribute(QString::fromLatin1("base"))) { + const QString base = readQNameAttribute(QString::fromLatin1("base"), "restriction"); + convertName(base, NamespaceSupport::ElementName, baseName); // translate qualified name into QXmlName + m_schemaResolver->addSimpleRestrictionBase(ptr, baseName, currentSourceLocation()); // add to resolver + + hasBaseAttribute = true; + hasBaseTypeSpecified = true; + } + validateIdAttribute("restriction"); + + XsdFacet::Hash facets; + QList<XsdFacet::Ptr> patternFacets; + QList<XsdFacet::Ptr> enumerationFacets; + QList<XsdFacet::Ptr> assertionFacets; + + TagValidationHandler tagValidator(XsdTagScope::SimpleRestriction, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + ptr->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::SimpleType, token, namespaceToken)) { + if (hasBaseAttribute) { + error(QtXmlPatterns::tr("%1 element is not allowed inside %2 element if %3 attribute is present") + .arg(formatElement("simpleType")) + .arg(formatElement("restriction")) + .arg(formatAttribute("base"))); + return; + } + + const XsdSimpleType::Ptr type = parseLocalSimpleType(); + type->setContext(ptr); + ptr->setWxsSuperType(type); + ptr->setCategory(type->category()); + hasBaseTypeSpecified = true; + + // add it to list of anonymous types as well + addAnonymousType(type); + } else if (isSchemaTag(XsdSchemaToken::MinExclusive, token, namespaceToken)) { + const XsdFacet::Ptr facet = parseMinExclusiveFacet(); + addFacet(facet, facets, ptr); + } else if (isSchemaTag(XsdSchemaToken::MinInclusive, token, namespaceToken)) { + const XsdFacet::Ptr facet = parseMinInclusiveFacet(); + addFacet(facet, facets, ptr); + } else if (isSchemaTag(XsdSchemaToken::MaxExclusive, token, namespaceToken)) { + const XsdFacet::Ptr facet = parseMaxExclusiveFacet(); + addFacet(facet, facets, ptr); + } else if (isSchemaTag(XsdSchemaToken::MaxInclusive, token, namespaceToken)) { + const XsdFacet::Ptr facet = parseMaxInclusiveFacet(); + addFacet(facet, facets, ptr); + } else if (isSchemaTag(XsdSchemaToken::TotalDigits, token, namespaceToken)) { + const XsdFacet::Ptr facet = parseTotalDigitsFacet(); + addFacet(facet, facets, ptr); + } else if (isSchemaTag(XsdSchemaToken::FractionDigits, token, namespaceToken)) { + const XsdFacet::Ptr facet = parseFractionDigitsFacet(); + addFacet(facet, facets, ptr); + } else if (isSchemaTag(XsdSchemaToken::Length, token, namespaceToken)) { + const XsdFacet::Ptr facet = parseLengthFacet(); + addFacet(facet, facets, ptr); + } else if (isSchemaTag(XsdSchemaToken::MinLength, token, namespaceToken)) { + const XsdFacet::Ptr facet = parseMinLengthFacet(); + addFacet(facet, facets, ptr); + } else if (isSchemaTag(XsdSchemaToken::MaxLength, token, namespaceToken)) { + const XsdFacet::Ptr facet = parseMaxLengthFacet(); + addFacet(facet, facets, ptr); + } else if (isSchemaTag(XsdSchemaToken::Enumeration, token, namespaceToken)) { + const XsdFacet::Ptr facet = parseEnumerationFacet(); + enumerationFacets.append(facet); + } else if (isSchemaTag(XsdSchemaToken::WhiteSpace, token, namespaceToken)) { + const XsdFacet::Ptr facet = parseWhiteSpaceFacet(); + addFacet(facet, facets, ptr); + } else if (isSchemaTag(XsdSchemaToken::Pattern, token, namespaceToken)) { + const XsdFacet::Ptr facet = parsePatternFacet(); + patternFacets.append(facet); + } else if (isSchemaTag(XsdSchemaToken::Assertion, token, namespaceToken)) { + const XsdFacet::Ptr facet = parseAssertionFacet(); + assertionFacets.append(facet); + } else { + parseUnknown(); + } + } + } + + if (!hasBaseTypeSpecified) { + error(QtXmlPatterns::tr("%1 element has neither %2 attribute nor %3 child element") + .arg(formatElement("restriction")) + .arg(formatAttribute("base")) + .arg(formatElement("simpleType"))); + return; + } + + // merge all pattern facets into one multi value facet + if (!patternFacets.isEmpty()) { + const XsdFacet::Ptr patternFacet(new XsdFacet()); + patternFacet->setType(XsdFacet::Pattern); + + AtomicValue::List multiValue; + for (int i = 0; i < patternFacets.count(); ++i) + multiValue << patternFacets.at(i)->multiValue(); + + patternFacet->setMultiValue(multiValue); + addFacet(patternFacet, facets, ptr); + } + + // merge all enumeration facets into one multi value facet + if (!enumerationFacets.isEmpty()) { + const XsdFacet::Ptr enumerationFacet(new XsdFacet()); + enumerationFacet->setType(XsdFacet::Enumeration); + + AtomicValue::List multiValue; + for (int i = 0; i < enumerationFacets.count(); ++i) + multiValue << enumerationFacets.at(i)->multiValue(); + + enumerationFacet->setMultiValue(multiValue); + addFacet(enumerationFacet, facets, ptr); + } + + // merge all assertion facets into one facet + if (!assertionFacets.isEmpty()) { + const XsdFacet::Ptr assertionFacet(new XsdFacet()); + assertionFacet->setType(XsdFacet::Assertion); + + XsdAssertion::List assertions; + for (int i = 0; i < assertionFacets.count(); ++i) + assertions << assertionFacets.at(i)->assertions(); + + assertionFacet->setAssertions(assertions); + addFacet(assertionFacet, facets, ptr); + } + + ptr->setFacets(facets); + + tagValidator.finalize(); +} + +void XsdSchemaParser::parseList(const XsdSimpleType::Ptr &ptr) +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::List, this); + + validateElement(XsdTagScope::List); + + ptr->setCategory(XsdSimpleType::SimpleTypeList); + ptr->setDerivationMethod(XsdSimpleType::DerivationList); + ptr->setWxsSuperType(BuiltinTypes::xsAnySimpleType); + + // The itemType attribute and simpleType member are mutually exclusive, + // so we keep track of that + bool hasItemTypeAttribute = false; + bool hasItemTypeSpecified = false; + + if (hasAttribute(QString::fromLatin1("itemType"))) { + const QString itemType = readQNameAttribute(QString::fromLatin1("itemType"), "list"); + QXmlName typeName; + convertName(itemType, NamespaceSupport::ElementName, typeName); // translate qualified name into QXmlName + m_schemaResolver->addSimpleListType(ptr, typeName, currentSourceLocation()); // add to resolver + + hasItemTypeAttribute = true; + hasItemTypeSpecified = true; + } + + validateIdAttribute("list"); + + TagValidationHandler tagValidator(XsdTagScope::List, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + ptr->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::SimpleType, token, namespaceToken)) { + if (hasItemTypeAttribute) { + error(QtXmlPatterns::tr("%1 element is not allowed inside %2 element if %3 attribute is present") + .arg(formatElement("simpleType")) + .arg(formatElement("list")) + .arg(formatAttribute("itemType"))); + return; + } + + const XsdSimpleType::Ptr type = parseLocalSimpleType(); + type->setContext(ptr); + ptr->setItemType(type); + + hasItemTypeSpecified = true; + + // add it to list of anonymous types as well + addAnonymousType(type); + } else { + parseUnknown(); + } + } + } + + if (!hasItemTypeSpecified) { + error(QtXmlPatterns::tr("%1 element has neither %2 attribute nor %3 child element") + .arg(formatElement("list")) + .arg(formatAttribute("itemType")) + .arg(formatElement("simpleType"))); + return; + } + + tagValidator.finalize(); + + // add the default white space facet that every simple type with list derivation has + const XsdFacet::Ptr defaultFacet(new XsdFacet()); + defaultFacet->setType(XsdFacet::WhiteSpace); + defaultFacet->setFixed(true); + defaultFacet->setValue(DerivedString<TypeString>::fromLexical(m_namePool, XsdSchemaToken::toString(XsdSchemaToken::Collapse))); + XsdFacet::Hash facets; + facets.insert(defaultFacet->type(), defaultFacet); + ptr->setFacets(facets); +} + +void XsdSchemaParser::parseUnion(const XsdSimpleType::Ptr &ptr) +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Union, this); + + validateElement(XsdTagScope::Union); + + ptr->setCategory(XsdSimpleType::SimpleTypeUnion); + ptr->setDerivationMethod(XsdSimpleType::DerivationUnion); + ptr->setWxsSuperType(BuiltinTypes::xsAnySimpleType); + + // The memberTypes attribute is not allowed to be empty, + // so we keep track of that + bool hasMemberTypesAttribute = false; + bool hasMemberTypesSpecified = false; + + if (hasAttribute(QString::fromLatin1("memberTypes"))) { + hasMemberTypesAttribute = true; + + const QStringList memberTypes = readAttribute(QString::fromLatin1("memberTypes")).split(QLatin1Char(' '), QString::SkipEmptyParts); + QList<QXmlName> typeNames; + + for (int i = 0; i < memberTypes.count(); ++i) { + QXmlName typeName; + convertName(memberTypes.at(i), NamespaceSupport::ElementName, typeName); // translate qualified name into QXmlName + typeNames.append(typeName); + } + + if (!typeNames.isEmpty()) { + m_schemaResolver->addSimpleUnionTypes(ptr, typeNames, currentSourceLocation()); // add to resolver + hasMemberTypesSpecified = true; + } + } + + validateIdAttribute("union"); + + AnySimpleType::List memberTypes; + + TagValidationHandler tagValidator(XsdTagScope::Union, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + ptr->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::SimpleType, token, namespaceToken)) { + const XsdSimpleType::Ptr type = parseLocalSimpleType(); + type->setContext(ptr); + memberTypes.append(type); + + // add it to list of anonymous types as well + addAnonymousType(type); + } else { + parseUnknown(); + } + } + } + + if (!memberTypes.isEmpty()) { + ptr->setMemberTypes(memberTypes); + hasMemberTypesSpecified = true; + } + + if (!hasMemberTypesSpecified) { + error(QtXmlPatterns::tr("%1 element has neither %2 attribute nor %3 child element") + .arg(formatElement("union")) + .arg(formatAttribute("memberTypes")) + .arg(formatElement("simpleType"))); + return; + } + + tagValidator.finalize(); +} + +XsdFacet::Ptr XsdSchemaParser::parseMinExclusiveFacet() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::MinExclusive, this); + + validateElement(XsdTagScope::MinExclusiveFacet); + + const XsdFacet::Ptr facet = XsdFacet::Ptr(new XsdFacet()); + facet->setType(XsdFacet::MinimumExclusive); + + // parse attributes + if (hasAttribute(QString::fromLatin1("fixed"))) { + const QString value = readAttribute(QString::fromLatin1("fixed")); + const Boolean::Ptr fixed = Boolean::fromLexical(value); + if (fixed->hasError()) { + attributeContentError("fixed", "minExclusive", value, BuiltinTypes::xsBoolean); + return facet; + } + + facet->setFixed(fixed->as<Boolean>()->value()); + } else { + facet->setFixed(false); // the default value + } + + // as minExclusive can have a value of type anySimpleType, we just read + // the string here and store it for later intepretation + const QString value = readAttribute(QString::fromLatin1("value")); + DerivedString<TypeString>::Ptr string = DerivedString<TypeString>::fromLexical(m_namePool, value); + if (string->hasError()) { + attributeContentError("value", "minExclusive", value, BuiltinTypes::xsAnySimpleType); + return facet; + } else { + facet->setValue(string); + } + + validateIdAttribute("minExclusive"); + + TagValidationHandler tagValidator(XsdTagScope::MinExclusiveFacet, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + facet->addAnnotation(annotation); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + return facet; +} + +XsdFacet::Ptr XsdSchemaParser::parseMinInclusiveFacet() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::MinInclusive, this); + + validateElement(XsdTagScope::MinInclusiveFacet); + + const XsdFacet::Ptr facet = XsdFacet::Ptr(new XsdFacet()); + facet->setType(XsdFacet::MinimumInclusive); + + // parse attributes + if (hasAttribute(QString::fromLatin1("fixed"))) { + const QString value = readAttribute(QString::fromLatin1("fixed")); + const Boolean::Ptr fixed = Boolean::fromLexical(value); + if (fixed->hasError()) { + attributeContentError("fixed", "minInclusive", value, BuiltinTypes::xsBoolean); + return facet; + } + + facet->setFixed(fixed->as<Boolean>()->value()); + } else { + facet->setFixed(false); // the default value + } + + // as minInclusive can have a value of type anySimpleType, we just read + // the string here and store it for later intepretation + const QString value = readAttribute(QString::fromLatin1("value")); + DerivedString<TypeString>::Ptr string = DerivedString<TypeString>::fromLexical(m_namePool, value); + if (string->hasError()) { + attributeContentError("value", "minInclusive", value, BuiltinTypes::xsAnySimpleType); + return facet; + } else { + facet->setValue(string); + } + + validateIdAttribute("minInclusive"); + + TagValidationHandler tagValidator(XsdTagScope::MinInclusiveFacet, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + facet->addAnnotation(annotation); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + return facet; +} + +XsdFacet::Ptr XsdSchemaParser::parseMaxExclusiveFacet() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::MaxExclusive, this); + + validateElement(XsdTagScope::MaxExclusiveFacet); + + const XsdFacet::Ptr facet = XsdFacet::Ptr(new XsdFacet()); + facet->setType(XsdFacet::MaximumExclusive); + + // parse attributes + if (hasAttribute(QString::fromLatin1("fixed"))) { + const QString value = readAttribute(QString::fromLatin1("fixed")); + const Boolean::Ptr fixed = Boolean::fromLexical(value); + if (fixed->hasError()) { + attributeContentError("fixed", "maxExclusive", value, BuiltinTypes::xsBoolean); + return facet; + } + + facet->setFixed(fixed->as<Boolean>()->value()); + } else { + facet->setFixed(false); // the default value + } + + // as maxExclusive can have a value of type anySimpleType, we just read + // the string here and store it for later intepretation + const QString value = readAttribute(QString::fromLatin1("value")); + DerivedString<TypeString>::Ptr string = DerivedString<TypeString>::fromLexical(m_namePool, value); + if (string->hasError()) { + attributeContentError("value", "maxExclusive", value, BuiltinTypes::xsAnySimpleType); + return facet; + } else { + facet->setValue(string); + } + + validateIdAttribute("maxExclusive"); + + TagValidationHandler tagValidator(XsdTagScope::MaxExclusiveFacet, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + facet->addAnnotation(annotation); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + return facet; +} + +XsdFacet::Ptr XsdSchemaParser::parseMaxInclusiveFacet() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::MaxInclusive, this); + + validateElement(XsdTagScope::MaxInclusiveFacet); + + const XsdFacet::Ptr facet = XsdFacet::Ptr(new XsdFacet()); + facet->setType(XsdFacet::MaximumInclusive); + + // parse attributes + if (hasAttribute(QString::fromLatin1("fixed"))) { + const QString value = readAttribute(QString::fromLatin1("fixed")); + const Boolean::Ptr fixed = Boolean::fromLexical(value); + if (fixed->hasError()) { + attributeContentError("fixed", "maxInclusive", value, BuiltinTypes::xsBoolean); + return facet; + } + + facet->setFixed(fixed->as<Boolean>()->value()); + } else { + facet->setFixed(false); // the default value + } + + // as maxInclusive can have a value of type anySimpleType, we just read + // the string here and store it for later intepretation + const QString value = readAttribute(QString::fromLatin1("value")); + DerivedString<TypeString>::Ptr string = DerivedString<TypeString>::fromLexical(m_namePool, value); + if (string->hasError()) { + attributeContentError("value", "maxInclusive", value, BuiltinTypes::xsAnySimpleType); + return facet; + } else { + facet->setValue(string); + } + + validateIdAttribute("maxInclusive"); + + TagValidationHandler tagValidator(XsdTagScope::MaxInclusiveFacet, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + facet->addAnnotation(annotation); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + return facet; +} + +XsdFacet::Ptr XsdSchemaParser::parseTotalDigitsFacet() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::TotalDigits, this); + + validateElement(XsdTagScope::TotalDigitsFacet); + + const XsdFacet::Ptr facet = XsdFacet::Ptr(new XsdFacet()); + facet->setType(XsdFacet::TotalDigits); + + // parse attributes + if (hasAttribute(QString::fromLatin1("fixed"))) { + const QString value = readAttribute(QString::fromLatin1("fixed")); + const Boolean::Ptr fixed = Boolean::fromLexical(value); + if (fixed->hasError()) { + attributeContentError("fixed", "totalDigits", value, BuiltinTypes::xsBoolean); + return facet; + } + + facet->setFixed(fixed->as<Boolean>()->value()); + } else { + facet->setFixed(false); // the default value + } + + const QString value = readAttribute(QString::fromLatin1("value")); + DerivedInteger<TypePositiveInteger>::Ptr integer = DerivedInteger<TypePositiveInteger>::fromLexical(m_namePool, value); + if (integer->hasError()) { + attributeContentError("value", "totalDigits", value, BuiltinTypes::xsPositiveInteger); + return facet; + } else { + facet->setValue(integer); + } + + validateIdAttribute("totalDigits"); + + TagValidationHandler tagValidator(XsdTagScope::TotalDigitsFacet, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + facet->addAnnotation(annotation); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + return facet; +} + +XsdFacet::Ptr XsdSchemaParser::parseFractionDigitsFacet() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::FractionDigits, this); + + validateElement(XsdTagScope::FractionDigitsFacet); + + const XsdFacet::Ptr facet = XsdFacet::Ptr(new XsdFacet()); + facet->setType(XsdFacet::FractionDigits); + + // parse attributes + if (hasAttribute(QString::fromLatin1("fixed"))) { + const QString value = readAttribute(QString::fromLatin1("fixed")); + const Boolean::Ptr fixed = Boolean::fromLexical(value); + if (fixed->hasError()) { + attributeContentError("fixed", "fractionDigits", value, BuiltinTypes::xsBoolean); + return facet; + } + + facet->setFixed(fixed->as<Boolean>()->value()); + } else { + facet->setFixed(false); // the default value + } + + const QString value = readAttribute(QString::fromLatin1("value")); + DerivedInteger<TypeNonNegativeInteger>::Ptr integer = DerivedInteger<TypeNonNegativeInteger>::fromLexical(m_namePool, value); + if (integer->hasError()) { + attributeContentError("value", "fractionDigits", value, BuiltinTypes::xsNonNegativeInteger); + return facet; + } else { + facet->setValue(integer); + } + + validateIdAttribute("fractionDigits"); + + TagValidationHandler tagValidator(XsdTagScope::FractionDigitsFacet, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + facet->addAnnotation(annotation); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + return facet; +} + +XsdFacet::Ptr XsdSchemaParser::parseLengthFacet() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Length, this); + + validateElement(XsdTagScope::LengthFacet); + + const XsdFacet::Ptr facet = XsdFacet::Ptr(new XsdFacet()); + facet->setType(XsdFacet::Length); + + // parse attributes + if (hasAttribute(QString::fromLatin1("fixed"))) { + const QString value = readAttribute(QString::fromLatin1("fixed")); + const Boolean::Ptr fixed = Boolean::fromLexical(value); + if (fixed->hasError()) { + attributeContentError("fixed", "length", value, BuiltinTypes::xsBoolean); + return facet; + } + + facet->setFixed(fixed->as<Boolean>()->value()); + } else { + facet->setFixed(false); // the default value + } + + const QString value = readAttribute(QString::fromLatin1("value")); + DerivedInteger<TypeNonNegativeInteger>::Ptr integer = DerivedInteger<TypeNonNegativeInteger>::fromLexical(m_namePool, value); + if (integer->hasError()) { + attributeContentError("value", "length", value, BuiltinTypes::xsNonNegativeInteger); + return facet; + } else { + facet->setValue(integer); + } + + validateIdAttribute("length"); + + TagValidationHandler tagValidator(XsdTagScope::LengthFacet, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + facet->addAnnotation(annotation); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + return facet; +} + +XsdFacet::Ptr XsdSchemaParser::parseMinLengthFacet() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::MinLength, this); + + validateElement(XsdTagScope::MinLengthFacet); + + const XsdFacet::Ptr facet = XsdFacet::Ptr(new XsdFacet()); + facet->setType(XsdFacet::MinimumLength); + + // parse attributes + if (hasAttribute(QString::fromLatin1("fixed"))) { + const QString value = readAttribute(QString::fromLatin1("fixed")); + const Boolean::Ptr fixed = Boolean::fromLexical(value); + if (fixed->hasError()) { + attributeContentError("fixed", "minLength", value, BuiltinTypes::xsBoolean); + return facet; + } + + facet->setFixed(fixed->as<Boolean>()->value()); + } else { + facet->setFixed(false); // the default value + } + + const QString value = readAttribute(QString::fromLatin1("value")); + DerivedInteger<TypeNonNegativeInteger>::Ptr integer = DerivedInteger<TypeNonNegativeInteger>::fromLexical(m_namePool, value); + if (integer->hasError()) { + attributeContentError("value", "minLength", value, BuiltinTypes::xsNonNegativeInteger); + return facet; + } else { + facet->setValue(integer); + } + + validateIdAttribute("minLength"); + + TagValidationHandler tagValidator(XsdTagScope::MinLengthFacet, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + facet->addAnnotation(annotation); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + return facet; +} + +XsdFacet::Ptr XsdSchemaParser::parseMaxLengthFacet() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::MaxLength, this); + + validateElement(XsdTagScope::MaxLengthFacet); + + const XsdFacet::Ptr facet = XsdFacet::Ptr(new XsdFacet()); + facet->setType(XsdFacet::MaximumLength); + + // parse attributes + if (hasAttribute(QString::fromLatin1("fixed"))) { + const QString value = readAttribute(QString::fromLatin1("fixed")); + const Boolean::Ptr fixed = Boolean::fromLexical(value); + if (fixed->hasError()) { + attributeContentError("fixed", "maxLength", value, BuiltinTypes::xsBoolean); + return facet; + } + + facet->setFixed(fixed->as<Boolean>()->value()); + } else { + facet->setFixed(false); // the default value + } + + const QString value = readAttribute(QString::fromLatin1("value")); + DerivedInteger<TypeNonNegativeInteger>::Ptr integer = DerivedInteger<TypeNonNegativeInteger>::fromLexical(m_namePool, value); + if (integer->hasError()) { + attributeContentError("value", "maxLength", value, BuiltinTypes::xsNonNegativeInteger); + return facet; + } else { + facet->setValue(integer); + } + + validateIdAttribute("maxLength"); + + TagValidationHandler tagValidator(XsdTagScope::MaxLengthFacet, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + facet->addAnnotation(annotation); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + return facet; +} + +XsdFacet::Ptr XsdSchemaParser::parseEnumerationFacet() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Enumeration, this); + + validateElement(XsdTagScope::EnumerationFacet); + + const XsdFacet::Ptr facet = XsdFacet::Ptr(new XsdFacet()); + facet->setType(XsdFacet::Enumeration); + + // parse attributes + facet->setFixed(false); // not defined in schema, but can't hurt + + const QString value = readAttribute(QString::fromLatin1("value")); + + // as enumeration can have a value of type anySimpleType, we just read + // the string here and store it for later intepretation + DerivedString<TypeString>::Ptr string = DerivedString<TypeString>::fromLexical(m_namePool, value); + if (string->hasError()) { + attributeContentError("value", "enumeration", value); + return facet; + } else { + AtomicValue::List multiValue; + multiValue << string; + facet->setMultiValue(multiValue); + } + m_schemaResolver->addEnumerationFacetValue(string, m_namespaceSupport); + + validateIdAttribute("enumeration"); + + TagValidationHandler tagValidator(XsdTagScope::EnumerationFacet, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + facet->addAnnotation(annotation); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + return facet; +} + +XsdFacet::Ptr XsdSchemaParser::parseWhiteSpaceFacet() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::WhiteSpace, this); + + validateElement(XsdTagScope::WhiteSpaceFacet); + + const XsdFacet::Ptr facet = XsdFacet::Ptr(new XsdFacet()); + facet->setType(XsdFacet::WhiteSpace); + + // parse attributes + if (hasAttribute(QString::fromLatin1("fixed"))) { + const QString value = readAttribute(QString::fromLatin1("fixed")); + const Boolean::Ptr fixed = Boolean::fromLexical(value); + if (fixed->hasError()) { + attributeContentError("fixed", "whiteSpace", value, BuiltinTypes::xsBoolean); + return facet; + } + + facet->setFixed(fixed->as<Boolean>()->value()); + } else { + facet->setFixed(false); // the default value + } + + const QString value = readAttribute(QString::fromLatin1("value")); + if (value != XsdSchemaToken::toString(XsdSchemaToken::Collapse) && + value != XsdSchemaToken::toString(XsdSchemaToken::Preserve) && + value != XsdSchemaToken::toString(XsdSchemaToken::Replace)) { + attributeContentError("value", "whiteSpace", value); + return facet; + } else { + DerivedString<TypeString>::Ptr string = DerivedString<TypeString>::fromLexical(m_namePool, value); + if (string->hasError()) { + attributeContentError("value", "whiteSpace", value); + return facet; + } else { + facet->setValue(string); + } + } + + validateIdAttribute("whiteSpace"); + + TagValidationHandler tagValidator(XsdTagScope::WhiteSpaceFacet, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + facet->addAnnotation(annotation); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + return facet; +} + +XsdFacet::Ptr XsdSchemaParser::parsePatternFacet() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Pattern, this); + + validateElement(XsdTagScope::PatternFacet); + + const XsdFacet::Ptr facet = XsdFacet::Ptr(new XsdFacet()); + facet->setType(XsdFacet::Pattern); + + // parse attributes + + // as pattern can have a value of type anySimpleType, we just read + // the string here and store it for later intepretation + const QString value = readAttribute(QString::fromLatin1("value")); + DerivedString<TypeString>::Ptr string = DerivedString<TypeString>::fromLexical(m_namePool, value); + if (string->hasError()) { + attributeContentError("value", "pattern", value); + return facet; + } else { + AtomicValue::List multiValue; + multiValue << string; + facet->setMultiValue(multiValue); + } + + validateIdAttribute("pattern"); + + TagValidationHandler tagValidator(XsdTagScope::PatternFacet, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + facet->addAnnotation(annotation); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + return facet; +} + +XsdFacet::Ptr XsdSchemaParser::parseAssertionFacet() +{ + // this is just a wrapper function around the parseAssertion() method + + const XsdAssertion::Ptr assertion = parseAssertion(XsdSchemaToken::Assertion, XsdTagScope::Assertion); + + const XsdFacet::Ptr facet = XsdFacet::Ptr(new XsdFacet()); + facet->setType(XsdFacet::Assertion); + facet->setAssertions(XsdAssertion::List() << assertion); + + return facet; +} + +XsdComplexType::Ptr XsdSchemaParser::parseGlobalComplexType() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::ComplexType, this); + + validateElement(XsdTagScope::GlobalComplexType); + + bool hasTypeSpecified = false; + bool hasComplexContent = false; + + const XsdComplexType::Ptr complexType(new XsdComplexType()); + + // parse attributes + if (hasAttribute(QString::fromLatin1("abstract"))) { + const QString abstract = readAttribute(QString::fromLatin1("abstract")); + + const Boolean::Ptr value = Boolean::fromLexical(abstract); + if (value->hasError()) { + attributeContentError("abstract", "complexType", abstract, BuiltinTypes::xsBoolean); + return complexType; + } + + complexType->setIsAbstract(value->as<Boolean>()->value()); + } else { + complexType->setIsAbstract(false); // default value + } + + complexType->setProhibitedSubstitutions(readBlockingConstraintAttribute(NamedSchemaComponent::ExtensionConstraint | NamedSchemaComponent::RestrictionConstraint, "complexType")); + complexType->setDerivationConstraints(readDerivationConstraintAttribute(SchemaType::ExtensionConstraint | SchemaType::RestrictionConstraint, "complexType")); + + const QXmlName objectName = m_namePool->allocateQName(m_targetNamespace, readNameAttribute("complexType")); + complexType->setName(objectName); + + bool effectiveMixed = false; + if (hasAttribute(QString::fromLatin1("mixed"))) { + const QString mixed = readAttribute(QString::fromLatin1("mixed")); + + const Boolean::Ptr value = Boolean::fromLexical(mixed); + if (value->hasError()) { + attributeContentError("mixed", "complexType", mixed, BuiltinTypes::xsBoolean); + return complexType; + } + + effectiveMixed = value->as<Boolean>()->value(); + } + + validateIdAttribute("complexType"); + + TagValidationHandler tagValidator(XsdTagScope::GlobalComplexType, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + complexType->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::SimpleContent, token, namespaceToken)) { + if (effectiveMixed) { + error(QtXmlPatterns::tr("%1 element with %2 child element must not have a %3 attribute") + .arg(formatElement("complexType")) + .arg(formatElement("simpleContent")) + .arg(formatAttribute("mixed"))); + return complexType; + } + + parseSimpleContent(complexType); + hasTypeSpecified = true; + } else if (isSchemaTag(XsdSchemaToken::ComplexContent, token, namespaceToken)) { + bool mixed; + parseComplexContent(complexType, &mixed); + hasTypeSpecified = true; + + effectiveMixed = (effectiveMixed || mixed); + hasComplexContent = true; + } else if (isSchemaTag(XsdSchemaToken::OpenContent, token, namespaceToken)) { + const XsdComplexType::OpenContent::Ptr openContent = parseOpenContent(); + complexType->contentType()->setOpenContent(openContent); + hasComplexContent = true; + } else if (isSchemaTag(XsdSchemaToken::Group, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseReferredGroup(particle); + particle->setTerm(term); + complexType->contentType()->setParticle(particle); + + complexType->setWxsSuperType(BuiltinTypes::xsAnyType); + complexType->contentType()->setVariety(XsdComplexType::ContentType::ElementOnly); + complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); + hasComplexContent = true; + } else if (isSchemaTag(XsdSchemaToken::All, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseLocalAll(particle, complexType); + particle->setTerm(term); + complexType->contentType()->setParticle(particle); + + complexType->setWxsSuperType(BuiltinTypes::xsAnyType); + complexType->contentType()->setVariety(XsdComplexType::ContentType::ElementOnly); + complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); + hasComplexContent = true; + } else if (isSchemaTag(XsdSchemaToken::Choice, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseLocalChoice(particle, complexType); + particle->setTerm(term); + complexType->contentType()->setParticle(particle); + + complexType->setWxsSuperType(BuiltinTypes::xsAnyType); + complexType->contentType()->setVariety(XsdComplexType::ContentType::ElementOnly); + complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); + hasComplexContent = true; + } else if (isSchemaTag(XsdSchemaToken::Sequence, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseLocalSequence(particle, complexType); + particle->setTerm(term); + complexType->contentType()->setParticle(particle); + + complexType->setWxsSuperType(BuiltinTypes::xsAnyType); + complexType->contentType()->setVariety(XsdComplexType::ContentType::ElementOnly); + complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); + hasComplexContent = true; + } else if (isSchemaTag(XsdSchemaToken::Attribute, token, namespaceToken)) { + const XsdAttributeUse::Ptr attributeUse = parseLocalAttribute(complexType); + complexType->addAttributeUse(attributeUse); + + complexType->setWxsSuperType(BuiltinTypes::xsAnyType); + complexType->contentType()->setVariety(XsdComplexType::ContentType::ElementOnly); + complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); + hasComplexContent = true; + } else if (isSchemaTag(XsdSchemaToken::AttributeGroup, token, namespaceToken)) { + const XsdAttributeUse::Ptr attributeUse = parseReferredAttributeGroup(); + complexType->addAttributeUse(attributeUse); + + complexType->setWxsSuperType(BuiltinTypes::xsAnyType); + complexType->contentType()->setVariety(XsdComplexType::ContentType::ElementOnly); + complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); + hasComplexContent = true; + } else if (isSchemaTag(XsdSchemaToken::AnyAttribute, token, namespaceToken)) { + const XsdWildcard::Ptr wildcard = parseAnyAttribute(); + complexType->setAttributeWildcard(wildcard); + + complexType->setWxsSuperType(BuiltinTypes::xsAnyType); + complexType->contentType()->setVariety(XsdComplexType::ContentType::ElementOnly); + complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); + hasComplexContent = true; + } else if (isSchemaTag(XsdSchemaToken::Assert, token, namespaceToken)) { + const XsdAssertion::Ptr assertion = parseAssertion(XsdSchemaToken::Assert, XsdTagScope::Assert); + complexType->addAssertion(assertion); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + if (!hasTypeSpecified) { + complexType->setWxsSuperType(BuiltinTypes::xsAnyType); + complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); + hasComplexContent = true; + } + + if (hasComplexContent == true) { + resolveComplexContentType(complexType, effectiveMixed); + } + + return complexType; +} + +XsdComplexType::Ptr XsdSchemaParser::parseLocalComplexType() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::ComplexType, this); + + validateElement(XsdTagScope::LocalComplexType); + + bool hasTypeSpecified = false; + bool hasComplexContent = true; + + const XsdComplexType::Ptr complexType(new XsdComplexType()); + complexType->setName(m_parserContext->createAnonymousName(m_targetNamespace)); + + // parse attributes + bool effectiveMixed = false; + if (hasAttribute(QString::fromLatin1("mixed"))) { + const QString mixed = readAttribute(QString::fromLatin1("mixed")); + + const Boolean::Ptr value = Boolean::fromLexical(mixed); + if (value->hasError()) { + attributeContentError("mixed", "complexType", mixed, BuiltinTypes::xsBoolean); + return complexType; + } + + effectiveMixed = value->as<Boolean>()->value(); + } + + validateIdAttribute("complexType"); + + TagValidationHandler tagValidator(XsdTagScope::LocalComplexType, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + complexType->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::SimpleContent, token, namespaceToken)) { + parseSimpleContent(complexType); + hasTypeSpecified = true; + } else if (isSchemaTag(XsdSchemaToken::ComplexContent, token, namespaceToken)) { + bool mixed; + parseComplexContent(complexType, &mixed); + hasTypeSpecified = true; + + effectiveMixed = (effectiveMixed || mixed); + hasComplexContent = true; + } else if (isSchemaTag(XsdSchemaToken::OpenContent, token, namespaceToken)) { + const XsdComplexType::OpenContent::Ptr openContent = parseOpenContent(); + complexType->contentType()->setOpenContent(openContent); + hasComplexContent = true; + } else if (isSchemaTag(XsdSchemaToken::Group, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseReferredGroup(particle); + particle->setTerm(term); + complexType->contentType()->setParticle(particle); + + complexType->setWxsSuperType(BuiltinTypes::xsAnyType); + complexType->contentType()->setVariety(XsdComplexType::ContentType::ElementOnly); + complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); + hasComplexContent = true; + } else if (isSchemaTag(XsdSchemaToken::All, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseLocalAll(particle, complexType); + particle->setTerm(term); + complexType->contentType()->setParticle(particle); + + complexType->setWxsSuperType(BuiltinTypes::xsAnyType); + complexType->contentType()->setVariety(XsdComplexType::ContentType::ElementOnly); + complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); + hasComplexContent = true; + } else if (isSchemaTag(XsdSchemaToken::Choice, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseLocalChoice(particle, complexType); + particle->setTerm(term); + complexType->contentType()->setParticle(particle); + + complexType->setWxsSuperType(BuiltinTypes::xsAnyType); + complexType->contentType()->setVariety(XsdComplexType::ContentType::ElementOnly); + complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); + hasComplexContent = true; + } else if (isSchemaTag(XsdSchemaToken::Sequence, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseLocalSequence(particle, complexType); + particle->setTerm(term); + complexType->contentType()->setParticle(particle); + + complexType->setWxsSuperType(BuiltinTypes::xsAnyType); + complexType->contentType()->setVariety(XsdComplexType::ContentType::ElementOnly); + complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); + hasComplexContent = true; + } else if (isSchemaTag(XsdSchemaToken::Attribute, token, namespaceToken)) { + const XsdAttributeUse::Ptr attributeUse = parseLocalAttribute(complexType); + complexType->addAttributeUse(attributeUse); + + complexType->setWxsSuperType(BuiltinTypes::xsAnyType); + complexType->contentType()->setVariety(XsdComplexType::ContentType::ElementOnly); + complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); + hasComplexContent = true; + } else if (isSchemaTag(XsdSchemaToken::AttributeGroup, token, namespaceToken)) { + const XsdAttributeUse::Ptr attributeUse = parseReferredAttributeGroup(); + complexType->addAttributeUse(attributeUse); + + complexType->setWxsSuperType(BuiltinTypes::xsAnyType); + complexType->contentType()->setVariety(XsdComplexType::ContentType::ElementOnly); + complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); + hasComplexContent = true; + } else if (isSchemaTag(XsdSchemaToken::AnyAttribute, token, namespaceToken)) { + const XsdWildcard::Ptr wildcard = parseAnyAttribute(); + complexType->setAttributeWildcard(wildcard); + + complexType->setWxsSuperType(BuiltinTypes::xsAnyType); + complexType->contentType()->setVariety(XsdComplexType::ContentType::ElementOnly); + complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); + hasComplexContent = true; + } else if (isSchemaTag(XsdSchemaToken::Assert, token, namespaceToken)) { + const XsdAssertion::Ptr assertion = parseAssertion(XsdSchemaToken::Assert, XsdTagScope::Assert); + complexType->addAssertion(assertion); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + if (!hasTypeSpecified) { + complexType->setWxsSuperType(BuiltinTypes::xsAnyType); + complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); + hasComplexContent = true; + } + + if (hasComplexContent == true) { + resolveComplexContentType(complexType, effectiveMixed); + } + + return complexType; +} + +void XsdSchemaParser::resolveComplexContentType(const XsdComplexType::Ptr &complexType, bool effectiveMixed) +{ + // @see http://www.w3.org/TR/xmlschema11-1/#dcl.ctd.ctcc.common + + // 1 + // the effectiveMixed contains the effective mixed value + + // 2 + bool hasEmptyContent = false; + if (!complexType->contentType()->particle()) { + hasEmptyContent = true; // 2.1.1 + } else { + if (complexType->contentType()->particle()->term()->isModelGroup()) { + const XsdModelGroup::Ptr group = complexType->contentType()->particle()->term(); + if (group->compositor() == XsdModelGroup::SequenceCompositor || group->compositor() == XsdModelGroup::AllCompositor) { + if (group->particles().isEmpty()) + hasEmptyContent = true; // 2.1.2 + } else if (group->compositor() == XsdModelGroup::ChoiceCompositor) { + if ((complexType->contentType()->particle()->minimumOccurs() == 0) && group->particles().isEmpty()) + hasEmptyContent = true; // 2.1.3 + } + + if ((complexType->contentType()->particle()->maximumOccursUnbounded() == false) && (complexType->contentType()->particle()->maximumOccurs() == 0)) + hasEmptyContent = true; // 2.1.4 + } + } + + const XsdParticle::Ptr explicitContent = (hasEmptyContent ? XsdParticle::Ptr() : complexType->contentType()->particle()); + + // do all the other work (3, 4, 5 and 6) in the resolver, as they need access to the base type object + m_schemaResolver->addComplexContentType(complexType, explicitContent, effectiveMixed); +} + +void XsdSchemaParser::parseSimpleContent(const XsdComplexType::Ptr &complexType) +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::SimpleContent, this); + + validateElement(XsdTagScope::SimpleContent); + + complexType->contentType()->setVariety(XsdComplexType::ContentType::Simple); + + // parse attributes + validateIdAttribute("simpleContent"); + + TagValidationHandler tagValidator(XsdTagScope::SimpleContent, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + complexType->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::Restriction, token, namespaceToken)) { + parseSimpleContentRestriction(complexType); + } else if (isSchemaTag(XsdSchemaToken::Extension, token, namespaceToken)) { + parseSimpleContentExtension(complexType); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); +} + +void XsdSchemaParser::parseSimpleContentRestriction(const XsdComplexType::Ptr &complexType) +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Restriction, this); + + validateElement(XsdTagScope::SimpleContentRestriction); + + complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); + + // parse attributes + const QString baseType = readQNameAttribute(QString::fromLatin1("base"), "restriction"); + QXmlName typeName; + convertName(baseType, NamespaceSupport::ElementName, typeName); // translate qualified name into QXmlName + + validateIdAttribute("restriction"); + + XsdFacet::Hash facets; + QList<XsdFacet::Ptr> patternFacets; + QList<XsdFacet::Ptr> enumerationFacets; + QList<XsdFacet::Ptr> assertionFacets; + + TagValidationHandler tagValidator(XsdTagScope::SimpleContentRestriction, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + complexType->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::SimpleType, token, namespaceToken)) { + const XsdSimpleType::Ptr type = parseLocalSimpleType(); + type->setContext(complexType); //TODO: investigate what the schema spec really wants here?!? + complexType->contentType()->setSimpleType(type); + + // add it to list of anonymous types as well + addAnonymousType(type); + } else if (isSchemaTag(XsdSchemaToken::MinExclusive, token, namespaceToken)) { + const XsdFacet::Ptr facet = parseMinExclusiveFacet(); + addFacet(facet, facets, complexType); + } else if (isSchemaTag(XsdSchemaToken::MinInclusive, token, namespaceToken)) { + const XsdFacet::Ptr facet = parseMinInclusiveFacet(); + addFacet(facet, facets, complexType); + } else if (isSchemaTag(XsdSchemaToken::MaxExclusive, token, namespaceToken)) { + const XsdFacet::Ptr facet = parseMaxExclusiveFacet(); + addFacet(facet, facets, complexType); + } else if (isSchemaTag(XsdSchemaToken::MaxInclusive, token, namespaceToken)) { + const XsdFacet::Ptr facet = parseMaxInclusiveFacet(); + addFacet(facet, facets, complexType); + } else if (isSchemaTag(XsdSchemaToken::TotalDigits, token, namespaceToken)) { + const XsdFacet::Ptr facet = parseTotalDigitsFacet(); + addFacet(facet, facets, complexType); + } else if (isSchemaTag(XsdSchemaToken::FractionDigits, token, namespaceToken)) { + const XsdFacet::Ptr facet = parseFractionDigitsFacet(); + addFacet(facet, facets, complexType); + } else if (isSchemaTag(XsdSchemaToken::Length, token, namespaceToken)) { + const XsdFacet::Ptr facet = parseLengthFacet(); + addFacet(facet, facets, complexType); + } else if (isSchemaTag(XsdSchemaToken::MinLength, token, namespaceToken)) { + const XsdFacet::Ptr facet = parseMinLengthFacet(); + addFacet(facet, facets, complexType); + } else if (isSchemaTag(XsdSchemaToken::MaxLength, token, namespaceToken)) { + const XsdFacet::Ptr facet = parseMaxLengthFacet(); + addFacet(facet, facets, complexType); + } else if (isSchemaTag(XsdSchemaToken::Enumeration, token, namespaceToken)) { + const XsdFacet::Ptr facet = parseEnumerationFacet(); + enumerationFacets.append(facet); + } else if (isSchemaTag(XsdSchemaToken::WhiteSpace, token, namespaceToken)) { + const XsdFacet::Ptr facet = parseWhiteSpaceFacet(); + addFacet(facet, facets, complexType); + } else if (isSchemaTag(XsdSchemaToken::Pattern, token, namespaceToken)) { + const XsdFacet::Ptr facet = parsePatternFacet(); + patternFacets.append(facet); + } else if (isSchemaTag(XsdSchemaToken::Assertion, token, namespaceToken)) { + const XsdFacet::Ptr facet = parseAssertionFacet(); + assertionFacets.append(facet); + } else if (isSchemaTag(XsdSchemaToken::Attribute, token, namespaceToken)) { + const XsdAttributeUse::Ptr attributeUse = parseLocalAttribute(complexType); + complexType->addAttributeUse(attributeUse); + } else if (isSchemaTag(XsdSchemaToken::AttributeGroup, token, namespaceToken)) { + const XsdAttributeUse::Ptr attributeUse = parseReferredAttributeGroup(); + complexType->addAttributeUse(attributeUse); + } else if (isSchemaTag(XsdSchemaToken::AnyAttribute, token, namespaceToken)) { + const XsdWildcard::Ptr wildcard = parseAnyAttribute(); + complexType->setAttributeWildcard(wildcard); + } else if (isSchemaTag(XsdSchemaToken::Assert, token, namespaceToken)) { + const XsdAssertion::Ptr assertion = parseAssertion(XsdSchemaToken::Assert, XsdTagScope::Assert); + complexType->addAssertion(assertion); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + // merge all pattern facets into one multi value facet + if (!patternFacets.isEmpty()) { + const XsdFacet::Ptr patternFacet(new XsdFacet()); + patternFacet->setType(XsdFacet::Pattern); + + AtomicValue::List multiValue; + for (int i = 0; i < patternFacets.count(); ++i) + multiValue << patternFacets.at(i)->multiValue(); + + patternFacet->setMultiValue(multiValue); + addFacet(patternFacet, facets, complexType); + } + + // merge all enumeration facets into one multi value facet + if (!enumerationFacets.isEmpty()) { + const XsdFacet::Ptr enumerationFacet(new XsdFacet()); + enumerationFacet->setType(XsdFacet::Enumeration); + + AtomicValue::List multiValue; + for (int i = 0; i < enumerationFacets.count(); ++i) + multiValue << enumerationFacets.at(i)->multiValue(); + + enumerationFacet->setMultiValue(multiValue); + addFacet(enumerationFacet, facets, complexType); + } + + // merge all assertion facets into one facet + if (!assertionFacets.isEmpty()) { + const XsdFacet::Ptr assertionFacet(new XsdFacet()); + assertionFacet->setType(XsdFacet::Assertion); + + XsdAssertion::List assertions; + for (int i = 0; i < assertionFacets.count(); ++i) + assertions << assertionFacets.at(i)->assertions(); + + assertionFacet->setAssertions(assertions); + addFacet(assertionFacet, facets, complexType); + } + + m_schemaResolver->addComplexBaseType(complexType, typeName, currentSourceLocation(), facets); // add to resolver +} + +void XsdSchemaParser::parseSimpleContentExtension(const XsdComplexType::Ptr &complexType) +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Extension, this); + + validateElement(XsdTagScope::SimpleContentExtension); + + complexType->setDerivationMethod(XsdComplexType::DerivationExtension); + + // parse attributes + const QString baseType = readQNameAttribute(QString::fromLatin1("base"), "extension"); + QXmlName typeName; + convertName(baseType, NamespaceSupport::ElementName, typeName); // translate qualified name into QXmlName + m_schemaResolver->addComplexBaseType(complexType, typeName, currentSourceLocation()); // add to resolver + + validateIdAttribute("extension"); + + TagValidationHandler tagValidator(XsdTagScope::SimpleContentExtension, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + complexType->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::Attribute, token, namespaceToken)) { + const XsdAttributeUse::Ptr attributeUse = parseLocalAttribute(complexType); + complexType->addAttributeUse(attributeUse); + } else if (isSchemaTag(XsdSchemaToken::AttributeGroup, token, namespaceToken)) { + const XsdAttributeUse::Ptr attributeUse = parseReferredAttributeGroup(); + complexType->addAttributeUse(attributeUse); + } else if (isSchemaTag(XsdSchemaToken::AnyAttribute, token, namespaceToken)) { + const XsdWildcard::Ptr wildcard = parseAnyAttribute(); + complexType->setAttributeWildcard(wildcard); + } else if (isSchemaTag(XsdSchemaToken::Assert, token, namespaceToken)) { + const XsdAssertion::Ptr assertion = parseAssertion(XsdSchemaToken::Assert, XsdTagScope::Assert); + complexType->addAssertion(assertion); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); +} + +void XsdSchemaParser::parseComplexContent(const XsdComplexType::Ptr &complexType, bool *mixed) +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::ComplexContent, this); + + validateElement(XsdTagScope::ComplexContent); + + complexType->contentType()->setVariety(XsdComplexType::ContentType::ElementOnly); + + // parse attributes + if (hasAttribute(QString::fromLatin1("mixed"))) { + const QString mixedStr = readAttribute(QString::fromLatin1("mixed")); + + const Boolean::Ptr value = Boolean::fromLexical(mixedStr); + if (value->hasError()) { + attributeContentError("mixed", "complexType", mixedStr, BuiltinTypes::xsBoolean); + return; + } + + *mixed = value->as<Boolean>()->value(); + } else { + *mixed = false; + } + + validateIdAttribute("complexContent"); + + TagValidationHandler tagValidator(XsdTagScope::ComplexContent, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + complexType->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::Restriction, token, namespaceToken)) { + parseComplexContentRestriction(complexType); + } else if (isSchemaTag(XsdSchemaToken::Extension, token, namespaceToken)) { + parseComplexContentExtension(complexType); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); +} + +void XsdSchemaParser::parseComplexContentRestriction(const XsdComplexType::Ptr &complexType) +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Restriction, this); + + validateElement(XsdTagScope::ComplexContentRestriction); + + complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); + + // parse attributes + const QString baseType = readQNameAttribute(QString::fromLatin1("base"), "restriction"); + QXmlName typeName; + convertName(baseType, NamespaceSupport::ElementName, typeName); // translate qualified name into QXmlName + m_schemaResolver->addComplexBaseType(complexType, typeName, currentSourceLocation()); // add to resolver + + validateIdAttribute("restriction"); + + TagValidationHandler tagValidator(XsdTagScope::ComplexContentRestriction, this, m_namePool); + + bool hasContent = false; + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + complexType->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::OpenContent, token, namespaceToken)) { + const XsdComplexType::OpenContent::Ptr openContent = parseOpenContent(); + complexType->contentType()->setOpenContent(openContent); + hasContent = true; + } else if (isSchemaTag(XsdSchemaToken::Group, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseReferredGroup(particle); + particle->setTerm(term); + complexType->contentType()->setParticle(particle); + hasContent = true; + } else if (isSchemaTag(XsdSchemaToken::All, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseLocalAll(particle, complexType); + particle->setTerm(term); + complexType->contentType()->setParticle(particle); + hasContent = true; + } else if (isSchemaTag(XsdSchemaToken::Choice, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseLocalChoice(particle, complexType); + particle->setTerm(term); + complexType->contentType()->setParticle(particle); + hasContent = true; + } else if (isSchemaTag(XsdSchemaToken::Sequence, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseLocalSequence(particle, complexType); + particle->setTerm(term); + complexType->contentType()->setParticle(particle); + hasContent = true; + } else if (isSchemaTag(XsdSchemaToken::Attribute, token, namespaceToken)) { + const XsdAttributeUse::Ptr attributeUse = parseLocalAttribute(complexType); + complexType->addAttributeUse(attributeUse); + } else if (isSchemaTag(XsdSchemaToken::AttributeGroup, token, namespaceToken)) { + const XsdAttributeUse::Ptr attributeUse = parseReferredAttributeGroup(); + complexType->addAttributeUse(attributeUse); + } else if (isSchemaTag(XsdSchemaToken::AnyAttribute, token, namespaceToken)) { + const XsdWildcard::Ptr wildcard = parseAnyAttribute(); + complexType->setAttributeWildcard(wildcard); + } else if (isSchemaTag(XsdSchemaToken::Assert, token, namespaceToken)) { + const XsdAssertion::Ptr assertion = parseAssertion(XsdSchemaToken::Assert, XsdTagScope::Assert); + complexType->addAssertion(assertion); + } else { + parseUnknown(); + } + } + } + + if (!hasContent) + complexType->contentType()->setVariety(XsdComplexType::ContentType::Empty); + + tagValidator.finalize(); +} + +void XsdSchemaParser::parseComplexContentExtension(const XsdComplexType::Ptr &complexType) +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Extension, this); + + validateElement(XsdTagScope::ComplexContentExtension); + + complexType->setDerivationMethod(XsdComplexType::DerivationExtension); + + // parse attributes + const QString baseType = readQNameAttribute(QString::fromLatin1("base"), "extension"); + QXmlName typeName; + convertName(baseType, NamespaceSupport::ElementName, typeName); // translate qualified name into QXmlName + m_schemaResolver->addComplexBaseType(complexType, typeName, currentSourceLocation()); // add to resolver + + validateIdAttribute("extension"); + + TagValidationHandler tagValidator(XsdTagScope::ComplexContentExtension, this, m_namePool); + + bool hasContent = false; + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + complexType->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::OpenContent, token, namespaceToken)) { + const XsdComplexType::OpenContent::Ptr openContent = parseOpenContent(); + complexType->contentType()->setOpenContent(openContent); + hasContent = true; + } else if (isSchemaTag(XsdSchemaToken::Group, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseReferredGroup(particle); + particle->setTerm(term); + complexType->contentType()->setParticle(particle); + hasContent = true; + } else if (isSchemaTag(XsdSchemaToken::All, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseLocalAll(particle, complexType); + particle->setTerm(term); + complexType->contentType()->setParticle(particle); + hasContent = true; + } else if (isSchemaTag(XsdSchemaToken::Choice, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseLocalChoice(particle, complexType); + particle->setTerm(term); + complexType->contentType()->setParticle(particle); + hasContent = true; + } else if (isSchemaTag(XsdSchemaToken::Sequence, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseLocalSequence(particle, complexType); + particle->setTerm(term); + complexType->contentType()->setParticle(particle); + hasContent = true; + } else if (isSchemaTag(XsdSchemaToken::Attribute, token, namespaceToken)) { + const XsdAttributeUse::Ptr attributeUse = parseLocalAttribute(complexType); + complexType->addAttributeUse(attributeUse); + } else if (isSchemaTag(XsdSchemaToken::AttributeGroup, token, namespaceToken)) { + const XsdAttributeUse::Ptr attributeUse = parseReferredAttributeGroup(); + complexType->addAttributeUse(attributeUse); + } else if (isSchemaTag(XsdSchemaToken::AnyAttribute, token, namespaceToken)) { + const XsdWildcard::Ptr wildcard = parseAnyAttribute(); + complexType->setAttributeWildcard(wildcard); + } else if (isSchemaTag(XsdSchemaToken::Assert, token, namespaceToken)) { + const XsdAssertion::Ptr assertion = parseAssertion(XsdSchemaToken::Assert, XsdTagScope::Assert); + complexType->addAssertion(assertion); + } else { + parseUnknown(); + } + } + } + + if (!hasContent) + complexType->contentType()->setVariety(XsdComplexType::ContentType::Empty); + + tagValidator.finalize(); +} + + +XsdAssertion::Ptr XsdSchemaParser::parseAssertion(const XsdSchemaToken::NodeName &nodeName, const XsdTagScope::Type &tag) +{ + const ElementNamespaceHandler namespaceHandler(nodeName, this); + + validateElement(tag); + + const XsdAssertion::Ptr assertion(new XsdAssertion()); + + // parse attributes + + const XsdXPathExpression::Ptr expression = readXPathExpression("assertion"); + assertion->setTest(expression); + + const QString test = readXPathAttribute(QString::fromLatin1("test"), XPath20, "assertion"); + expression->setExpression(test); + + validateIdAttribute("assertion"); + + TagValidationHandler tagValidator(tag, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + assertion->addAnnotation(annotation); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + return assertion; +} + +XsdComplexType::OpenContent::Ptr XsdSchemaParser::parseOpenContent() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::OpenContent, this); + + validateElement(XsdTagScope::OpenContent); + + const XsdComplexType::OpenContent::Ptr openContent(new XsdComplexType::OpenContent()); + + if (hasAttribute(QString::fromLatin1("mode"))) { + const QString mode = readAttribute(QString::fromLatin1("mode")); + + if (mode == QString::fromLatin1("none")) { + m_defaultOpenContent->setMode(XsdComplexType::OpenContent::None); + } else if (mode == QString::fromLatin1("interleave")) { + m_defaultOpenContent->setMode(XsdComplexType::OpenContent::Interleave); + } else if (mode == QString::fromLatin1("suffix")) { + m_defaultOpenContent->setMode(XsdComplexType::OpenContent::Suffix); + } else { + attributeContentError("mode", "openContent", mode); + return openContent; + } + } else { + openContent->setMode(XsdComplexType::OpenContent::Interleave); + } + + validateIdAttribute("openContent"); + + TagValidationHandler tagValidator(XsdTagScope::OpenContent, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + openContent->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::Any, token, namespaceToken)) { + const XsdParticle::Ptr particle; + const XsdWildcard::Ptr wildcard = parseAny(particle); + openContent->setWildcard(wildcard); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + return openContent; +} + +XsdModelGroup::Ptr XsdSchemaParser::parseNamedGroup() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Group, this); + + validateElement(XsdTagScope::NamedGroup); + + const XsdModelGroup::Ptr modelGroup(new XsdModelGroup()); + XsdModelGroup::Ptr group; + + QXmlName objectName; + if (hasAttribute(QString::fromLatin1("name"))) { + objectName = m_namePool->allocateQName(m_targetNamespace, readNameAttribute("group")); + } + + validateIdAttribute("group"); + + TagValidationHandler tagValidator(XsdTagScope::NamedGroup, this, m_namePool); + + XsdAnnotation::Ptr annotation; + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + annotation = parseAnnotation(); + } else if (isSchemaTag(XsdSchemaToken::All, token, namespaceToken)) { + group = parseAll(modelGroup); + } else if (isSchemaTag(XsdSchemaToken::Choice, token, namespaceToken)) { + group = parseChoice(modelGroup); + } else if (isSchemaTag(XsdSchemaToken::Sequence, token, namespaceToken)) { + group = parseSequence(modelGroup); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + group->setName(objectName); + + if (annotation) + group->addAnnotation(annotation); + + return group; +} + +XsdTerm::Ptr XsdSchemaParser::parseReferredGroup(const XsdParticle::Ptr &particle) +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Group, this); + + validateElement(XsdTagScope::ReferredGroup); + + const XsdReference::Ptr reference(new XsdReference()); + reference->setType(XsdReference::ModelGroup); + reference->setSourceLocation(currentSourceLocation()); + + // parse attributes + if (!parseMinMaxConstraint(particle, "group")) { + return reference; + } + + const QString value = readQNameAttribute(QString::fromLatin1("ref"), "group"); + QXmlName referenceName; + convertName(value, NamespaceSupport::ElementName, referenceName); // translate qualified name into QXmlName + reference->setReferenceName(referenceName); + + validateIdAttribute("group"); + + TagValidationHandler tagValidator(XsdTagScope::ReferredGroup, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + reference->addAnnotation(annotation); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + return reference; +} + +XsdModelGroup::Ptr XsdSchemaParser::parseAll(const NamedSchemaComponent::Ptr &parent) +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::All, this); + + validateElement(XsdTagScope::All); + + const XsdModelGroup::Ptr modelGroup(new XsdModelGroup()); + modelGroup->setCompositor(XsdModelGroup::AllCompositor); + + validateIdAttribute("all"); + + TagValidationHandler tagValidator(XsdTagScope::All, this, m_namePool); + + XsdParticle::List particles; + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + modelGroup->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::Element, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseLocalElement(particle, parent); + particle->setTerm(term); + + if (particle->maximumOccursUnbounded() || particle->maximumOccurs() > 1) { + error(QtXmlPatterns::tr("%1 attribute of %2 element must be %3 or %4") + .arg(formatAttribute("maxOccurs")) + .arg(formatElement("all")) + .arg(formatData("0")) + .arg(formatData("1"))); + return modelGroup; + } + + particles.append(particle); + } else { + parseUnknown(); + } + } + } + + modelGroup->setParticles(particles); + + tagValidator.finalize(); + + return modelGroup; +} + +XsdModelGroup::Ptr XsdSchemaParser::parseLocalAll(const XsdParticle::Ptr &particle, const NamedSchemaComponent::Ptr &parent) +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::All, this); + + validateElement(XsdTagScope::LocalAll); + + const XsdModelGroup::Ptr modelGroup(new XsdModelGroup()); + modelGroup->setCompositor(XsdModelGroup::AllCompositor); + + // parse attributes + if (!parseMinMaxConstraint(particle, "all")) { + return modelGroup; + } + if (particle->maximumOccursUnbounded() || particle->maximumOccurs() != 1) { + error(QtXmlPatterns::tr("%1 attribute of %2 element must have a value of %3") + .arg(formatAttribute("maxOccurs")) + .arg(formatElement("all")) + .arg(formatData("1"))); + return modelGroup; + } + if (particle->minimumOccurs() != 0 && particle->minimumOccurs() != 1) { + error(QtXmlPatterns::tr("%1 attribute of %2 element must have a value of %3 or %4") + .arg(formatAttribute("minOccurs")) + .arg(formatElement("all")) + .arg(formatData("0")) + .arg(formatData("1"))); + return modelGroup; + } + + validateIdAttribute("all"); + + TagValidationHandler tagValidator(XsdTagScope::LocalAll, this, m_namePool); + + XsdParticle::List particles; + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + modelGroup->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::Element, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseLocalElement(particle, parent); + particle->setTerm(term); + + if (particle->maximumOccursUnbounded() || particle->maximumOccurs() > 1) { + error(QtXmlPatterns::tr("%1 attribute of %2 element must have a value of %3 or %4") + .arg(formatAttribute("maxOccurs")) + .arg(formatElement("all")) + .arg(formatData("0")) + .arg(formatData("1"))); + return modelGroup; + } + + particles.append(particle); + } else { + parseUnknown(); + } + } + } + + modelGroup->setParticles(particles); + + tagValidator.finalize(); + + return modelGroup; +} + +XsdModelGroup::Ptr XsdSchemaParser::parseChoice(const NamedSchemaComponent::Ptr &parent) +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Choice, this); + + validateElement(XsdTagScope::Choice); + + const XsdModelGroup::Ptr modelGroup(new XsdModelGroup()); + modelGroup->setCompositor(XsdModelGroup::ChoiceCompositor); + + validateIdAttribute("choice"); + + XsdParticle::List particles; + + TagValidationHandler tagValidator(XsdTagScope::Choice, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + modelGroup->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::Element, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseLocalElement(particle, parent); + particle->setTerm(term); + particles.append(particle); + } else if (isSchemaTag(XsdSchemaToken::Group, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseReferredGroup(particle); + m_schemaResolver->addAllGroupCheck(term); + particle->setTerm(term); + particles.append(particle); + } else if (isSchemaTag(XsdSchemaToken::Choice, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseLocalChoice(particle, parent); + particle->setTerm(term); + particles.append(particle); + } else if (isSchemaTag(XsdSchemaToken::Sequence, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseLocalSequence(particle, parent); + particle->setTerm(term); + particles.append(particle); + } else if (isSchemaTag(XsdSchemaToken::Any, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseAny(particle); + particle->setTerm(term); + particles.append(particle); + } else { + parseUnknown(); + } + } + } + + modelGroup->setParticles(particles); + + tagValidator.finalize(); + + return modelGroup; +} + +XsdModelGroup::Ptr XsdSchemaParser::parseLocalChoice(const XsdParticle::Ptr &particle, const NamedSchemaComponent::Ptr &parent) +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Choice, this); + + validateElement(XsdTagScope::LocalChoice); + + const XsdModelGroup::Ptr modelGroup(new XsdModelGroup()); + modelGroup->setCompositor(XsdModelGroup::ChoiceCompositor); + + // parse attributes + if (!parseMinMaxConstraint(particle, "choice")) { + return modelGroup; + } + + validateIdAttribute("choice"); + + XsdParticle::List particles; + + TagValidationHandler tagValidator(XsdTagScope::LocalChoice, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + modelGroup->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::Element, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseLocalElement(particle, parent); + particle->setTerm(term); + particles.append(particle); + } else if (isSchemaTag(XsdSchemaToken::Group, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseReferredGroup(particle); + m_schemaResolver->addAllGroupCheck(term); + particle->setTerm(term); + particles.append(particle); + } else if (isSchemaTag(XsdSchemaToken::Choice, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseLocalChoice(particle, parent); + particle->setTerm(term); + particles.append(particle); + } else if (isSchemaTag(XsdSchemaToken::Sequence, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseLocalSequence(particle, parent); + particle->setTerm(term); + particles.append(particle); + } else if (isSchemaTag(XsdSchemaToken::Any, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseAny(particle); + particle->setTerm(term); + particles.append(particle); + } else { + parseUnknown(); + } + } + } + + modelGroup->setParticles(particles); + + tagValidator.finalize(); + + return modelGroup; +} + +XsdModelGroup::Ptr XsdSchemaParser::parseSequence(const NamedSchemaComponent::Ptr &parent) +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Sequence, this); + + validateElement(XsdTagScope::Sequence); + + const XsdModelGroup::Ptr modelGroup(new XsdModelGroup()); + modelGroup->setCompositor(XsdModelGroup::SequenceCompositor); + + validateIdAttribute("sequence"); + + XsdParticle::List particles; + + TagValidationHandler tagValidator(XsdTagScope::Sequence, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + modelGroup->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::Element, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseLocalElement(particle, parent); + particle->setTerm(term); + particles.append(particle); + } else if (isSchemaTag(XsdSchemaToken::Group, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseReferredGroup(particle); + m_schemaResolver->addAllGroupCheck(term); + particle->setTerm(term); + particles.append(particle); + } else if (isSchemaTag(XsdSchemaToken::Choice, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseLocalChoice(particle, parent); + particle->setTerm(term); + particles.append(particle); + } else if (isSchemaTag(XsdSchemaToken::Sequence, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseLocalSequence(particle, parent); + particle->setTerm(term); + particles.append(particle); + } else if (isSchemaTag(XsdSchemaToken::Any, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseAny(particle); + particle->setTerm(term); + particles.append(particle); + } else { + parseUnknown(); + } + } + } + + modelGroup->setParticles(particles); + + tagValidator.finalize(); + + return modelGroup; +} + +XsdModelGroup::Ptr XsdSchemaParser::parseLocalSequence(const XsdParticle::Ptr &particle, const NamedSchemaComponent::Ptr &parent) +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Sequence, this); + + validateElement(XsdTagScope::LocalSequence); + + const XsdModelGroup::Ptr modelGroup(new XsdModelGroup()); + modelGroup->setCompositor(XsdModelGroup::SequenceCompositor); + + // parse attributes + if (!parseMinMaxConstraint(particle, "sequence")) { + return modelGroup; + } + + validateIdAttribute("sequence"); + + XsdParticle::List particles; + + TagValidationHandler tagValidator(XsdTagScope::LocalSequence, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + modelGroup->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::Element, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseLocalElement(particle, parent); + particle->setTerm(term); + particles.append(particle); + } else if (isSchemaTag(XsdSchemaToken::Group, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseReferredGroup(particle); + m_schemaResolver->addAllGroupCheck(term); + particle->setTerm(term); + particles.append(particle); + } else if (isSchemaTag(XsdSchemaToken::Choice, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseLocalChoice(particle, parent); + particle->setTerm(term); + particles.append(particle); + } else if (isSchemaTag(XsdSchemaToken::Sequence, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseLocalSequence(particle, parent); + particle->setTerm(term); + particles.append(particle); + } else if (isSchemaTag(XsdSchemaToken::Any, token, namespaceToken)) { + const XsdParticle::Ptr particle(new XsdParticle()); + const XsdTerm::Ptr term = parseAny(particle); + particle->setTerm(term); + particles.append(particle); + } else { + parseUnknown(); + } + } + } + + modelGroup->setParticles(particles); + + tagValidator.finalize(); + + return modelGroup; +} + +XsdAttribute::Ptr XsdSchemaParser::parseGlobalAttribute() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Attribute, this); + + validateElement(XsdTagScope::GlobalAttribute); + + const XsdAttribute::Ptr attribute(new XsdAttribute()); + attribute->setScope(XsdAttribute::Scope::Ptr(new XsdAttribute::Scope())); + attribute->scope()->setVariety(XsdAttribute::Scope::Global); + + if (hasAttribute(QString::fromLatin1("default")) && hasAttribute(QString::fromLatin1("fixed"))) { + error(QtXmlPatterns::tr("%1 element must not have %2 and %3 attribute together") + .arg(formatElement("attribute")) + .arg(formatAttribute("default")) + .arg(formatAttribute("fixed"))); + return attribute; + } + + // parse attributes + if (hasAttribute(QString::fromLatin1("default"))) { + const QString value = readAttribute(QString::fromLatin1("default")); + attribute->setValueConstraint(XsdAttribute::ValueConstraint::Ptr(new XsdAttribute::ValueConstraint())); + attribute->valueConstraint()->setVariety(XsdAttribute::ValueConstraint::Default); + attribute->valueConstraint()->setValue(value); + } else if (hasAttribute(QString::fromLatin1("fixed"))) { + const QString value = readAttribute(QString::fromLatin1("fixed")); + attribute->setValueConstraint(XsdAttribute::ValueConstraint::Ptr(new XsdAttribute::ValueConstraint())); + attribute->valueConstraint()->setVariety(XsdAttribute::ValueConstraint::Fixed); + attribute->valueConstraint()->setValue(value); + } + + const QXmlName objectName = m_namePool->allocateQName(m_targetNamespace, readNameAttribute("attribute")); + if ((objectName.namespaceURI() == StandardNamespaces::xsi) && + (m_namePool->stringForLocalName(objectName.localName()) != QString::fromLatin1("type")) && + (m_namePool->stringForLocalName(objectName.localName()) != QString::fromLatin1("nil")) && + (m_namePool->stringForLocalName(objectName.localName()) != QString::fromLatin1("schemaLocation")) && + (m_namePool->stringForLocalName(objectName.localName()) != QString::fromLatin1("noNamespaceSchemaLocation"))) { + + error(QtXmlPatterns::tr("content of %1 attribute of %2 element must not be from namespace %3") + .arg(formatAttribute("name")) + .arg(formatElement("attribute")) + .arg(formatURI(CommonNamespaces::XSI))); + return attribute; + } + if (m_namePool->stringForLocalName(objectName.localName()) == QString::fromLatin1("xmlns")) { + error(QtXmlPatterns::tr("%1 attribute of %2 element must not be %3") + .arg(formatAttribute("name")) + .arg(formatElement("attribute")) + .arg(formatData("xmlns"))); + return attribute; + } + attribute->setName(objectName); + + bool hasTypeAttribute = false; + bool hasTypeSpecified = false; + + if (hasAttribute(QString::fromLatin1("type"))) { + hasTypeAttribute = true; + + const QString type = readQNameAttribute(QString::fromLatin1("type"), "attribute"); + QXmlName typeName; + convertName(type, NamespaceSupport::ElementName, typeName); // translate qualified name into QXmlName + m_schemaResolver->addAttributeType(attribute, typeName, currentSourceLocation()); // add to resolver + hasTypeSpecified = true; + } + + validateIdAttribute("attribute"); + + TagValidationHandler tagValidator(XsdTagScope::GlobalAttribute, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + attribute->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::SimpleType, token, namespaceToken)) { + if (hasTypeAttribute) { + error(QtXmlPatterns::tr("%1 element with %2 child element must not have a %3 attribute") + .arg(formatElement("attribute")) + .arg(formatElement("simpleType")) + .arg(formatAttribute("type"))); + break; + } + + const XsdSimpleType::Ptr type = parseLocalSimpleType(); + type->setContext(attribute); + attribute->setType(type); + hasTypeSpecified = true; + + // add it to list of anonymous types as well + addAnonymousType(type); + } else { + parseUnknown(); + } + } + } + + if (!hasTypeSpecified) { + attribute->setType(BuiltinTypes::xsAnySimpleType); // default value + return attribute; + } + + tagValidator.finalize(); + + return attribute; +} + +XsdAttributeUse::Ptr XsdSchemaParser::parseLocalAttribute(const NamedSchemaComponent::Ptr &parent) +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Attribute, this); + + validateElement(XsdTagScope::LocalAttribute); + + bool hasRefAttribute = false; + bool hasTypeAttribute = false; + bool hasTypeSpecified = false; + + XsdAttributeUse::Ptr attributeUse; + if (hasAttribute(QString::fromLatin1("ref"))) { + const XsdAttributeReference::Ptr reference = XsdAttributeReference::Ptr(new XsdAttributeReference()); + reference->setType(XsdAttributeReference::AttributeUse); + reference->setSourceLocation(currentSourceLocation()); + + attributeUse = reference; + hasRefAttribute = true; + } else { + attributeUse = XsdAttributeUse::Ptr(new XsdAttributeUse()); + } + + if (hasAttribute(QString::fromLatin1("default")) && hasAttribute(QString::fromLatin1("fixed"))) { + error(QtXmlPatterns::tr("%1 element must not have %2 and %3 attribute together") + .arg(formatElement("attribute")) + .arg(formatAttribute("default")) + .arg(formatAttribute("fixed"))); + return attributeUse; + } + + if (hasRefAttribute) { + if (hasAttribute(QString::fromLatin1("form"))) { + error(QtXmlPatterns::tr("%1 element must not have %2 and %3 attribute together") + .arg(formatElement("attribute")) + .arg(formatAttribute("ref")) + .arg(formatAttribute("form"))); + return attributeUse; + } + if (hasAttribute(QString::fromLatin1("name"))) { + error(QtXmlPatterns::tr("%1 element must not have %2 and %3 attribute together") + .arg(formatElement("attribute")) + .arg(formatAttribute("ref")) + .arg(formatAttribute("name"))); + return attributeUse; + } + if (hasAttribute(QString::fromLatin1("type"))) { + error(QtXmlPatterns::tr("%1 element must not have %2 and %3 attribute together") + .arg(formatElement("attribute")) + .arg(formatAttribute("ref")) + .arg(formatAttribute("type"))); + return attributeUse; + } + } + + // parse attributes + + // default, fixed and use are handled by both, attribute use and attribute reference + if (hasAttribute(QString::fromLatin1("default"))) { + const QString value = readAttribute(QString::fromLatin1("default")); + attributeUse->setValueConstraint(XsdAttributeUse::ValueConstraint::Ptr(new XsdAttributeUse::ValueConstraint())); + attributeUse->valueConstraint()->setVariety(XsdAttributeUse::ValueConstraint::Default); + attributeUse->valueConstraint()->setValue(value); + } else if (hasAttribute(QString::fromLatin1("fixed"))) { + const QString value = readAttribute(QString::fromLatin1("fixed")); + attributeUse->setValueConstraint(XsdAttributeUse::ValueConstraint::Ptr(new XsdAttributeUse::ValueConstraint())); + attributeUse->valueConstraint()->setVariety(XsdAttributeUse::ValueConstraint::Fixed); + attributeUse->valueConstraint()->setValue(value); + } + + if (hasAttribute(QString::fromLatin1("use"))) { + const QString value = readAttribute(QString::fromLatin1("use")); + if (value != QString::fromLatin1("optional") && + value != QString::fromLatin1("prohibited") && + value != QString::fromLatin1("required")) { + attributeContentError("use", "attribute", value); + return attributeUse; + } + + if (value == QString::fromLatin1("optional")) + attributeUse->setUseType(XsdAttributeUse::OptionalUse); + else if (value == QString::fromLatin1("prohibited")) + attributeUse->setUseType(XsdAttributeUse::ProhibitedUse); + else if (value == QString::fromLatin1("required")) + attributeUse->setUseType(XsdAttributeUse::RequiredUse); + + if (attributeUse->valueConstraint() && attributeUse->valueConstraint()->variety() == XsdAttributeUse::ValueConstraint::Default && value != QString::fromLatin1("optional")) { + error(QtXmlPatterns::tr("%1 attribute of %2 element must have the value %3 because the %4 attribute is set") + .arg(formatAttribute("use")) + .arg(formatElement("attribute")) + .arg(formatData("optional")) + .arg(formatElement("default"))); + return attributeUse; + } + } + + const XsdAttribute::Ptr attribute(new XsdAttribute()); + + attributeUse->setAttribute(attribute); + m_componentLocationHash.insert(attribute, currentSourceLocation()); + + attribute->setScope(XsdAttribute::Scope::Ptr(new XsdAttribute::Scope())); + attribute->scope()->setVariety(XsdAttribute::Scope::Local); + attribute->scope()->setParent(parent); + + // now make a difference between attribute reference and attribute use + if (hasRefAttribute) { + const QString reference = readQNameAttribute(QString::fromLatin1("ref"), "attribute"); + QXmlName referenceName; + convertName(reference, NamespaceSupport::ElementName, referenceName); // translate qualified name into QXmlName + + const XsdAttributeReference::Ptr attributeReference = attributeUse; + attributeReference->setReferenceName(referenceName); + } else { + if (hasAttribute(QString::fromLatin1("name"))) { + const QString attributeName = readNameAttribute("attribute"); + + QXmlName objectName; + if (hasAttribute(QString::fromLatin1("form"))) { + const QString value = readAttribute(QString::fromLatin1("form")); + if (value != QString::fromLatin1("qualified") && value != QString::fromLatin1("unqualified")) { + attributeContentError("form", "attribute", value); + return attributeUse; + } + + if (value == QString::fromLatin1("qualified")) { + objectName = m_namePool->allocateQName(m_targetNamespace, attributeName); + } else { + objectName = m_namePool->allocateQName(QString(), attributeName); + } + } else { + if (m_attributeFormDefault == QString::fromLatin1("qualified")) { + objectName = m_namePool->allocateQName(m_targetNamespace, attributeName); + } else { + objectName = m_namePool->allocateQName(QString(), attributeName); + } + } + + if ((objectName.namespaceURI() == StandardNamespaces::xsi) && + (m_namePool->stringForLocalName(objectName.localName()) != QString::fromLatin1("type")) && + (m_namePool->stringForLocalName(objectName.localName()) != QString::fromLatin1("nil")) && + (m_namePool->stringForLocalName(objectName.localName()) != QString::fromLatin1("schemaLocation")) && + (m_namePool->stringForLocalName(objectName.localName()) != QString::fromLatin1("noNamespaceSchemaLocation"))) { + + error(QtXmlPatterns::tr("content of %1 attribute of %2 element must not be from namespace %3") + .arg(formatAttribute("name")) + .arg(formatElement("attribute")) + .arg(formatURI(CommonNamespaces::XSI))); + return attributeUse; + } + if (m_namePool->stringForLocalName(objectName.localName()) == QString::fromLatin1("xmlns")) { + error(QtXmlPatterns::tr("%1 attribute of %2 element must not be %3") + .arg(formatAttribute("name")) + .arg(formatElement("attribute")) + .arg(formatData("xmlns"))); + return attributeUse; + } + + attribute->setName(objectName); + } + + if (hasAttribute(QString::fromLatin1("type"))) { + hasTypeAttribute = true; + + const QString type = readQNameAttribute(QString::fromLatin1("type"), "attribute"); + QXmlName typeName; + convertName(type, NamespaceSupport::ElementName, typeName); // translate qualified name into QXmlName + m_schemaResolver->addAttributeType(attribute, typeName, currentSourceLocation()); // add to resolver + hasTypeSpecified = true; + } + + if (attributeUse->valueConstraint()) { + //TODO: check whether assigning the value constraint of the attribute use to the attribute is correct + if (!attribute->valueConstraint()) + attribute->setValueConstraint(XsdAttribute::ValueConstraint::Ptr(new XsdAttribute::ValueConstraint())); + + attribute->valueConstraint()->setVariety((XsdAttribute::ValueConstraint::Variety)attributeUse->valueConstraint()->variety()); + attribute->valueConstraint()->setValue(attributeUse->valueConstraint()->value()); + attribute->valueConstraint()->setLexicalForm(attributeUse->valueConstraint()->lexicalForm()); + } + } + + validateIdAttribute("attribute"); + + TagValidationHandler tagValidator(XsdTagScope::LocalAttribute, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + attribute->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::SimpleType, token, namespaceToken)) { + if (hasTypeAttribute) { + error(QtXmlPatterns::tr("%1 element with %2 child element must not have a %3 attribute") + .arg(formatElement("attribute")) + .arg(formatElement("simpleType")) + .arg(formatAttribute("type"))); + break; + } + if (hasRefAttribute) { + error(QtXmlPatterns::tr("%1 element with %2 child element must not have a %3 attribute") + .arg(formatElement("attribute")) + .arg(formatElement("simpleType")) + .arg(formatAttribute("ref"))); + break; + } + + const XsdSimpleType::Ptr type = parseLocalSimpleType(); + type->setContext(attribute); + attribute->setType(type); + hasTypeSpecified = true; + + // add it to list of anonymous types as well + addAnonymousType(type); + } else { + parseUnknown(); + } + } + } + + if (!hasTypeSpecified) { + attribute->setType(BuiltinTypes::xsAnySimpleType); // default value + } + + tagValidator.finalize(); + + return attributeUse; +} + +XsdAttributeGroup::Ptr XsdSchemaParser::parseNamedAttributeGroup() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::AttributeGroup, this); + + validateElement(XsdTagScope::NamedAttributeGroup); + + const XsdAttributeGroup::Ptr attributeGroup(new XsdAttributeGroup()); + + // parse attributes + const QXmlName objectName = m_namePool->allocateQName(m_targetNamespace, readNameAttribute("attributeGroup")); + attributeGroup->setName(objectName); + + validateIdAttribute("attributeGroup"); + + TagValidationHandler tagValidator(XsdTagScope::NamedAttributeGroup, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + attributeGroup->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::Attribute, token, namespaceToken)) { + const XsdAttributeUse::Ptr attributeUse = parseLocalAttribute(attributeGroup); + + if (attributeUse->useType() == XsdAttributeUse::ProhibitedUse) { + warning(QtXmlPatterns::tr("specifying use='prohibited' inside an attribute group has no effect")); + } else { + attributeGroup->addAttributeUse(attributeUse); + } + } else if (isSchemaTag(XsdSchemaToken::AttributeGroup, token, namespaceToken)) { + const XsdAttributeUse::Ptr attributeUse = parseReferredAttributeGroup(); + attributeGroup->addAttributeUse(attributeUse); + } else if (isSchemaTag(XsdSchemaToken::AnyAttribute, token, namespaceToken)) { + const XsdWildcard::Ptr wildcard = parseAnyAttribute(); + attributeGroup->setWildcard(wildcard); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + return attributeGroup; +} + +XsdAttributeUse::Ptr XsdSchemaParser::parseReferredAttributeGroup() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::AttributeGroup, this); + + validateElement(XsdTagScope::ReferredAttributeGroup); + + const XsdAttributeReference::Ptr attributeReference(new XsdAttributeReference()); + attributeReference->setType(XsdAttributeReference::AttributeGroup); + attributeReference->setSourceLocation(currentSourceLocation()); + + // parse attributes + const QString reference = readQNameAttribute(QString::fromLatin1("ref"), "attributeGroup"); + QXmlName referenceName; + convertName(reference, NamespaceSupport::ElementName, referenceName); // translate qualified name into QXmlName + attributeReference->setReferenceName(referenceName); + + validateIdAttribute("attributeGroup"); + + TagValidationHandler tagValidator(XsdTagScope::ReferredAttributeGroup, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + attributeReference->addAnnotation(annotation); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + return attributeReference; +} + +XsdElement::Ptr XsdSchemaParser::parseGlobalElement() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Element, this); + + validateElement(XsdTagScope::GlobalElement); + + const XsdElement::Ptr element(new XsdElement()); + element->setScope(XsdElement::Scope::Ptr(new XsdElement::Scope())); + element->scope()->setVariety(XsdElement::Scope::Global); + + bool hasTypeAttribute = false; + bool hasTypeSpecified = false; + bool hasSubstitutionGroup = false; + + // parse attributes + const QXmlName objectName = m_namePool->allocateQName(m_targetNamespace, readNameAttribute("element")); + element->setName(objectName); + + if (hasAttribute(QString::fromLatin1("abstract"))) { + const QString abstract = readAttribute(QString::fromLatin1("abstract")); + + const Boolean::Ptr value = Boolean::fromLexical(abstract); + if (value->hasError()) { + attributeContentError("abstract", "element", abstract, BuiltinTypes::xsBoolean); + return element; + } + + element->setIsAbstract(value->as<Boolean>()->value()); + } else { + element->setIsAbstract(false); // the default value + } + + if (hasAttribute(QString::fromLatin1("default")) && hasAttribute(QString::fromLatin1("fixed"))) { + error(QtXmlPatterns::tr("%1 element must not have %2 and %3 attribute together") + .arg(formatElement("element")) + .arg(formatAttribute("default")) + .arg(formatAttribute("fixed"))); + return element; + } + + if (hasAttribute(QString::fromLatin1("default"))) { + const QString value = readAttribute(QString::fromLatin1("default")); + element->setValueConstraint(XsdElement::ValueConstraint::Ptr(new XsdElement::ValueConstraint())); + element->valueConstraint()->setVariety(XsdElement::ValueConstraint::Default); + element->valueConstraint()->setValue(value); + } else if (hasAttribute(QString::fromLatin1("fixed"))) { + const QString value = readAttribute(QString::fromLatin1("fixed")); + element->setValueConstraint(XsdElement::ValueConstraint::Ptr(new XsdElement::ValueConstraint())); + element->valueConstraint()->setVariety(XsdElement::ValueConstraint::Fixed); + element->valueConstraint()->setValue(value); + } + + element->setDisallowedSubstitutions(readBlockingConstraintAttribute(NamedSchemaComponent::ExtensionConstraint | NamedSchemaComponent::RestrictionConstraint | NamedSchemaComponent::SubstitutionConstraint, "element")); + element->setSubstitutionGroupExclusions(readDerivationConstraintAttribute(SchemaType::ExtensionConstraint | SchemaType::RestrictionConstraint, "element")); + + if (hasAttribute(QString::fromLatin1("nillable"))) { + const QString nillable = readAttribute(QString::fromLatin1("nillable")); + + const Boolean::Ptr value = Boolean::fromLexical(nillable); + if (value->hasError()) { + attributeContentError("nillable", "element", nillable, BuiltinTypes::xsBoolean); + return element; + } + + element->setIsNillable(value->as<Boolean>()->value()); + } else { + element->setIsNillable(false); // the default value + } + + if (hasAttribute(QString::fromLatin1("type"))) { + const QString type = readQNameAttribute(QString::fromLatin1("type"), "element"); + QXmlName typeName; + convertName(type, NamespaceSupport::ElementName, typeName); // translate qualified name into QXmlName + m_schemaResolver->addElementType(element, typeName, currentSourceLocation()); // add to resolver + + hasTypeAttribute = true; + hasTypeSpecified = true; + } + + if (hasAttribute(QString::fromLatin1("substitutionGroup"))) { + QList<QXmlName> elementNames; + + const QString value = readAttribute(QString::fromLatin1("substitutionGroup")); + const QStringList substitutionGroups = value.split(QLatin1Char(' '), QString::SkipEmptyParts); + if (substitutionGroups.isEmpty()) { + attributeContentError("substitutionGroup", "element", value, BuiltinTypes::xsQName); + return element; + } + + for (int i = 0; i < substitutionGroups.count(); ++i) { + const QString value = substitutionGroups.at(i).simplified(); + if (!XPathHelper::isQName(value)) { + attributeContentError("substitutionGroup", "element", value, BuiltinTypes::xsQName); + return element; + } + + QXmlName elementName; + convertName(value, NamespaceSupport::ElementName, elementName); // translate qualified name into QXmlName + elementNames.append(elementName); + } + + m_schemaResolver->addSubstitutionGroupAffiliation(element, elementNames, currentSourceLocation()); // add to resolver + + hasSubstitutionGroup = true; + } + + validateIdAttribute("element"); + + XsdAlternative::List alternatives; + + TagValidationHandler tagValidator(XsdTagScope::GlobalElement, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + element->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::SimpleType, token, namespaceToken)) { + if (hasTypeAttribute) { + error(QtXmlPatterns::tr("%1 element with %2 child element must not have a %3 attribute") + .arg(formatElement("element")) + .arg(formatElement("simpleType")) + .arg(formatAttribute("type"))); + return element; + } + + const XsdSimpleType::Ptr type = parseLocalSimpleType(); + type->setContext(element); + element->setType(type); + + // add it to list of anonymous types as well + addAnonymousType(type); + + hasTypeSpecified = true; + } else if (isSchemaTag(XsdSchemaToken::ComplexType, token, namespaceToken)) { + if (hasTypeAttribute) { + error(QtXmlPatterns::tr("%1 element with %2 child element must not have a %3 attribute") + .arg(formatElement("element")) + .arg(formatElement("complexType")) + .arg(formatAttribute("type"))); + return element; + } + + const XsdComplexType::Ptr type = parseLocalComplexType(); + type->setContext(element); + element->setType(type); + + // add it to list of anonymous types as well + addAnonymousType(type); + + hasTypeSpecified = true; + } else if (isSchemaTag(XsdSchemaToken::Alternative, token, namespaceToken)) { + const XsdAlternative::Ptr alternative = parseAlternative(); + alternatives.append(alternative); + } else if (isSchemaTag(XsdSchemaToken::Unique, token, namespaceToken)) { + const XsdIdentityConstraint::Ptr constraint = parseUnique(); + element->addIdentityConstraint(constraint); + } else if (isSchemaTag(XsdSchemaToken::Key, token, namespaceToken)) { + const XsdIdentityConstraint::Ptr constraint = parseKey(); + element->addIdentityConstraint(constraint); + } else if (isSchemaTag(XsdSchemaToken::Keyref, token, namespaceToken)) { + const XsdIdentityConstraint::Ptr constraint = parseKeyRef(element); + element->addIdentityConstraint(constraint); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + if (!hasTypeSpecified) { + if (hasSubstitutionGroup) + m_schemaResolver->addSubstitutionGroupType(element); + else + element->setType(BuiltinTypes::xsAnyType); + } + + if (!alternatives.isEmpty()) { + element->setTypeTable(XsdElement::TypeTable::Ptr(new XsdElement::TypeTable())); + + for (int i = 0; i < alternatives.count(); ++i) { + if (alternatives.at(i)->test()) + element->typeTable()->addAlternative(alternatives.at(i)); + + if (i == (alternatives.count() - 1)) { // the final one + if (!alternatives.at(i)->test()) { + element->typeTable()->setDefaultTypeDefinition(alternatives.at(i)); + } else { + const XsdAlternative::Ptr alternative(new XsdAlternative()); + if (element->type()) + alternative->setType(element->type()); + else + m_schemaResolver->addAlternativeType(alternative, element); // add to resolver + + element->typeTable()->setDefaultTypeDefinition(alternative); + } + } + } + } + + return element; +} + +XsdTerm::Ptr XsdSchemaParser::parseLocalElement(const XsdParticle::Ptr &particle, const NamedSchemaComponent::Ptr &parent) +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Element, this); + + validateElement(XsdTagScope::LocalElement); + + bool hasRefAttribute = false; + bool hasTypeAttribute = false; + bool hasTypeSpecified = false; + + XsdTerm::Ptr term; + XsdElement::Ptr element; + if (hasAttribute(QString::fromLatin1("ref"))) { + term = XsdReference::Ptr(new XsdReference()); + hasRefAttribute = true; + } else { + term = XsdElement::Ptr(new XsdElement()); + element = term; + } + + if (hasRefAttribute) { + if (hasAttribute(QString::fromLatin1("name"))) { + error(QtXmlPatterns::tr("%1 element must not have %2 and %3 attribute together") + .arg(formatElement("element")) + .arg(formatAttribute("ref")) + .arg(formatAttribute("name"))); + return term; + } else if (hasAttribute(QString::fromLatin1("block"))) { + error(QtXmlPatterns::tr("%1 element must not have %2 and %3 attribute together") + .arg(formatElement("element")) + .arg(formatAttribute("ref")) + .arg(formatAttribute("block"))); + return term; + } else if (hasAttribute(QString::fromLatin1("nillable"))) { + error(QtXmlPatterns::tr("%1 element must not have %2 and %3 attribute together") + .arg(formatElement("element")) + .arg(formatAttribute("ref")) + .arg(formatAttribute("nillable"))); + return term; + } else if (hasAttribute(QString::fromLatin1("default"))) { + error(QtXmlPatterns::tr("%1 element must not have %2 and %3 attribute together") + .arg(formatElement("element")) + .arg(formatAttribute("ref")) + .arg(formatAttribute("default"))); + return term; + } else if (hasAttribute(QString::fromLatin1("fixed"))) { + error(QtXmlPatterns::tr("%1 element must not have %2 and %3 attribute together") + .arg(formatElement("element")) + .arg(formatAttribute("ref")) + .arg(formatAttribute("fixed"))); + return term; + } else if (hasAttribute(QString::fromLatin1("form"))) { + error(QtXmlPatterns::tr("%1 element must not have %2 and %3 attribute together") + .arg(formatElement("element")) + .arg(formatAttribute("ref")) + .arg(formatAttribute("form"))); + return term; + } else if (hasAttribute(QString::fromLatin1("type"))) { + error(QtXmlPatterns::tr("%1 element must not have %2 and %3 attribute together") + .arg(formatElement("element")) + .arg(formatAttribute("ref")) + .arg(formatAttribute("type"))); + return term; + } + } + + // parse attributes + if (!parseMinMaxConstraint(particle, "element")) { + return element; + } + + if (!hasAttribute(QString::fromLatin1("name")) && !hasAttribute(QString::fromLatin1("ref"))) { + error(QtXmlPatterns::tr("%1 element must have either %2 or %3 attribute") + .arg(formatElement("element")) + .arg(formatAttribute("name")) + .arg(formatAttribute("ref"))); + return element; + } + + if (hasRefAttribute) { + const QString ref = readQNameAttribute(QString::fromLatin1("ref"), "element"); + QXmlName referenceName; + convertName(ref, NamespaceSupport::ElementName, referenceName); // translate qualified name into QXmlName + + const XsdReference::Ptr reference = term; + reference->setReferenceName(referenceName); + reference->setType(XsdReference::Element); + reference->setSourceLocation(currentSourceLocation()); + } else { + element->setScope(XsdElement::Scope::Ptr(new XsdElement::Scope())); + element->scope()->setVariety(XsdElement::Scope::Local); + element->scope()->setParent(parent); + + if (hasAttribute(QString::fromLatin1("name"))) { + const QString elementName = readNameAttribute("element"); + + QXmlName objectName; + if (hasAttribute(QString::fromLatin1("form"))) { + const QString value = readAttribute(QString::fromLatin1("form")); + if (value != QString::fromLatin1("qualified") && value != QString::fromLatin1("unqualified")) { + attributeContentError("form", "element", value); + return element; + } + + if (value == QString::fromLatin1("qualified")) { + objectName = m_namePool->allocateQName(m_targetNamespace, elementName); + } else { + objectName = m_namePool->allocateQName(QString(), elementName); + } + } else { + if (m_elementFormDefault == QString::fromLatin1("qualified")) { + objectName = m_namePool->allocateQName(m_targetNamespace, elementName); + } else { + objectName = m_namePool->allocateQName(QString(), elementName); + } + } + + element->setName(objectName); + } + + if (hasAttribute(QString::fromLatin1("nillable"))) { + const QString nillable = readAttribute(QString::fromLatin1("nillable")); + + const Boolean::Ptr value = Boolean::fromLexical(nillable); + if (value->hasError()) { + attributeContentError("nillable", "element", nillable, BuiltinTypes::xsBoolean); + return term; + } + + element->setIsNillable(value->as<Boolean>()->value()); + } else { + element->setIsNillable(false); // the default value + } + + if (hasAttribute(QString::fromLatin1("default")) && hasAttribute(QString::fromLatin1("fixed"))) { + error(QtXmlPatterns::tr("%1 element must not have %2 and %3 attribute together") + .arg(formatElement("element")) + .arg(formatAttribute("default")) + .arg(formatAttribute("fixed"))); + return element; + } + + if (hasAttribute(QString::fromLatin1("default"))) { + const QString value = readAttribute(QString::fromLatin1("default")); + element->setValueConstraint(XsdElement::ValueConstraint::Ptr(new XsdElement::ValueConstraint())); + element->valueConstraint()->setVariety(XsdElement::ValueConstraint::Default); + element->valueConstraint()->setValue(value); + } else if (hasAttribute(QString::fromLatin1("fixed"))) { + const QString value = readAttribute(QString::fromLatin1("fixed")); + element->setValueConstraint(XsdElement::ValueConstraint::Ptr(new XsdElement::ValueConstraint())); + element->valueConstraint()->setVariety(XsdElement::ValueConstraint::Fixed); + element->valueConstraint()->setValue(value); + } + + if (hasAttribute(QString::fromLatin1("type"))) { + const QString type = readQNameAttribute(QString::fromLatin1("type"), "element"); + QXmlName typeName; + convertName(type, NamespaceSupport::ElementName, typeName); // translate qualified name into QXmlName + m_schemaResolver->addElementType(element, typeName, currentSourceLocation()); // add to resolver + + hasTypeAttribute = true; + hasTypeSpecified = true; + } + + element->setDisallowedSubstitutions(readBlockingConstraintAttribute(NamedSchemaComponent::ExtensionConstraint | NamedSchemaComponent::RestrictionConstraint | NamedSchemaComponent::SubstitutionConstraint, "element")); + } + + validateIdAttribute("element"); + + XsdAlternative::List alternatives; + + TagValidationHandler tagValidator(XsdTagScope::LocalElement, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + element->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::SimpleType, token, namespaceToken)) { + if (hasRefAttribute) { + error(QtXmlPatterns::tr("%1 element with %2 child element must not have a %3 attribute") + .arg(formatElement("element")) + .arg(formatElement("simpleType")) + .arg(formatAttribute("ref"))); + return term; + } else if (hasTypeAttribute) { + error(QtXmlPatterns::tr("%1 element with %2 child element must not have a %3 attribute") + .arg(formatElement("element")) + .arg(formatElement("simpleType")) + .arg(formatAttribute("type"))); + return term; + } + + const XsdSimpleType::Ptr type = parseLocalSimpleType(); + type->setContext(element); + element->setType(type); + + // add it to list of anonymous types as well + addAnonymousType(type); + + hasTypeSpecified = true; + } else if (isSchemaTag(XsdSchemaToken::ComplexType, token, namespaceToken)) { + if (hasRefAttribute) { + error(QtXmlPatterns::tr("%1 element with %2 child element must not have a %3 attribute") + .arg(formatElement("element")) + .arg(formatElement("complexType")) + .arg(formatAttribute("ref"))); + return term; + } else if (hasTypeAttribute) { + error(QtXmlPatterns::tr("%1 element with %2 child element must not have a %3 attribute") + .arg(formatElement("element")) + .arg(formatElement("complexType")) + .arg(formatAttribute("type"))); + return term; + } + + const XsdComplexType::Ptr type = parseLocalComplexType(); + type->setContext(element); + element->setType(type); + + // add it to list of anonymous types as well + addAnonymousType(type); + + hasTypeSpecified = true; + } else if (isSchemaTag(XsdSchemaToken::Alternative, token, namespaceToken)) { + if (hasRefAttribute) { + error(QtXmlPatterns::tr("%1 element with %2 child element must not have a %3 attribute") + .arg(formatElement("element")) + .arg(formatElement("alternative")) + .arg(formatAttribute("ref"))); + return term; + } + + const XsdAlternative::Ptr alternative = parseAlternative(); + alternatives.append(alternative); + } else if (isSchemaTag(XsdSchemaToken::Unique, token, namespaceToken)) { + if (hasRefAttribute) { + error(QtXmlPatterns::tr("%1 element with %2 child element must not have a %3 attribute") + .arg(formatElement("element")) + .arg(formatElement("unique")) + .arg(formatAttribute("ref"))); + return term; + } + + const XsdIdentityConstraint::Ptr constraint = parseUnique(); + element->addIdentityConstraint(constraint); + } else if (isSchemaTag(XsdSchemaToken::Key, token, namespaceToken)) { + if (hasRefAttribute) { + error(QtXmlPatterns::tr("%1 element with %2 child element must not have a %3 attribute") + .arg(formatElement("element")) + .arg(formatElement("key")) + .arg(formatAttribute("ref"))); + return term; + } + + const XsdIdentityConstraint::Ptr constraint = parseKey(); + element->addIdentityConstraint(constraint); + } else if (isSchemaTag(XsdSchemaToken::Keyref, token, namespaceToken)) { + if (hasRefAttribute) { + error(QtXmlPatterns::tr("%1 element with %2 child element must not have a %3 attribute") + .arg(formatElement("element")) + .arg(formatElement("keyref")) + .arg(formatAttribute("ref"))); + return term; + } + + const XsdIdentityConstraint::Ptr constraint = parseKeyRef(element); + element->addIdentityConstraint(constraint); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + if (!hasTypeSpecified && !hasRefAttribute) + element->setType(BuiltinTypes::xsAnyType); + + if (!hasRefAttribute && !alternatives.isEmpty()) { + element->setTypeTable(XsdElement::TypeTable::Ptr(new XsdElement::TypeTable())); + + for (int i = 0; i < alternatives.count(); ++i) { + if (alternatives.at(i)->test()) + element->typeTable()->addAlternative(alternatives.at(i)); + + if (i == (alternatives.count() - 1)) { // the final one + if (!alternatives.at(i)->test()) { + element->typeTable()->setDefaultTypeDefinition(alternatives.at(i)); + } else { + const XsdAlternative::Ptr alternative(new XsdAlternative()); + if (element->type()) + alternative->setType(element->type()); + else + m_schemaResolver->addAlternativeType(alternative, element); // add to resolver + + element->typeTable()->setDefaultTypeDefinition(alternative); + } + } + } + } + + return term; +} + +XsdIdentityConstraint::Ptr XsdSchemaParser::parseUnique() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Unique, this); + + validateElement(XsdTagScope::Unique); + + const XsdIdentityConstraint::Ptr constraint(new XsdIdentityConstraint()); + constraint->setCategory(XsdIdentityConstraint::Unique); + + // parse attributes + const QXmlName objectName = m_namePool->allocateQName(m_targetNamespace, readNameAttribute("unique")); + constraint->setName(objectName); + + validateIdAttribute("unique"); + + TagValidationHandler tagValidator(XsdTagScope::Unique, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + constraint->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::Selector, token, namespaceToken)) { + parseSelector(constraint); + } else if (isSchemaTag(XsdSchemaToken::Field, token, namespaceToken)) { + parseField(constraint); + } else { + parseUnknown(); + } + } + } + + // add constraint to schema for further checking + addIdentityConstraint(constraint); + + tagValidator.finalize(); + + return constraint; +} + +XsdIdentityConstraint::Ptr XsdSchemaParser::parseKey() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Key, this); + + validateElement(XsdTagScope::Key); + + const XsdIdentityConstraint::Ptr constraint(new XsdIdentityConstraint()); + constraint->setCategory(XsdIdentityConstraint::Key); + + // parse attributes + const QXmlName objectName = m_namePool->allocateQName(m_targetNamespace, readNameAttribute("key")); + constraint->setName(objectName); + + validateIdAttribute("key"); + + TagValidationHandler tagValidator(XsdTagScope::Key, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + constraint->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::Selector, token, namespaceToken)) { + parseSelector(constraint); + } else if (isSchemaTag(XsdSchemaToken::Field, token, namespaceToken)) { + parseField(constraint); + } else { + parseUnknown(); + } + } + } + + // add constraint to schema for further checking + addIdentityConstraint(constraint); + + tagValidator.finalize(); + + return constraint; +} + +XsdIdentityConstraint::Ptr XsdSchemaParser::parseKeyRef(const XsdElement::Ptr &element) +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Keyref, this); + + validateElement(XsdTagScope::KeyRef); + + const XsdIdentityConstraint::Ptr constraint(new XsdIdentityConstraint()); + constraint->setCategory(XsdIdentityConstraint::KeyReference); + + // parse attributes + const QXmlName objectName = m_namePool->allocateQName(m_targetNamespace, readNameAttribute("keyref")); + constraint->setName(objectName); + + const QString refer = readQNameAttribute(QString::fromLatin1("refer"), "keyref"); + QXmlName referenceName; + convertName(refer, NamespaceSupport::ElementName, referenceName); // translate qualified name into QXmlName + m_schemaResolver->addKeyReference(element, constraint, referenceName, currentSourceLocation()); // add to resolver + + validateIdAttribute("keyref"); + + TagValidationHandler tagValidator(XsdTagScope::KeyRef, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + constraint->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::Selector, token, namespaceToken)) { + parseSelector(constraint); + } else if (isSchemaTag(XsdSchemaToken::Field, token, namespaceToken)) { + parseField(constraint); + } else { + parseUnknown(); + } + } + } + + // add constraint to schema for further checking + addIdentityConstraint(constraint); + + tagValidator.finalize(); + + return constraint; +} + +void XsdSchemaParser::parseSelector(const XsdIdentityConstraint::Ptr &ptr) +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Selector, this); + + validateElement(XsdTagScope::Selector); + + // parse attributes + const XsdXPathExpression::Ptr expression = readXPathExpression("selector"); + + const QString xpath = readXPathAttribute(QString::fromLatin1("xpath"), XPathSelector, "selector"); + expression->setExpression(xpath); + + ptr->setSelector(expression); + + validateIdAttribute("selector"); + + TagValidationHandler tagValidator(XsdTagScope::Selector, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + expression->addAnnotation(annotation); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); +} + +void XsdSchemaParser::parseField(const XsdIdentityConstraint::Ptr &ptr) +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Field, this); + + validateElement(XsdTagScope::Field); + + // parse attributes + const XsdXPathExpression::Ptr expression = readXPathExpression("field"); + + const QString xpath = readXPathAttribute(QString::fromLatin1("xpath"), XPathField, "field"); + expression->setExpression(xpath); + + ptr->addField(expression); + + validateIdAttribute("field"); + + TagValidationHandler tagValidator(XsdTagScope::Field, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + expression->addAnnotation(annotation); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); +} + +XsdAlternative::Ptr XsdSchemaParser::parseAlternative() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Alternative, this); + + validateElement(XsdTagScope::Alternative); + + const XsdAlternative::Ptr alternative(new XsdAlternative()); + + bool hasTypeSpecified = false; + + if (hasAttribute(QString::fromLatin1("test"))) { + const XsdXPathExpression::Ptr expression = readXPathExpression("alternative"); + + const QString test = readXPathAttribute(QString::fromLatin1("test"), XPath20, "alternative"); + expression->setExpression(test); + + alternative->setTest(expression); + } + + if (hasAttribute(QString::fromLatin1("type"))) { + const QString type = readQNameAttribute(QString::fromLatin1("type"), "alternative"); + QXmlName typeName; + convertName(type, NamespaceSupport::ElementName, typeName); // translate qualified name into QXmlName + m_schemaResolver->addAlternativeType(alternative, typeName, currentSourceLocation()); // add to resolver + + hasTypeSpecified = true; + } + + validateIdAttribute("alternative"); + + TagValidationHandler tagValidator(XsdTagScope::Alternative, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + alternative->addAnnotation(annotation); + } else if (isSchemaTag(XsdSchemaToken::SimpleType, token, namespaceToken)) { + const XsdSimpleType::Ptr type = parseLocalSimpleType(); + alternative->setType(type); + + // add it to list of anonymous types as well + addAnonymousType(type); + + hasTypeSpecified = true; + } else if (isSchemaTag(XsdSchemaToken::ComplexType, token, namespaceToken)) { + const XsdComplexType::Ptr type = parseLocalComplexType(); + alternative->setType(type); + + // add it to list of anonymous types as well + addAnonymousType(type); + + hasTypeSpecified = true; + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + if (!hasTypeSpecified) { + error(QtXmlPatterns::tr("%1 element must have either %2 attribute or %3 or %4 as child element") + .arg(formatElement("alternative")) + .arg(formatAttribute("type")) + .arg(formatElement("simpleType")) + .arg(formatElement("complexType"))); + return alternative; + } + + return alternative; +} + +XsdNotation::Ptr XsdSchemaParser::parseNotation() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Notation, this); + + validateElement(XsdTagScope::Notation); + + const XsdNotation::Ptr notation(new XsdNotation()); + + // parse attributes + const QXmlName objectName = m_namePool->allocateQName(m_targetNamespace, readNameAttribute("notation")); + notation->setName(objectName); + + bool hasOptionalAttribute = false; + + if (hasAttribute(QString::fromLatin1("public"))) { + const QString value = readAttribute(QString::fromLatin1("public")); + if (!value.isEmpty()) { + const DerivedString<TypeToken>::Ptr publicId = DerivedString<TypeToken>::fromLexical(m_namePool, value); + if (publicId->hasError()) { + attributeContentError("public", "notation", value, BuiltinTypes::xsToken); + return notation; + } + notation->setPublicId(publicId); + } + + hasOptionalAttribute = true; + } + + if (hasAttribute(QString::fromLatin1("system"))) { + const QString value = readAttribute(QString::fromLatin1("system")); + if (!isValidUri(value)) { + attributeContentError("system", "notation", value, BuiltinTypes::xsAnyURI); + return notation; + } + + if (!value.isEmpty()) { + const AnyURI::Ptr systemId = AnyURI::fromLexical(value); + notation->setSystemId(systemId); + } + + hasOptionalAttribute = true; + } + + if (!hasOptionalAttribute) { + error(QtXmlPatterns::tr("%1 element requires either %2 or %3 attribute") + .arg(formatElement("notation")) + .arg(formatAttribute("public")) + .arg(formatAttribute("system"))); + return notation; + } + + validateIdAttribute("notation"); + + TagValidationHandler tagValidator(XsdTagScope::Notation, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isCharacters() || isEntityReference()) { + if (!text().toString().trimmed().isEmpty()) { + error(QtXmlPatterns::tr("text or entity references not allowed inside %1 element").arg(formatElement("notation"))); + return notation; + } + } + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + notation->addAnnotation(annotation); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + return notation; +} + +XsdWildcard::Ptr XsdSchemaParser::parseAny(const XsdParticle::Ptr &particle) +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Any, this); + + validateElement(XsdTagScope::Any); + + const XsdWildcard::Ptr wildcard(new XsdWildcard()); + + // parse attributes + if (!parseMinMaxConstraint(particle, "any")) { + return wildcard; + } + + if (hasAttribute(QString::fromLatin1("namespace"))) { + const QSet<QString> values = readAttribute(QString::fromLatin1("namespace")).split(QLatin1Char(' '), QString::SkipEmptyParts).toSet(); + if ((values.contains(QString::fromLatin1("##any")) || values.contains(QString::fromLatin1("##other"))) && values.count() != 1) { + error(QtXmlPatterns::tr("%1 attribute of %2 element must contain %3, %4 or a list of URIs") + .arg(formatAttribute("namespace")) + .arg(formatElement("any")) + .arg(formatData("##any")) + .arg(formatData("##other"))); + return wildcard; + } + + if (values.contains(QString::fromLatin1("##any"))) { + wildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Any); + } else if (values.contains(QString::fromLatin1("##other"))) { + wildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Not); + if (!m_targetNamespace.isEmpty()) + wildcard->namespaceConstraint()->setNamespaces(QSet<QString>() << m_targetNamespace); + else + wildcard->namespaceConstraint()->setNamespaces(QSet<QString>() << XsdWildcard::absentNamespace()); + } else { + wildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Enumeration); + QStringList newValues = values.toList(); + + // replace the ##targetNamespace entry + for (int i = 0; i < newValues.count(); ++i) { + if (newValues.at(i) == QString::fromLatin1("##targetNamespace")) { + if (!m_targetNamespace.isEmpty()) + newValues[i] = m_targetNamespace; + else + newValues[i] = XsdWildcard::absentNamespace(); + } else if (newValues.at(i) == QString::fromLatin1("##local")) { + newValues[i] = XsdWildcard::absentNamespace(); + } + } + + // check for invalid URIs + for (int i = 0; i < newValues.count(); ++i) { + const QString stringValue = newValues.at(i); + if (stringValue == XsdWildcard::absentNamespace()) + continue; + + if (!isValidUri(stringValue)) { + attributeContentError("namespace", "any", stringValue, BuiltinTypes::xsAnyURI); + return wildcard; + } + } + + wildcard->namespaceConstraint()->setNamespaces(newValues.toSet()); + } + } else { + wildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Any); + } + + if (hasAttribute(QString::fromLatin1("processContents"))) { + const QString value = readAttribute(QString::fromLatin1("processContents")); + if (value != QString::fromLatin1("lax") && + value != QString::fromLatin1("skip") && + value != QString::fromLatin1("strict")) { + attributeContentError("processContents", "any", value); + return wildcard; + } + + if (value == QString::fromLatin1("lax")) { + wildcard->setProcessContents(XsdWildcard::Lax); + } else if (value == QString::fromLatin1("skip")) { + wildcard->setProcessContents(XsdWildcard::Skip); + } else if (value == QString::fromLatin1("strict")) { + wildcard->setProcessContents(XsdWildcard::Strict); + } + } else { + wildcard->setProcessContents(XsdWildcard::Strict); + } + + validateIdAttribute("any"); + + TagValidationHandler tagValidator(XsdTagScope::Any, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + wildcard->addAnnotation(annotation); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + return wildcard; +} + +XsdWildcard::Ptr XsdSchemaParser::parseAnyAttribute() +{ + const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::AnyAttribute, this); + + validateElement(XsdTagScope::AnyAttribute); + + const XsdWildcard::Ptr wildcard(new XsdWildcard()); + + // parse attributes + if (hasAttribute(QString::fromLatin1("namespace"))) { + const QSet<QString> values = readAttribute(QString::fromLatin1("namespace")).split(QLatin1Char(' '), QString::SkipEmptyParts).toSet(); + if ((values.contains(QString::fromLatin1("##any")) || values.contains(QString::fromLatin1("##other"))) && values.count() != 1) { + error(QtXmlPatterns::tr("%1 attribute of %2 element must contain %3, %4 or a list of URIs") + .arg(formatAttribute("namespace")) + .arg(formatElement("anyAttribute")) + .arg(formatData("##any")) + .arg(formatData("##other"))); + return wildcard; + } + + if (values.contains(QString::fromLatin1("##any"))) { + wildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Any); + } else if (values.contains(QString::fromLatin1("##other"))) { + wildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Not); + if (!m_targetNamespace.isEmpty()) + wildcard->namespaceConstraint()->setNamespaces(QSet<QString>() << m_targetNamespace); + else + wildcard->namespaceConstraint()->setNamespaces(QSet<QString>() << XsdWildcard::absentNamespace()); + } else { + wildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Enumeration); + QStringList newValues = values.toList(); + + // replace the ##targetNamespace entry + for (int i = 0; i < newValues.count(); ++i) { + if (newValues.at(i) == QString::fromLatin1("##targetNamespace")) { + if (!m_targetNamespace.isEmpty()) + newValues[i] = m_targetNamespace; + else + newValues[i] = XsdWildcard::absentNamespace(); + } else if (newValues.at(i) == QString::fromLatin1("##local")) { + newValues[i] = XsdWildcard::absentNamespace(); + } + } + + // check for invalid URIs + for (int i = 0; i < newValues.count(); ++i) { + const QString stringValue = newValues.at(i); + if (stringValue == XsdWildcard::absentNamespace()) + continue; + + if (!isValidUri(stringValue)) { + attributeContentError("namespace", "anyAttribute", stringValue, BuiltinTypes::xsAnyURI); + return wildcard; + } + } + + wildcard->namespaceConstraint()->setNamespaces(newValues.toSet()); + } + } else { + wildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Any); + } + + if (hasAttribute(QString::fromLatin1("processContents"))) { + const QString value = readAttribute(QString::fromLatin1("processContents")); + if (value != QString::fromLatin1("lax") && + value != QString::fromLatin1("skip") && + value != QString::fromLatin1("strict")) { + attributeContentError("processContents", "anyAttribute", value); + return wildcard; + } + + if (value == QString::fromLatin1("lax")) { + wildcard->setProcessContents(XsdWildcard::Lax); + } else if (value == QString::fromLatin1("skip")) { + wildcard->setProcessContents(XsdWildcard::Skip); + } else if (value == QString::fromLatin1("strict")) { + wildcard->setProcessContents(XsdWildcard::Strict); + } + } else { + wildcard->setProcessContents(XsdWildcard::Strict); + } + + validateIdAttribute("anyAttribute"); + + TagValidationHandler tagValidator(XsdTagScope::AnyAttribute, this, m_namePool); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); + const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); + + tagValidator.validate(token); + + if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { + const XsdAnnotation::Ptr annotation = parseAnnotation(); + wildcard->addAnnotation(annotation); + } else { + parseUnknown(); + } + } + } + + tagValidator.finalize(); + + return wildcard; +} + + +void XsdSchemaParser::parseUnknownDocumentation() +{ + Q_ASSERT(isStartElement()); + m_namespaceSupport.pushContext(); + m_namespaceSupport.setPrefixes(namespaceDeclarations()); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) + parseUnknownDocumentation(); + } + + m_namespaceSupport.popContext(); +} + +void XsdSchemaParser::parseUnknown() +{ + Q_ASSERT(isStartElement()); + m_namespaceSupport.pushContext(); + m_namespaceSupport.setPrefixes(namespaceDeclarations()); + + error(QtXmlPatterns::tr("%1 element is not allowed in this context").arg(formatElement(name().toString()))); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) + parseUnknown(); + } + + m_namespaceSupport.popContext(); +} + +bool XsdSchemaParser::parseMinMaxConstraint(const XsdParticle::Ptr &particle, const char *elementName) +{ + if (hasAttribute(QString::fromLatin1("minOccurs"))) { + const QString value = readAttribute(QString::fromLatin1("minOccurs")); + + DerivedInteger<TypeNonNegativeInteger>::Ptr integer = DerivedInteger<TypeNonNegativeInteger>::fromLexical(m_namePool, value); + if (integer->hasError()) { + attributeContentError("minOccurs", elementName, value, BuiltinTypes::xsNonNegativeInteger); + return false; + } else { + particle->setMinimumOccurs(integer->as< DerivedInteger<TypeNonNegativeInteger> >()->storedValue()); + } + } else { + particle->setMinimumOccurs(1); + } + + if (hasAttribute(QString::fromLatin1("maxOccurs"))) { + const QString value = readAttribute(QString::fromLatin1("maxOccurs")); + + if (value == QString::fromLatin1("unbounded")) { + particle->setMaximumOccursUnbounded(true); + } else { + particle->setMaximumOccursUnbounded(false); + DerivedInteger<TypeNonNegativeInteger>::Ptr integer = DerivedInteger<TypeNonNegativeInteger>::fromLexical(m_namePool, value); + if (integer->hasError()) { + attributeContentError("maxOccurs", elementName, value, BuiltinTypes::xsNonNegativeInteger); + return false; + } else { + particle->setMaximumOccurs(integer->as< DerivedInteger<TypeNonNegativeInteger> >()->storedValue()); + } + } + } else { + particle->setMaximumOccursUnbounded(false); + particle->setMaximumOccurs(1); + } + + if (!particle->maximumOccursUnbounded()) { + if (particle->maximumOccurs() < particle->minimumOccurs()) { + error(QtXmlPatterns::tr("%1 attribute of %2 element has larger value than %3 attribute") + .arg(formatAttribute("minOccurs")) + .arg(formatElement(elementName)) + .arg(formatAttribute("maxOccurs"))); + return false; + } + } + + return true; +} + +QSourceLocation XsdSchemaParser::currentSourceLocation() const +{ + QSourceLocation location; + location.setLine(lineNumber()); + location.setColumn(columnNumber()); + location.setUri(m_documentURI); + + return location; +} + +void XsdSchemaParser::convertName(const QString &qualifiedName, NamespaceSupport::NameType type, QXmlName &name) +{ + bool result = m_namespaceSupport.processName(qualifiedName, type, name); + if (!result) { + error(QtXmlPatterns::tr("prefix of qualified name %1 is not defined").arg(formatKeyword(qualifiedName))); + } +} + +QString XsdSchemaParser::readNameAttribute(const char *elementName) +{ + const QString value = readAttribute(QString::fromLatin1("name")).simplified(); + if (!QXmlUtils::isNCName(value)) { + attributeContentError("name", elementName, value, BuiltinTypes::xsNCName); + return QString(); + } else { + return value; + } +} + +QString XsdSchemaParser::readQNameAttribute(const QString &typeAttribute, const char *elementName) +{ + const QString value = readAttribute(typeAttribute).simplified(); + if (!XPathHelper::isQName(value)) { + attributeContentError(typeAttribute.toLatin1(), elementName, value, BuiltinTypes::xsQName); + return QString(); + } else { + return value; + } +} + +QString XsdSchemaParser::readNamespaceAttribute(const QString &attributeName, const char *elementName) +{ + const QString value = readAttribute(attributeName); + if (value.isEmpty()) { + attributeContentError(attributeName.toLatin1(), elementName, value, BuiltinTypes::xsAnyURI); + return QString(); + } + + return value; +} + +SchemaType::DerivationConstraints XsdSchemaParser::readDerivationConstraintAttribute(const SchemaType::DerivationConstraints &allowedConstraints, const char *elementName) +{ + // first convert the flags into strings for easier comparision + QSet<QString> allowedContent; + if (allowedConstraints & SchemaType::RestrictionConstraint) + allowedContent.insert(QString::fromLatin1("restriction")); + if (allowedConstraints & SchemaType::ExtensionConstraint) + allowedContent.insert(QString::fromLatin1("extension")); + if (allowedConstraints & SchemaType::ListConstraint) + allowedContent.insert(QString::fromLatin1("list")); + if (allowedConstraints & SchemaType::UnionConstraint) + allowedContent.insert(QString::fromLatin1("union")); + + // read content from the attribute if available, otherwise use the default definitions from the schema tag + QString content; + if (hasAttribute(QString::fromLatin1("final"))) { + content = readAttribute(QString::fromLatin1("final")); + + // split string into list to validate the content of the attribute + const QStringList values = content.split(QLatin1Char(' '), QString::SkipEmptyParts); + for (int i = 0; i < values.count(); i++) { + const QString value = values.at(i); + if (!allowedContent.contains(value) && (value != QString::fromLatin1("#all"))) { + attributeContentError("final", elementName, value); + return SchemaType::DerivationConstraints(); + } + + if ((value == QString::fromLatin1("#all")) && values.count() != 1) { + error(QtXmlPatterns::tr("%1 attribute of %2 element must either contain %3 or the other values") + .arg(formatAttribute("final")) + .arg(formatElement(elementName)) + .arg(formatData("#all"))); + return SchemaType::DerivationConstraints(); + } + } + } else { + // content of the default value has been validated in parseSchema already + content = m_finalDefault; + } + + QSet<QString> contentSet = content.split(QLatin1Char(' '), QString::SkipEmptyParts).toSet(); + + // if the '#all' tag is defined, we return all allowed values + if (contentSet.contains(QString::fromLatin1("#all"))) { + return allowedConstraints; + } else { // return the values from content set that intersects with the allowed values + contentSet.intersect(allowedContent); + + SchemaType::DerivationConstraints constraints; + + if (contentSet.contains(QString::fromLatin1("restriction"))) + constraints |= SchemaType::RestrictionConstraint; + if (contentSet.contains(QString::fromLatin1("extension"))) + constraints |= SchemaType::ExtensionConstraint; + if (contentSet.contains(QString::fromLatin1("list"))) + constraints |= SchemaType::ListConstraint; + if (contentSet.contains(QString::fromLatin1("union"))) + constraints |= SchemaType::UnionConstraint; + + return constraints; + } +} + +NamedSchemaComponent::BlockingConstraints XsdSchemaParser::readBlockingConstraintAttribute(const NamedSchemaComponent::BlockingConstraints &allowedConstraints, const char *elementName) +{ + // first convert the flags into strings for easier comparision + QSet<QString> allowedContent; + if (allowedConstraints & NamedSchemaComponent::RestrictionConstraint) + allowedContent.insert(QString::fromLatin1("restriction")); + if (allowedConstraints & NamedSchemaComponent::ExtensionConstraint) + allowedContent.insert(QString::fromLatin1("extension")); + if (allowedConstraints & NamedSchemaComponent::SubstitutionConstraint) + allowedContent.insert(QString::fromLatin1("substitution")); + + // read content from the attribute if available, otherwise use the default definitions from the schema tag + QString content; + if (hasAttribute(QString::fromLatin1("block"))) { + content = readAttribute(QString::fromLatin1("block")); + + // split string into list to validate the content of the attribute + const QStringList values = content.split(QLatin1Char(' '), QString::SkipEmptyParts); + for (int i = 0; i < values.count(); i++) { + const QString value = values.at(i); + if (!allowedContent.contains(value) && (value != QString::fromLatin1("#all"))) { + attributeContentError("block", elementName, value); + return NamedSchemaComponent::BlockingConstraints(); + } + + if ((value == QString::fromLatin1("#all")) && values.count() != 1) { + error(QtXmlPatterns::tr("%1 attribute of %2 element must either contain %3 or the other values") + .arg(formatAttribute("block")) + .arg(formatElement(elementName)) + .arg(formatData("#all"))); + return NamedSchemaComponent::BlockingConstraints(); + } + } + } else { + // content of the default value has been validated in parseSchema already + content = m_blockDefault; + } + + QSet<QString> contentSet = content.split(QLatin1Char(' '), QString::SkipEmptyParts).toSet(); + + // if the '#all' tag is defined, we return all allowed values + if (contentSet.contains(QString::fromLatin1("#all"))) { + return allowedConstraints; + } else { // return the values from content set that intersects with the allowed values + contentSet.intersect(allowedContent); + + NamedSchemaComponent::BlockingConstraints constraints; + + if (contentSet.contains(QString::fromLatin1("restriction"))) + constraints |= NamedSchemaComponent::RestrictionConstraint; + if (contentSet.contains(QString::fromLatin1("extension"))) + constraints |= NamedSchemaComponent::ExtensionConstraint; + if (contentSet.contains(QString::fromLatin1("substitution"))) + constraints |= NamedSchemaComponent::SubstitutionConstraint; + + return constraints; + } +} + +XsdXPathExpression::Ptr XsdSchemaParser::readXPathExpression(const char *elementName) +{ + const XsdXPathExpression::Ptr expression(new XsdXPathExpression()); + + const QList<QXmlName> namespaceBindings = m_namespaceSupport.namespaceBindings(); + QXmlName emptyName; + for (int i = 0; i < namespaceBindings.count(); ++i) { + if (namespaceBindings.at(i).prefix() == StandardPrefixes::empty) + emptyName = namespaceBindings.at(i); + } + + expression->setNamespaceBindings(namespaceBindings); + + QString xpathDefaultNamespace; + if (hasAttribute(QString::fromLatin1("xpathDefaultNamespace"))) { + xpathDefaultNamespace = readAttribute(QString::fromLatin1("xpathDefaultNamespace")); + if (xpathDefaultNamespace != QString::fromLatin1("##defaultNamespace") && + xpathDefaultNamespace != QString::fromLatin1("##targetNamespace") && + xpathDefaultNamespace != QString::fromLatin1("##local")) { + if (!isValidUri(xpathDefaultNamespace)) { + attributeContentError("xpathDefaultNamespace", elementName, xpathDefaultNamespace, BuiltinTypes::xsAnyURI); + return expression; + } + } + } else { + xpathDefaultNamespace = m_xpathDefaultNamespace; + } + + AnyURI::Ptr namespaceURI; + if (xpathDefaultNamespace == QString::fromLatin1("##defaultNamespace")) { + if (!emptyName.isNull()) + namespaceURI = AnyURI::fromLexical(m_namePool->stringForNamespace(emptyName.namespaceURI())); + } else if (xpathDefaultNamespace == QString::fromLatin1("##targetNamespace")) { + if (!m_targetNamespace.isEmpty()) + namespaceURI = AnyURI::fromLexical(m_targetNamespace); + } else if (xpathDefaultNamespace == QString::fromLatin1("##local")) { + // it is absent + } else { + namespaceURI = AnyURI::fromLexical(xpathDefaultNamespace); + } + if (namespaceURI) { + if (namespaceURI->hasError()) { + attributeContentError("xpathDefaultNamespace", elementName, xpathDefaultNamespace, BuiltinTypes::xsAnyURI); + return expression; + } + + expression->setDefaultNamespace(namespaceURI); + } + + //TODO: read the base uri if qmaintaining reader support it + + return expression; +} + +QString XsdSchemaParser::readXPathAttribute(const QString &attributeName, XPathType type, const char *elementName) +{ + const QString value = readAttribute(attributeName); + if (value.isEmpty() || value.startsWith(QLatin1Char('/'))) { + attributeContentError(attributeName.toLatin1(), elementName, value); + return QString(); + } + + QXmlNamePool namePool(m_namePool.data()); + + QXmlQuery::QueryLanguage language = QXmlQuery::XPath20; + switch (type) { + case XPath20: language = QXmlQuery::XPath20; break; + case XPathSelector: language = QXmlQuery::XmlSchema11IdentityConstraintSelector; break; + case XPathField: language = QXmlQuery::XmlSchema11IdentityConstraintField; break; + }; + + QXmlQuery query(language, namePool); + QXmlQueryPrivate *queryPrivate = query.d; + + const QList<QXmlName> namespaceBindings = m_namespaceSupport.namespaceBindings(); + for (int i = 0; i < namespaceBindings.count(); ++i) { + if (!namespaceBindings.at(i).prefix() == StandardPrefixes::empty) + queryPrivate->addAdditionalNamespaceBinding(namespaceBindings.at(i)); + } + + query.setQuery(value, m_documentURI); + if (!query.isValid()) { + attributeContentError(attributeName.toLatin1(), elementName, value); + return QString(); + } + + return value; +} + +void XsdSchemaParser::validateIdAttribute(const char *elementName) +{ + if (hasAttribute(QString::fromLatin1("id"))) { + const QString value = readAttribute(QString::fromLatin1("id")); + DerivedString<TypeID>::Ptr id = DerivedString<TypeID>::fromLexical(m_namePool, value); + if (id->hasError()) { + attributeContentError("id", elementName, value, BuiltinTypes::xsID); + } else { + if (m_idCache->hasId(value)) { + error(QtXmlPatterns::tr("component with id %1 has been defined previously").arg(formatData(value))); + } else { + m_idCache->addId(value); + } + } + } +} + +bool XsdSchemaParser::isSchemaTag(XsdSchemaToken::NodeName tag, XsdSchemaToken::NodeName token, XsdSchemaToken::NodeName namespaceToken) const +{ + return ((tag == token) && (namespaceToken == XsdSchemaToken::XML_NS_SCHEMA_URI)); +} + +void XsdSchemaParser::addElement(const XsdElement::Ptr &element) +{ + const QXmlName objectName = element->name(m_namePool); + if (m_schema->element(objectName)) { + error(QtXmlPatterns::tr("element %1 already defined").arg(formatElement(m_namePool->displayName(objectName)))); + } else { + m_schema->addElement(element); + m_componentLocationHash.insert(element, currentSourceLocation()); + } +} + +void XsdSchemaParser::addAttribute(const XsdAttribute::Ptr &attribute) +{ + const QXmlName objectName = attribute->name(m_namePool); + if (m_schema->attribute(objectName)) { + error(QtXmlPatterns::tr("attribute %1 already defined").arg(formatAttribute(m_namePool->displayName(objectName)))); + } else { + m_schema->addAttribute(attribute); + m_componentLocationHash.insert(attribute, currentSourceLocation()); + } +} + +void XsdSchemaParser::addType(const SchemaType::Ptr &type) +{ + // we don't import redefinitions of builtin types, that just causes problems + if (m_builtinTypeNames.contains(type->name(m_namePool))) + return; + + const QXmlName objectName = type->name(m_namePool); + if (m_schema->type(objectName)) { + error(QtXmlPatterns::tr("type %1 already defined").arg(formatType(m_namePool, objectName))); + } else { + m_schema->addType(type); + if (type->isSimpleType()) + m_componentLocationHash.insert(XsdSimpleType::Ptr(type), currentSourceLocation()); + else + m_componentLocationHash.insert(XsdComplexType::Ptr(type), currentSourceLocation()); + } +} + +void XsdSchemaParser::addAnonymousType(const SchemaType::Ptr &type) +{ + m_schema->addAnonymousType(type); + if (type->isSimpleType()) + m_componentLocationHash.insert(XsdSimpleType::Ptr(type), currentSourceLocation()); + else + m_componentLocationHash.insert(XsdComplexType::Ptr(type), currentSourceLocation()); +} + +void XsdSchemaParser::addAttributeGroup(const XsdAttributeGroup::Ptr &group) +{ + const QXmlName objectName = group->name(m_namePool); + if (m_schema->attributeGroup(objectName)) { + error(QtXmlPatterns::tr("attribute group %1 already defined").arg(formatKeyword(m_namePool, objectName))); + } else { + m_schema->addAttributeGroup(group); + m_componentLocationHash.insert(group, currentSourceLocation()); + } +} + +void XsdSchemaParser::addElementGroup(const XsdModelGroup::Ptr &group) +{ + const QXmlName objectName = group->name(m_namePool); + if (m_schema->elementGroup(objectName)) { + error(QtXmlPatterns::tr("element group %1 already defined").arg(formatKeyword(m_namePool, objectName))); + } else { + m_schema->addElementGroup(group); + m_componentLocationHash.insert(group, currentSourceLocation()); + } +} + +void XsdSchemaParser::addNotation(const XsdNotation::Ptr ¬ation) +{ + const QXmlName objectName = notation->name(m_namePool); + if (m_schema->notation(objectName)) { + error(QtXmlPatterns::tr("notation %1 already defined").arg(formatKeyword(m_namePool, objectName))); + } else { + m_schema->addNotation(notation); + m_componentLocationHash.insert(notation, currentSourceLocation()); + } +} + +void XsdSchemaParser::addIdentityConstraint(const XsdIdentityConstraint::Ptr &constraint) +{ + const QXmlName objectName = constraint->name(m_namePool); + if (m_schema->identityConstraint(objectName)) { + error(QtXmlPatterns::tr("identity constraint %1 already defined").arg(formatKeyword(m_namePool, objectName))); + } else { + m_schema->addIdentityConstraint(constraint); + m_componentLocationHash.insert(constraint, currentSourceLocation()); + } +} + +void XsdSchemaParser::addFacet(const XsdFacet::Ptr &facet, XsdFacet::Hash &facets, const SchemaType::Ptr &type) +{ + // @see http://www.w3.org/TR/xmlschema-2/#src-single-facet-value + if (facets.contains(facet->type())) { + error(QtXmlPatterns::tr("duplicated facets in simple type %1").arg(formatType(m_namePool, type))); + return; + } + + facets.insert(facet->type(), facet); +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdschemaparser_p.h b/src/xmlpatterns/schema/qxsdschemaparser_p.h new file mode 100644 index 0000000..51a8e3d --- /dev/null +++ b/src/xmlpatterns/schema/qxsdschemaparser_p.h @@ -0,0 +1,721 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdSchemaParser_H +#define Patternist_XsdSchemaParser_H + +#include "qnamespacesupport_p.h" +#include "qxsdalternative_p.h" +#include "qxsdattribute_p.h" +#include "qxsdattributegroup_p.h" +#include "qxsdattributeterm_p.h" +#include "qxsdcomplextype_p.h" +#include "qxsdelement_p.h" +#include "qxsdidcache_p.h" +#include "qxsdmodelgroup_p.h" +#include "qxsdnotation_p.h" +#include "qxsdsimpletype_p.h" +#include "qxsdschemacontext_p.h" +#include "qxsdschemaparsercontext_p.h" +#include "qxsdstatemachine_p.h" + +#include <QtCore/QHash> +#include <QtCore/QSet> +#include <QtCore/QUrl> +#include <QtXml/QXmlStreamReader> +#include <QtXmlPatterns/QXmlNamePool> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short Implements the parsing of XML schema file. + * + * This class parses a XML schema in XML presentation from an QIODevice + * and returns object representation as XsdSchema. + * + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdSchemaParser : public MaintainingReader<XsdSchemaToken, XsdTagScope::Type> + { + friend class ElementNamespaceHandler; + friend class TagValidationHandler; + + public: + enum ParserType + { + TopLevelParser, + IncludeParser, + ImportParser, + RedefineParser + }; + + /** + * Creates a new schema parser object. + */ + XsdSchemaParser(const XsdSchemaContext::Ptr &context, const XsdSchemaParserContext::Ptr &parserContext, QIODevice *device); + + /** + * Parses the XML schema file. + * + * @return @c true on success, @c false if the schema is somehow invalid. + */ + bool parse(ParserType parserType = TopLevelParser); + + /** + * Describes a set of namespace URIs + */ + typedef QSet<QUrl> NamespaceSet; + + /** + * Sets which @p schemas have been included already, so the parser + * can detect circular includes. + */ + void setIncludedSchemas(const NamespaceSet &schemas); + + /** + * Sets which @p schemas have been imported already, so the parser + * can detect circular imports. + */ + void setImportedSchemas(const NamespaceSet &schemas); + + /** + * Sets which @p schemas have been redefined already, so the parser + * can detect circular redefines. + */ + void setRedefinedSchemas(const NamespaceSet &schemas); + + /** + * Sets the target namespace of the schema to parse. + */ + void setTargetNamespace(const QString &targetNamespace); + + /** + * Sets the document URI of the schema to parse. + */ + void setDocumentURI(const QUrl &uri); + + /** + * Returns the document URI of the schema to parse. + */ + QUrl documentURI() const; + + /** + * Reimplemented from MaintainingReader, always returns @c false. + */ + bool isAnyAttributeAllowed() const; + + private: + /** + * Used internally to report any kind of parsing error or + * schema inconsistency. + */ + virtual void error(const QString &msg); + + void attributeContentError(const char *attributeName, const char *elementName, const QString &value, const SchemaType::Ptr &type = SchemaType::Ptr()); + + /** + * Sets the target namespace of the schema to parse. + */ + void setTargetNamespaceExtended(const QString &targetNamespace); + + /** + * This method is called for parsing the top-level <em>schema</em> object. + */ + void parseSchema(ParserType parserType); + + /** + * This method is called for parsing any top-level <em>include</em> object. + */ + void parseInclude(); + + /** + * This method is called for parsing any top-level <em>import</em> object. + */ + void parseImport(); + + /** + * This method is called for parsing any top-level <em>redefine</em> object. + */ + void parseRedefine(); + + /** + * This method is called for parsing any <em>annotation</em> object everywhere + * in the schema. + */ + XsdAnnotation::Ptr parseAnnotation(); + + /** + * This method is called for parsing an <em>appinfo</em> object as child of + * an <em>annotation</em> object. + */ + XsdApplicationInformation::Ptr parseAppInfo(); + + /** + * This method is called for parsing a <em>documentation</em> object as child of + * an <em>annotation</em> object. + */ + XsdDocumentation::Ptr parseDocumentation(); + + /** + * This method is called for parsing a <em>defaultOpenContent</em> object. + */ + void parseDefaultOpenContent(); + + /** + * This method is called for parsing any top-level <em>simpleType</em> object. + */ + XsdSimpleType::Ptr parseGlobalSimpleType(); + + /** + * This method is called for parsing any <em>simpleType</em> object as descendant + * of an <em>element</em> or <em>complexType</em> object. + */ + XsdSimpleType::Ptr parseLocalSimpleType(); + + /** + * This method is called for parsing a <em>restriction</em> object as child + * of a <em>simpleType</em> object. + */ + void parseSimpleRestriction(const XsdSimpleType::Ptr &ptr); + + /** + * This method is called for parsing a <em>list</em> object as child + * of a <em>simpleType</em> object. + */ + void parseList(const XsdSimpleType::Ptr &ptr); + + /** + * This method is called for parsing a <em>union</em> object as child + * of a <em>simpleType</em> object. + */ + void parseUnion(const XsdSimpleType::Ptr &ptr); + + /** + * This method is called for parsing a <em>minExclusive</em> object as child + * of a <em>restriction</em> object. + */ + XsdFacet::Ptr parseMinExclusiveFacet(); + + /** + * This method is called for parsing a <em>minInclusive</em> object as child + * of a <em>restriction</em> object. + */ + XsdFacet::Ptr parseMinInclusiveFacet(); + + /** + * This method is called for parsing a <em>maxExclusive</em> object as child + * of a <em>restriction</em> object. + */ + XsdFacet::Ptr parseMaxExclusiveFacet(); + + /** + * This method is called for parsing a <em>maxInclusive</em> object as child + * of a <em>restriction</em> object. + */ + XsdFacet::Ptr parseMaxInclusiveFacet(); + + /** + * This method is called for parsing a <em>totalDigits</em> object as child + * of a <em>restriction</em> object. + */ + XsdFacet::Ptr parseTotalDigitsFacet(); + + /** + * This method is called for parsing a <em>fractionDigits</em> object as child + * of a <em>restriction</em> object. + */ + XsdFacet::Ptr parseFractionDigitsFacet(); + + /** + * This method is called for parsing a <em>length</em> object as child + * of a <em>restriction</em> object. + */ + XsdFacet::Ptr parseLengthFacet(); + + /** + * This method is called for parsing a <em>minLength</em> object as child + * of a <em>restriction</em> object. + */ + XsdFacet::Ptr parseMinLengthFacet(); + + /** + * This method is called for parsing a <em>maxLength</em> object as child + * of a <em>restriction</em> object. + */ + XsdFacet::Ptr parseMaxLengthFacet(); + + /** + * This method is called for parsing an <em>enumeration</em> object as child + * of a <em>restriction</em> object. + */ + XsdFacet::Ptr parseEnumerationFacet(); + + /** + * This method is called for parsing a <em>whiteSpace</em> object as child + * of a <em>restriction</em> object. + */ + XsdFacet::Ptr parseWhiteSpaceFacet(); + + /** + * This method is called for parsing a <em>pattern</em> object as child + * of a <em>restriction</em> object. + */ + XsdFacet::Ptr parsePatternFacet(); + + /** + * This method is called for parsing an <em>assertion</em> object as child + * of a <em>restriction</em> object. + */ + XsdFacet::Ptr parseAssertionFacet(); + + /** + * This method is called for parsing any top-level <em>complexType</em> object. + */ + XsdComplexType::Ptr parseGlobalComplexType(); + + /** + * This method is called for parsing any <em>complexType</em> object as descendant + * of an <em>element</em> object. + */ + XsdComplexType::Ptr parseLocalComplexType(); + + /** + * This method resolves the content type of the @p complexType for the given + * @p effectiveMixed value. + */ + void resolveComplexContentType(const XsdComplexType::Ptr &complexType, bool effectiveMixed); + + /** + * This method is called for parsing a <em>simpleContent</em> object as child + * of a <em>complexType</em> object. + */ + void parseSimpleContent(const XsdComplexType::Ptr &complexType); + + /** + * This method is called for parsing a <em>restriction</em> object as child + * of a <em>simpleContent</em> object. + */ + void parseSimpleContentRestriction(const XsdComplexType::Ptr &complexType); + + /** + * This method is called for parsing an <em>extension</em> object as child + * of a <em>simpleContent</em> object. + */ + void parseSimpleContentExtension(const XsdComplexType::Ptr &complexType); + + /** + * This method is called for parsing a <em>complexContent</em> object as child + * of a <em>complexType</em> object. + * + * @param complexType The complex type the complex content belongs to. + * @param mixed The output parameter for the mixed value. + */ + void parseComplexContent(const XsdComplexType::Ptr &complexType, bool *mixed); + + /** + * This method is called for parsing a <em>restriction</em> object as child + * of a <em>complexContent</em> object. + */ + void parseComplexContentRestriction(const XsdComplexType::Ptr &complexType); + + /** + * This method is called for parsing an <em>extension</em> object as child + * of a <em>complexContent</em> object. + */ + void parseComplexContentExtension(const XsdComplexType::Ptr &complexType); + + /** + * This method is called for parsing an <em>assert</em> object as child + * of a <em>complexType</em> or parsing a <em>assertion</em> facet object as + * child of a <em>simpleType</em>. + * + * @param nodeName Either XsdSchemaToken::Assert or XsdSchemaToken::Assertion. + * @param tag Either XsdTagScope::Assert or XsdTagScope::Assertion. + */ + XsdAssertion::Ptr parseAssertion(const XsdSchemaToken::NodeName &nodeName, const XsdTagScope::Type &tag); + + /** + * This method is called for parsing an <em>openContent</em> object. + */ + XsdComplexType::OpenContent::Ptr parseOpenContent(); + + /** + * This method is called for parsing a top-level <em>group</em> object. + */ + XsdModelGroup::Ptr parseNamedGroup(); + + /** + * This method is called for parsing a non-top-level <em>group</em> object + * that contains a <em>ref</em> attribute. + */ + XsdTerm::Ptr parseReferredGroup(const XsdParticle::Ptr &particle); + + /** + * This method is called for parsing an <em>all</em> object as child + * of a top-level <em>group</em> object. + * + * @param parent The schema component the <em>all</em> object is part of. + */ + XsdModelGroup::Ptr parseAll(const NamedSchemaComponent::Ptr &parent); + + /** + * This method is called for parsing an <em>all</em> object as descendant + * of a <em>complexType</em> object. + * + * @param particle The particle the <em>all</em> object belongs to. + * @param parent The schema component the <em>all</em> object is part of. + */ + XsdModelGroup::Ptr parseLocalAll(const XsdParticle::Ptr &particle, const NamedSchemaComponent::Ptr &parent); + + /** + * This method is called for parsing a <em>choice</em> object as child + * of a top-level <em>group</em> object. + * + * @param parent The schema component the <em>choice</em> object is part of. + */ + XsdModelGroup::Ptr parseChoice(const NamedSchemaComponent::Ptr &parent); + + /** + * This method is called for parsing a <em>choice</em> object as descendant + * of a <em>complexType</em> object or a <em>choice</em> object. + * + * @param particle The particle the <em>choice</em> object belongs to. + * @param parent The schema component the <em>choice</em> object is part of. + */ + XsdModelGroup::Ptr parseLocalChoice(const XsdParticle::Ptr &particle, const NamedSchemaComponent::Ptr &parent); + + /** + * This method is called for parsing a <em>sequence</em> object as child + * of a top-level <em>group</em> object. + * + * @param parent The schema component the <em>sequence</em> object is part of. + */ + XsdModelGroup::Ptr parseSequence(const NamedSchemaComponent::Ptr &parent); + + /** + * This method is called for parsing a <em>sequence</em> object as descendant + * of a <em>complexType</em> object or a <em>sequence</em> object. + * + * @param particle The particle the <em>sequence</em> object belongs to. + * @param parent The schema component the <em>sequence</em> object is part of. + */ + XsdModelGroup::Ptr parseLocalSequence(const XsdParticle::Ptr &particle, const NamedSchemaComponent::Ptr &parent); + + /** + * A helper method that parses the minOccurs and maxOccurs constraints for + * the given @p particle that has the given @p tagName. + */ + bool parseMinMaxConstraint(const XsdParticle::Ptr &particle, const char* tagName); + + /** + * This method is called for parsing any top-level <em>attribute</em> object. + */ + XsdAttribute::Ptr parseGlobalAttribute(); + + /** + * This method is called for parsing any non-top-level <em>attribute</em> object as a + * descendant of a <em>complexType</em> object or an <em>attributeGroup</em> object. + * + * @param parent The parent component the <em>attribute</em> object is part of. + */ + XsdAttributeUse::Ptr parseLocalAttribute(const NamedSchemaComponent::Ptr &parent); + + /** + * This method is called for parsing a top-level <em>attributeGroup</em> object. + */ + XsdAttributeGroup::Ptr parseNamedAttributeGroup(); + + /** + * This method is called for parsing a non-top-level <em>attributeGroup</em> object + * that contains a <em>ref</em> attribute. + */ + XsdAttributeUse::Ptr parseReferredAttributeGroup(); + + /** + * This method is called for parsing any top-level <em>element</em> object. + */ + XsdElement::Ptr parseGlobalElement(); + + /** + * This method is called for parsing any non-top-level <em>element</em> object as a + * descendant of a <em>complexType</em> object or a <em>group</em> object. + * + * @param particle The particle the <em>element</em> object belongs to. + * @param parent The parent component the <em>element</em> object is part of. + */ + XsdTerm::Ptr parseLocalElement(const XsdParticle::Ptr &particle, const NamedSchemaComponent::Ptr &parent); + + /** + * This method is called for parsing a <em>unique</em> object as child of an <em>element</em> object. + */ + XsdIdentityConstraint::Ptr parseUnique(); + + /** + * This method is called for parsing a <em>key</em> object as child of an <em>element</em> object. + */ + XsdIdentityConstraint::Ptr parseKey(); + + /** + * This method is called for parsing a <em>keyref</em> object as child of an <em>element</em> object. + */ + XsdIdentityConstraint::Ptr parseKeyRef(const XsdElement::Ptr &element); + + /** + * This method is called for parsing a <em>selector</em> object as child of an <em>unique</em> object, + * <em>key</em> object or <em>keyref</em> object, + * + * @param ptr The identity constraint it belongs to. + */ + void parseSelector(const XsdIdentityConstraint::Ptr &ptr); + + /** + * This method is called for parsing a <em>field</em> object as child of an <em>unique</em> object, + * <em>key</em> object or <em>keyref</em> object, + * + * @param ptr The identity constraint it belongs to. + */ + void parseField(const XsdIdentityConstraint::Ptr &ptr); + + /** + * This method is called for parsing an <em>alternative</em> object inside an <em>element</em> object. + */ + XsdAlternative::Ptr parseAlternative(); + + /** + * This method is called for parsing a top-level <em>notation</em> object. + */ + XsdNotation::Ptr parseNotation(); + + /** + * This method is called for parsing an <em>any</em> object somewhere in + * the schema. + * + * @param particle The particle the <em>any</em> object belongs to. + */ + XsdWildcard::Ptr parseAny(const XsdParticle::Ptr &particle); + + /** + * This method is called for parsing an <em>anyAttribute</em> object somewhere in + * the schema. + */ + XsdWildcard::Ptr parseAnyAttribute(); + + /** + * This method is called for parsing unknown object as descendant of the <em>annotation</em> object. + */ + void parseUnknownDocumentation(); + + /** + * This method is called for parsing unknown object in the schema. + */ + void parseUnknown(); + + /** + * Returnes an source location for the current position. + */ + QSourceLocation currentSourceLocation() const; + + /** + * Converts a @p qualified name into a QXmlName @p name and does some error handling. + */ + void convertName(const QString &qualified, NamespaceSupport::NameType type, QXmlName &name); + + /** + * A helper method that reads in a 'name' attribute and checks it for syntactic errors. + */ + inline QString readNameAttribute(const char *elementName); + + /** + * A helper method that reads in an attribute that contains an QName and + * checks it for syntactic errors. + */ + inline QString readQNameAttribute(const QString &typeAttribute, const char *elementName); + + /** + * A helper method that reads in a namespace attribute and checks for syntactic errors. + */ + inline QString readNamespaceAttribute(const QString &attributeName, const char *elementName); + + /** + * A helper method that reads the final attribute and does correct handling of schema default definitions. + */ + inline SchemaType::DerivationConstraints readDerivationConstraintAttribute(const SchemaType::DerivationConstraints &allowedConstraints, const char *elementName); + + /** + * A helper method that reads the block attribute and does correct handling of schema default definitions. + */ + inline NamedSchemaComponent::BlockingConstraints readBlockingConstraintAttribute(const NamedSchemaComponent::BlockingConstraints &allowedConstraints, const char *elementName); + + /** + * A helper method that reads all components for a xpath expression for the current scope. + */ + XsdXPathExpression::Ptr readXPathExpression(const char *elementName); + + /** + * Describes the type of XPath that is allowed by the readXPathAttribute method. + */ + enum XPathType { + XPath20, + XPathSelector, + XPathField + }; + + /** + * A helper method that reads an attribute that represents a xpath query and does basic + * validation. + */ + QString readXPathAttribute(const QString &attributeName, XPathType type, const char *elementName); + + /** + * A helper method that reads in an "id" attribute, checks it for syntactic errors + * and tests whether a component with the same id has already been parsed. + */ + inline void validateIdAttribute(const char *elementName); + + /** + * Adds an @p element to the schema and checks for duplicated entries. + */ + void addElement(const XsdElement::Ptr &element); + + /** + * Adds an @p attribute to the schema and checks for duplicated entries. + */ + void addAttribute(const XsdAttribute::Ptr &attribute); + + /** + * Adds a @p type to the schema and checks for duplicated entries. + */ + void addType(const SchemaType::Ptr &type); + + /** + * Adds an anonymous @p type to the schema and checks for duplicated entries. + */ + void addAnonymousType(const SchemaType::Ptr &type); + + /** + * Adds an attribute @p group to the schema and checks for duplicated entries. + */ + void addAttributeGroup(const XsdAttributeGroup::Ptr &group); + + /** + * Adds an element @p group to the schema and checks for duplicated entries. + */ + void addElementGroup(const XsdModelGroup::Ptr &group); + + /** + * Adds a @p notation to the schema and checks for duplicated entries. + */ + void addNotation(const XsdNotation::Ptr ¬ation); + + /** + * Adds an identity @p constraint to the schema and checks for duplicated entries. + */ + void addIdentityConstraint(const XsdIdentityConstraint::Ptr &constraint); + + /** + * Adds the @p facet to the list of @p facets for @p type and checks for duplicates. + */ + void addFacet(const XsdFacet::Ptr &facet, XsdFacet::Hash &facets, const SchemaType::Ptr &type); + + /** + * Sets up the state machines for validating the right occurrence of xml elements. + */ + void setupStateMachines(); + + /** + * Sets up a list of names of known builtin types. + */ + void setupBuiltinTypeNames(); + + /** + * Checks whether the given @p tag is equal to the given @p token and + * the given @p namespaceToken is the XML Schema namespace. + */ + inline bool isSchemaTag(XsdSchemaToken::NodeName tag, XsdSchemaToken::NodeName token, XsdSchemaToken::NodeName namespaceToken) const; + + XsdSchemaContext::Ptr m_context; + XsdSchemaParserContext::Ptr m_parserContext; + NamePool::Ptr m_namePool; + NamespaceSupport m_namespaceSupport; + XsdSchemaResolver::Ptr m_schemaResolver; + XsdSchema::Ptr m_schema; + + QString m_targetNamespace; + QString m_attributeFormDefault; + QString m_elementFormDefault; + QString m_blockDefault; + QString m_finalDefault; + QString m_xpathDefaultNamespace; + QXmlName m_defaultAttributes; + XsdComplexType::OpenContent::Ptr m_defaultOpenContent; + bool m_defaultOpenContentAppliesToEmpty; + + NamespaceSet m_includedSchemas; + NamespaceSet m_importedSchemas; + NamespaceSet m_redefinedSchemas; + QUrl m_documentURI; + XsdIdCache::Ptr m_idCache; + QHash<XsdTagScope::Type, XsdStateMachine<XsdSchemaToken::NodeName> > m_stateMachines; + ComponentLocationHash m_componentLocationHash; + QSet<QXmlName> m_builtinTypeNames; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdschemaparser_setup.cpp b/src/xmlpatterns/schema/qxsdschemaparser_setup.cpp new file mode 100644 index 0000000..abd6262 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdschemaparser_setup.cpp @@ -0,0 +1,1110 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdschemaparser_p.h" + +#include "qbuiltintypes_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +/** + * @page using_dfa_for_schema Using DFA for validation of correct XML tag occurrence + * + * This page describes how to use DFAs for validating that the XML child tags of an + * XML parent tag occur in the right order. + * + * To validate the occurence of XML tags one need a regular expression that describes + * which tags can appear how often in what context. For example the regular expression + * of the global <em>attribute</em> tag in XML Schema is (annotation?, simpleType?). + * That means the <em>attribute</em> tag can contain an <em>annotation</em> tag followed + * by a <em>simpleType</em> tag, or just one <em>simpleType</em> tag and even no child + * tag at all. + * So the regular expression describes some kind of language and all the various occurrences + * of the child tags can be seen as words of that language. + * We can create a DFA now, that accepts all words (and only these words) of that language + * and whenever we want to check if a sequence of child tags belongs to the language, + * we test if the sequence passes the DFA successfully. + * + * The following example shows how to create the DFA for the regular expression method + * above. + * + * \dotfile GlobalAttribute_diagram.dot + * + * At first we need a start state (1), that's the state the DFA is before it + * starts running. As our regular expression allows that there are no child tags, the + * start state is an end state as well (marked by the double circle). + * Now we fetch the first token from the XML file (let's assume it is an <em>annotation</em> tag) + * and check if there is an edge labled with the tag name leaving the current state of the DFA. + * If there is no such edge, the input doesn't fullfill the rules of the regular expression, + * so we throw an error. Otherwise we follow that edge and the DFA is set to the new state (2) the + * edge points to. Now we fetch the next token from the XML file and do the previous steps again. + * If there is no further input from the XML file, we check whether the DFA is in an end state and + * throw an error if not. + * + * So the algorithm for checking is quite simple, the whole logic is encoded in the DFA and creating + * one for a regular expression is sometimes not easy, however the ones for XML Schema are straight + * forward. + * + * <h2>Legend:</h2> + * \dotfile legend.dot + * <br> + * + * <h2>DFA for <em>all</em> tag</h2> + * \dotfile All_diagram.dot + * <br> + * <h2>DFA for <em>alternative</em> tag</h2> + * \dotfile Alternative_diagram.dot + * <br> + * <h2>DFA for <em>annotation</em> tag</h2> + * \dotfile Annotation_diagram.dot + * <br> + * <h2>DFA for <em>anyAttribute</em> tag</h2> + * \dotfile AnyAttribute_diagram.dot + * <br> + * <h2>DFA for <em>any</em> tag</h2> + * \dotfile Any_diagram.dot + * <br> + * <h2>DFA for <em>assert</em> tag</h2> + * \dotfile Assert_diagram.dot + * <br> + * <h2>DFA for <em>choice</em> tag</h2> + * \dotfile Choice_diagram.dot + * <br> + * <h2>DFA for <em>complexContent</em> tag</h2> + * \dotfile ComplexContent_diagram.dot + * <br> + * <h2>DFA for <em>extension</em> tag inside a <em>complexContent</em> tag</h2> + * \dotfile ComplexContentExtension_diagram.dot + * <br> + * <h2>DFA for <em>restriction</em> tag inside a <em>complexContent</em> tag</h2> + * \dotfile ComplexContentRestriction_diagram.dot + * <br> + * <h2>DFA for <em>defaultOpenContent</em> tag</h2> + * \dotfile DefaultOpenContent_diagram.dot + * <br> + * <h2>DFA for <em>enumeration</em> tag</h2> + * \dotfile EnumerationFacet_diagram.dot + * <br> + * <h2>DFA for <em>field</em> tag</h2> + * \dotfile Field_diagram.dot + * <br> + * <h2>DFA for <em>fractionDigits</em> tag</h2> + * \dotfile FractionDigitsFacet_diagram.dot + * <br> + * <h2>DFA for <em>attribute</em> tag</h2> + * \dotfile GlobalAttribute_diagram.dot + * <br> + * <h2>DFA for <em>complexType</em> tag</h2> + * \dotfile GlobalComplexType_diagram.dot + * <br> + * <h2>DFA for <em>element</em> tag</h2> + * \dotfile GlobalElement_diagram.dot + * <br> + * <h2>DFA for <em>simpleType</em> tag</h2> + * \dotfile GlobalSimpleType_diagram.dot + * <br> + * <h2>DFA for <em>import</em> tag</h2> + * \dotfile Import_diagram.dot + * <br> + * <h2>DFA for <em>include</em> tag</h2> + * \dotfile Include_diagram.dot + * <br> + * <h2>DFA for <em>key</em> tag</h2> + * \dotfile Key_diagram.dot + * <br> + * <h2>DFA for <em>keyref</em> tag</h2> + * \dotfile KeyRef_diagram.dot + * <br> + * <h2>DFA for <em>length</em> tag</h2> + * \dotfile LengthFacet_diagram.dot + * <br> + * <h2>DFA for <em>list</em> tag</h2> + * \dotfile List_diagram.dot + * <br> + * <h2>DFA for <em>all</em> tag</h2> + * \dotfile LocalAll_diagram.dot + * <br> + * <h2>DFA for <em>attribute</em> tag</h2> + * \dotfile LocalAttribute_diagram.dot + * <br> + * <h2>DFA for <em>choice</em> tag</h2> + * \dotfile LocalChoice_diagram.dot + * <br> + * <h2>DFA for <em>complexType</em> tag</h2> + * \dotfile LocalComplexType_diagram.dot + * <br> + * <h2>DFA for <em>element</em> tag</h2> + * \dotfile LocalElement_diagram.dot + * <br> + * <h2>DFA for <em>sequence</em> tag</h2> + * \dotfile LocalSequence_diagram.dot + * <br> + * <h2>DFA for <em>simpleType</em> tag that </h2> + * \dotfile LocalSimpleType_diagram.dot + * <br> + * <h2>DFA for <em>maxExclusive</em> tag</h2> + * \dotfile MaxExclusiveFacet_diagram.dot + * <br> + * <h2>DFA for <em>maxInclusive</em> tag</h2> + * \dotfile MaxInclusiveFacet_diagram.dot + * <br> + * <h2>DFA for <em>maxLength</em> tag</h2> + * \dotfile MaxLengthFacet_diagram.dot + * <br> + * <h2>DFA for <em>minExclusive</em> tag</h2> + * \dotfile MinExclusiveFacet_diagram.dot + * <br> + * <h2>DFA for <em>minInclusive</em> tag</h2> + * \dotfile MinInclusiveFacet_diagram.dot + * <br> + * <h2>DFA for <em>minLength</em> tag</h2> + * \dotfile MinLengthFacet_diagram.dot + * <br> + * <h2>DFA for <em>attributeGroup</em> tag without <em>ref</em> attribute</h2> + * \dotfile NamedAttributeGroup_diagram.dot + * <br> + * <h2>DFA for <em>group</em> tag without <em>ref</em> attribute</h2> + * \dotfile NamedGroup_diagram.dot + * <br> + * <h2>DFA for <em>notation</em> tag</h2> + * \dotfile Notation_diagram.dot + * <br> + * <h2>DFA for <em>override</em> tag</h2> + * \dotfile Override_diagram.dot + * <br> + * <h2>DFA for <em>pattern</em> tag</h2> + * \dotfile PatternFacet_diagram.dot + * <br> + * <h2>DFA for <em>redefine</em> tag</h2> + * \dotfile Redefine_diagram.dot + * <br> + * <h2>DFA for <em>attributeGroup</em> tag with <em>ref</em> attribute</h2> + * \dotfile ReferredAttributeGroup_diagram.dot + * <br> + * <h2>DFA for <em>group</em> tag with <em>ref</em> attribute</h2> + * \dotfile ReferredGroup_diagram.dot + * <br> + * <h2>DFA for <em>schema</em> tag</h2> + * \dotfile Schema_diagram.dot + * <br> + * <h2>DFA for <em>selector</em> tag</h2> + * \dotfile Selector_diagram.dot + * <br> + * <h2>DFA for <em>sequence</em> tag</h2> + * \dotfile Sequence_diagram.dot + * <br> + * <h2>DFA for <em>simpleContent</em> tag</h2> + * \dotfile SimpleContent_diagram.dot + * <br> + * <h2>DFA for <em>extension</em> tag inside a <em>simpleContent</em> tag</h2> + * \dotfile SimpleContentExtension_diagram.dot + * <br> + * <h2>DFA for <em>restriction</em> tag inside a <em>simpleContent</em> tag</h2> + * \dotfile SimpleContentRestriction_diagram.dot + * <br> + * <h2>DFA for <em>restriction</em> tag inside a <em>simpleType</em> tag</h2> + * \dotfile SimpleRestriction_diagram.dot + * <br> + * <h2>DFA for <em>totalDigits</em> tag</h2> + * \dotfile TotalDigitsFacet_diagram.dot + * <br> + * <h2>DFA for <em>union</em> tag</h2> + * \dotfile Union_diagram.dot + * <br> + * <h2>DFA for <em>unique</em> tag</h2> + * \dotfile Unique_diagram.dot + * <br> + * <h2>DFA for <em>whiteSpace</em> tag</h2> + * \dotfile WhiteSpaceFacet_diagram.dot + */ + +void XsdSchemaParser::setupStateMachines() +{ + { + XsdStateMachine<XsdSchemaToken::NodeName> machine(m_namePool); + + // setup state machine for (annotation?, simpleType?) : attribute + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId startState = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::StartEndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s1 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s2 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + + machine.addTransition(startState, XsdSchemaToken::Annotation, s1); + machine.addTransition(startState, XsdSchemaToken::SimpleType, s2); + machine.addTransition(s1, XsdSchemaToken::SimpleType, s2); + + m_stateMachines.insert(XsdTagScope::GlobalAttribute, machine); + m_stateMachines.insert(XsdTagScope::LocalAttribute, machine); + } + + { + XsdStateMachine<XsdSchemaToken::NodeName> machine(m_namePool); + + // setup state machine for (annotation?, ((simpleType | complexType)?, alternative*, (unique | key | keyref)*)) : element + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId startState = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::StartEndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s1 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s2 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s3 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s4 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + + machine.addTransition(startState, XsdSchemaToken::Annotation, s1); + machine.addTransition(startState, XsdSchemaToken::SimpleType, s2); + machine.addTransition(startState, XsdSchemaToken::ComplexType, s2); + machine.addTransition(startState, XsdSchemaToken::Alternative, s3); + machine.addTransition(startState, XsdSchemaToken::Unique, s4); + machine.addTransition(startState, XsdSchemaToken::Key, s4); + machine.addTransition(startState, XsdSchemaToken::Keyref, s4); + + machine.addTransition(s1, XsdSchemaToken::SimpleType, s2); + machine.addTransition(s1, XsdSchemaToken::ComplexType, s2); + machine.addTransition(s1, XsdSchemaToken::Alternative, s3); + machine.addTransition(s1, XsdSchemaToken::Unique, s4); + machine.addTransition(s1, XsdSchemaToken::Key, s4); + machine.addTransition(s1, XsdSchemaToken::Keyref, s4); + + machine.addTransition(s2, XsdSchemaToken::Alternative, s3); + machine.addTransition(s2, XsdSchemaToken::Unique, s4); + machine.addTransition(s2, XsdSchemaToken::Key, s4); + machine.addTransition(s2, XsdSchemaToken::Keyref, s4); + + machine.addTransition(s3, XsdSchemaToken::Alternative, s3); + machine.addTransition(s3, XsdSchemaToken::Unique, s4); + machine.addTransition(s3, XsdSchemaToken::Key, s4); + machine.addTransition(s3, XsdSchemaToken::Keyref, s4); + + machine.addTransition(s4, XsdSchemaToken::Unique, s4); + machine.addTransition(s4, XsdSchemaToken::Key, s4); + machine.addTransition(s4, XsdSchemaToken::Keyref, s4); + + m_stateMachines.insert(XsdTagScope::GlobalElement, machine); + m_stateMachines.insert(XsdTagScope::LocalElement, machine); + } + + { + XsdStateMachine<XsdSchemaToken::NodeName> machine(m_namePool); + + // setup state machine for (annotation?, (simpleContent | complexContent | (openContent?, (group | all | choice | sequence)?, ((attribute | attributeGroup)*, anyAttribute?), assert*))) : complexType + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId startState = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::StartEndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s1 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s2 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s3 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s4 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s5 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s6 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s7 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + + machine.addTransition(startState, XsdSchemaToken::Annotation, s1); + machine.addTransition(startState, XsdSchemaToken::SimpleContent, s2); + machine.addTransition(startState, XsdSchemaToken::ComplexContent, s2); + machine.addTransition(startState, XsdSchemaToken::OpenContent, s3); + machine.addTransition(startState, XsdSchemaToken::Group, s4); + machine.addTransition(startState, XsdSchemaToken::All, s4); + machine.addTransition(startState, XsdSchemaToken::Choice, s4); + machine.addTransition(startState, XsdSchemaToken::Sequence, s4); + machine.addTransition(startState, XsdSchemaToken::Attribute, s5); + machine.addTransition(startState, XsdSchemaToken::AttributeGroup, s5); + machine.addTransition(startState, XsdSchemaToken::AnyAttribute, s6); + machine.addTransition(startState, XsdSchemaToken::Assert, s7); + + machine.addTransition(s1, XsdSchemaToken::SimpleContent, s2); + machine.addTransition(s1, XsdSchemaToken::ComplexContent, s2); + machine.addTransition(s1, XsdSchemaToken::OpenContent, s3); + machine.addTransition(s1, XsdSchemaToken::Group, s4); + machine.addTransition(s1, XsdSchemaToken::All, s4); + machine.addTransition(s1, XsdSchemaToken::Choice, s4); + machine.addTransition(s1, XsdSchemaToken::Sequence, s4); + machine.addTransition(s1, XsdSchemaToken::Attribute, s5); + machine.addTransition(s1, XsdSchemaToken::AttributeGroup, s5); + machine.addTransition(s1, XsdSchemaToken::AnyAttribute, s6); + machine.addTransition(s1, XsdSchemaToken::Assert, s7); + + machine.addTransition(s3, XsdSchemaToken::Group, s4); + machine.addTransition(s3, XsdSchemaToken::All, s4); + machine.addTransition(s3, XsdSchemaToken::Choice, s4); + machine.addTransition(s3, XsdSchemaToken::Sequence, s4); + machine.addTransition(s3, XsdSchemaToken::Attribute, s5); + machine.addTransition(s3, XsdSchemaToken::AttributeGroup, s5); + machine.addTransition(s3, XsdSchemaToken::AnyAttribute, s6); + machine.addTransition(s3, XsdSchemaToken::Assert, s7); + + machine.addTransition(s4, XsdSchemaToken::Attribute, s5); + machine.addTransition(s4, XsdSchemaToken::AttributeGroup, s5); + machine.addTransition(s4, XsdSchemaToken::AnyAttribute, s6); + machine.addTransition(s4, XsdSchemaToken::Assert, s7); + + machine.addTransition(s5, XsdSchemaToken::Attribute, s5); + machine.addTransition(s5, XsdSchemaToken::AttributeGroup, s5); + machine.addTransition(s5, XsdSchemaToken::AnyAttribute, s6); + machine.addTransition(s5, XsdSchemaToken::Assert, s7); + + machine.addTransition(s6, XsdSchemaToken::Assert, s7); + + machine.addTransition(s7, XsdSchemaToken::Assert, s7); + + m_stateMachines.insert(XsdTagScope::GlobalComplexType, machine); + m_stateMachines.insert(XsdTagScope::LocalComplexType, machine); + } + + { + XsdStateMachine<XsdSchemaToken::NodeName> machine(m_namePool); + + // setup state machine for (annotation?, (restriction | extension)) : simpleContent/complexContent + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId startState = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::StartState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s1 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::InternalState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s2 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + + machine.addTransition(startState, XsdSchemaToken::Annotation, s1); + machine.addTransition(startState, XsdSchemaToken::Restriction, s2); + machine.addTransition(startState, XsdSchemaToken::Extension, s2); + + machine.addTransition(s1, XsdSchemaToken::Restriction, s2); + machine.addTransition(s1, XsdSchemaToken::Extension, s2); + + m_stateMachines.insert(XsdTagScope::SimpleContent, machine); + m_stateMachines.insert(XsdTagScope::ComplexContent, machine); + } + + { + XsdStateMachine<XsdSchemaToken::NodeName> machine(m_namePool); + + // setup state machine for (annotation?, (simpleType?, (minExclusive | minInclusive | maxExclusive | maxInclusive | totalDigits | fractionDigits | length | minLength | maxLength | enumeration | whiteSpace | pattern | assertion)*)?, ((attribute | attributeGroup)*, anyAttribute?), assert*) : simpleContent restriction + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId startState = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::StartEndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s1 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s2 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s3 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s4 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s5 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s6 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + + machine.addTransition(startState, XsdSchemaToken::Annotation, s1); + machine.addTransition(startState, XsdSchemaToken::SimpleType, s2); + machine.addTransition(startState, XsdSchemaToken::MinExclusive, s3); + machine.addTransition(startState, XsdSchemaToken::MinInclusive, s3); + machine.addTransition(startState, XsdSchemaToken::MaxExclusive, s3); + machine.addTransition(startState, XsdSchemaToken::MaxInclusive, s3); + machine.addTransition(startState, XsdSchemaToken::TotalDigits, s3); + machine.addTransition(startState, XsdSchemaToken::FractionDigits, s3); + machine.addTransition(startState, XsdSchemaToken::Length, s3); + machine.addTransition(startState, XsdSchemaToken::MinLength, s3); + machine.addTransition(startState, XsdSchemaToken::MaxLength, s3); + machine.addTransition(startState, XsdSchemaToken::Enumeration, s3); + machine.addTransition(startState, XsdSchemaToken::WhiteSpace, s3); + machine.addTransition(startState, XsdSchemaToken::Pattern, s3); + machine.addTransition(startState, XsdSchemaToken::Assertion, s3); + machine.addTransition(startState, XsdSchemaToken::Attribute, s4); + machine.addTransition(startState, XsdSchemaToken::AttributeGroup, s4); + machine.addTransition(startState, XsdSchemaToken::AnyAttribute, s5); + machine.addTransition(startState, XsdSchemaToken::Assert, s6); + + machine.addTransition(s1, XsdSchemaToken::SimpleType, s2); + machine.addTransition(s1, XsdSchemaToken::MinExclusive, s3); + machine.addTransition(s1, XsdSchemaToken::MinInclusive, s3); + machine.addTransition(s1, XsdSchemaToken::MaxExclusive, s3); + machine.addTransition(s1, XsdSchemaToken::MaxInclusive, s3); + machine.addTransition(s1, XsdSchemaToken::TotalDigits, s3); + machine.addTransition(s1, XsdSchemaToken::FractionDigits, s3); + machine.addTransition(s1, XsdSchemaToken::Length, s3); + machine.addTransition(s1, XsdSchemaToken::MinLength, s3); + machine.addTransition(s1, XsdSchemaToken::MaxLength, s3); + machine.addTransition(s1, XsdSchemaToken::Enumeration, s3); + machine.addTransition(s1, XsdSchemaToken::WhiteSpace, s3); + machine.addTransition(s1, XsdSchemaToken::Pattern, s3); + machine.addTransition(s1, XsdSchemaToken::Assertion, s3); + machine.addTransition(s1, XsdSchemaToken::Attribute, s4); + machine.addTransition(s1, XsdSchemaToken::AttributeGroup, s4); + machine.addTransition(s1, XsdSchemaToken::AnyAttribute, s5); + machine.addTransition(s1, XsdSchemaToken::Assert, s6); + + machine.addTransition(s2, XsdSchemaToken::MinExclusive, s3); + machine.addTransition(s2, XsdSchemaToken::MinInclusive, s3); + machine.addTransition(s2, XsdSchemaToken::MaxExclusive, s3); + machine.addTransition(s2, XsdSchemaToken::MaxInclusive, s3); + machine.addTransition(s2, XsdSchemaToken::TotalDigits, s3); + machine.addTransition(s2, XsdSchemaToken::FractionDigits, s3); + machine.addTransition(s2, XsdSchemaToken::Length, s3); + machine.addTransition(s2, XsdSchemaToken::MinLength, s3); + machine.addTransition(s2, XsdSchemaToken::MaxLength, s3); + machine.addTransition(s2, XsdSchemaToken::Enumeration, s3); + machine.addTransition(s2, XsdSchemaToken::WhiteSpace, s3); + machine.addTransition(s2, XsdSchemaToken::Pattern, s3); + machine.addTransition(s2, XsdSchemaToken::Assertion, s3); + machine.addTransition(s2, XsdSchemaToken::Attribute, s4); + machine.addTransition(s2, XsdSchemaToken::AttributeGroup, s4); + machine.addTransition(s2, XsdSchemaToken::AnyAttribute, s5); + machine.addTransition(s2, XsdSchemaToken::Assert, s6); + + machine.addTransition(s3, XsdSchemaToken::MinExclusive, s3); + machine.addTransition(s3, XsdSchemaToken::MinInclusive, s3); + machine.addTransition(s3, XsdSchemaToken::MaxExclusive, s3); + machine.addTransition(s3, XsdSchemaToken::MaxInclusive, s3); + machine.addTransition(s3, XsdSchemaToken::TotalDigits, s3); + machine.addTransition(s3, XsdSchemaToken::FractionDigits, s3); + machine.addTransition(s3, XsdSchemaToken::Length, s3); + machine.addTransition(s3, XsdSchemaToken::MinLength, s3); + machine.addTransition(s3, XsdSchemaToken::MaxLength, s3); + machine.addTransition(s3, XsdSchemaToken::Enumeration, s3); + machine.addTransition(s3, XsdSchemaToken::WhiteSpace, s3); + machine.addTransition(s3, XsdSchemaToken::Pattern, s3); + machine.addTransition(s3, XsdSchemaToken::Assertion, s3); + machine.addTransition(s3, XsdSchemaToken::Attribute, s4); + machine.addTransition(s3, XsdSchemaToken::AttributeGroup, s4); + machine.addTransition(s3, XsdSchemaToken::AnyAttribute, s5); + machine.addTransition(s3, XsdSchemaToken::Assert, s6); + + machine.addTransition(s4, XsdSchemaToken::Attribute, s4); + machine.addTransition(s4, XsdSchemaToken::AttributeGroup, s4); + machine.addTransition(s4, XsdSchemaToken::AnyAttribute, s5); + machine.addTransition(s4, XsdSchemaToken::Assert, s6); + + machine.addTransition(s5, XsdSchemaToken::Assert, s6); + + machine.addTransition(s6, XsdSchemaToken::Assert, s6); + + m_stateMachines.insert(XsdTagScope::SimpleContentRestriction, machine); + } + + { + XsdStateMachine<XsdSchemaToken::NodeName> machine(m_namePool); + + // setup state machine for (annotation?, ((attribute | attributeGroup)*, anyAttribute?), assert*) : simple content extension + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId startState = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::StartEndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s1 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s2 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s3 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s4 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + + machine.addTransition(startState, XsdSchemaToken::Annotation, s1); + machine.addTransition(startState, XsdSchemaToken::Attribute, s2); + machine.addTransition(startState, XsdSchemaToken::AttributeGroup, s2); + machine.addTransition(startState, XsdSchemaToken::AnyAttribute, s3); + machine.addTransition(startState, XsdSchemaToken::Assert, s4); + + machine.addTransition(s1, XsdSchemaToken::Attribute, s2); + machine.addTransition(s1, XsdSchemaToken::AttributeGroup, s2); + machine.addTransition(s1, XsdSchemaToken::AnyAttribute, s3); + machine.addTransition(s1, XsdSchemaToken::Assert, s4); + + machine.addTransition(s2, XsdSchemaToken::Attribute, s2); + machine.addTransition(s2, XsdSchemaToken::AttributeGroup, s2); + machine.addTransition(s2, XsdSchemaToken::AnyAttribute, s3); + machine.addTransition(s2, XsdSchemaToken::Assert, s4); + + machine.addTransition(s3, XsdSchemaToken::Assert, s4); + + machine.addTransition(s4, XsdSchemaToken::Assert, s4); + + m_stateMachines.insert(XsdTagScope::SimpleContentExtension, machine); + } + + { + XsdStateMachine<XsdSchemaToken::NodeName> machine(m_namePool); + + // setup state machine for (annotation?, openContent?, ((group | all | choice | sequence)?, ((attribute | attributeGroup)*, anyAttribute?), assert*)) : complex content restriction/complex content extension + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId startState = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::StartEndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s1 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s2 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s3 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s4 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s5 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s6 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + + machine.addTransition(startState, XsdSchemaToken::Annotation, s1); + machine.addTransition(startState, XsdSchemaToken::OpenContent, s2); + machine.addTransition(startState, XsdSchemaToken::Group, s3); + machine.addTransition(startState, XsdSchemaToken::All, s3); + machine.addTransition(startState, XsdSchemaToken::Choice, s3); + machine.addTransition(startState, XsdSchemaToken::Sequence, s3); + machine.addTransition(startState, XsdSchemaToken::Attribute, s4); + machine.addTransition(startState, XsdSchemaToken::AttributeGroup, s4); + machine.addTransition(startState, XsdSchemaToken::AnyAttribute, s5); + machine.addTransition(startState, XsdSchemaToken::Assert, s6); + + machine.addTransition(s1, XsdSchemaToken::OpenContent, s2); + machine.addTransition(s1, XsdSchemaToken::Group, s3); + machine.addTransition(s1, XsdSchemaToken::All, s3); + machine.addTransition(s1, XsdSchemaToken::Choice, s3); + machine.addTransition(s1, XsdSchemaToken::Sequence, s3); + machine.addTransition(s1, XsdSchemaToken::Attribute, s4); + machine.addTransition(s1, XsdSchemaToken::AttributeGroup, s4); + machine.addTransition(s1, XsdSchemaToken::AnyAttribute, s5); + machine.addTransition(s1, XsdSchemaToken::Assert, s6); + + machine.addTransition(s2, XsdSchemaToken::Group, s3); + machine.addTransition(s2, XsdSchemaToken::All, s3); + machine.addTransition(s2, XsdSchemaToken::Choice, s3); + machine.addTransition(s2, XsdSchemaToken::Sequence, s3); + machine.addTransition(s2, XsdSchemaToken::Attribute, s4); + machine.addTransition(s2, XsdSchemaToken::AttributeGroup, s4); + machine.addTransition(s2, XsdSchemaToken::AnyAttribute, s5); + machine.addTransition(s2, XsdSchemaToken::Assert, s6); + + machine.addTransition(s3, XsdSchemaToken::Attribute, s4); + machine.addTransition(s3, XsdSchemaToken::AttributeGroup, s4); + machine.addTransition(s3, XsdSchemaToken::AnyAttribute, s5); + machine.addTransition(s3, XsdSchemaToken::Assert, s6); + + machine.addTransition(s4, XsdSchemaToken::Attribute, s4); + machine.addTransition(s4, XsdSchemaToken::AttributeGroup, s4); + machine.addTransition(s4, XsdSchemaToken::AnyAttribute, s5); + machine.addTransition(s4, XsdSchemaToken::Assert, s6); + + machine.addTransition(s5, XsdSchemaToken::Assert, s6); + + machine.addTransition(s6, XsdSchemaToken::Assert, s6); + + m_stateMachines.insert(XsdTagScope::ComplexContentRestriction, machine); + m_stateMachines.insert(XsdTagScope::ComplexContentExtension, machine); + } + + { + XsdStateMachine<XsdSchemaToken::NodeName> machine(m_namePool); + + // setup state machine for (annotation?, ((attribute | attributeGroup)*, anyAttribute?)) : named attribute group + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId startState = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::StartEndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s1 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s2 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s3 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + + machine.addTransition(startState, XsdSchemaToken::Annotation, s1); + machine.addTransition(startState, XsdSchemaToken::Attribute, s2); + machine.addTransition(startState, XsdSchemaToken::AttributeGroup, s2); + machine.addTransition(startState, XsdSchemaToken::AnyAttribute, s3); + + machine.addTransition(s1, XsdSchemaToken::Attribute, s2); + machine.addTransition(s1, XsdSchemaToken::AttributeGroup, s2); + machine.addTransition(s1, XsdSchemaToken::AnyAttribute, s3); + + machine.addTransition(s2, XsdSchemaToken::Attribute, s2); + machine.addTransition(s2, XsdSchemaToken::AttributeGroup, s2); + machine.addTransition(s2, XsdSchemaToken::AnyAttribute, s3); + + m_stateMachines.insert(XsdTagScope::NamedAttributeGroup, machine); + } + + { + XsdStateMachine<XsdSchemaToken::NodeName> machine(m_namePool); + + // setup state machine for (annotation?, (all | choice | sequence)?) : group + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId startState = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::StartEndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s1 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s2 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + + machine.addTransition(startState, XsdSchemaToken::Annotation, s1); + machine.addTransition(startState, XsdSchemaToken::All, s2); + machine.addTransition(startState, XsdSchemaToken::Choice, s2); + machine.addTransition(startState, XsdSchemaToken::Sequence, s2); + + machine.addTransition(s1, XsdSchemaToken::All, s2); + machine.addTransition(s1, XsdSchemaToken::Choice, s2); + machine.addTransition(s1, XsdSchemaToken::Sequence, s2); + + m_stateMachines.insert(XsdTagScope::NamedGroup, machine); + m_stateMachines.insert(XsdTagScope::ReferredGroup, machine); + } + + { + XsdStateMachine<XsdSchemaToken::NodeName> machine(m_namePool); + + // setup state machine for (annotation?, (element | any)*) : all + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId startState = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::StartEndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s1 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s2 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + + machine.addTransition(startState, XsdSchemaToken::Annotation, s1); + machine.addTransition(startState, XsdSchemaToken::Element, s2); + machine.addTransition(startState, XsdSchemaToken::Any, s2); + + machine.addTransition(s1, XsdSchemaToken::Element, s2); + machine.addTransition(s1, XsdSchemaToken::Any, s2); + + machine.addTransition(s2, XsdSchemaToken::Element, s2); + machine.addTransition(s2, XsdSchemaToken::Any, s2); + + m_stateMachines.insert(XsdTagScope::All, machine); + m_stateMachines.insert(XsdTagScope::LocalAll, machine); + } + + { + XsdStateMachine<XsdSchemaToken::NodeName> machine(m_namePool); + + // setup state machine for (annotation?, (element | group | choice | sequence | any)*) : choice sequence + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId startState = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::StartEndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s1 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s2 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + + machine.addTransition(startState, XsdSchemaToken::Annotation, s1); + machine.addTransition(startState, XsdSchemaToken::Element, s2); + machine.addTransition(startState, XsdSchemaToken::Group, s2); + machine.addTransition(startState, XsdSchemaToken::Choice, s2); + machine.addTransition(startState, XsdSchemaToken::Sequence, s2); + machine.addTransition(startState, XsdSchemaToken::Any, s2); + + machine.addTransition(s1, XsdSchemaToken::Element, s2); + machine.addTransition(s1, XsdSchemaToken::Group, s2); + machine.addTransition(s1, XsdSchemaToken::Choice, s2); + machine.addTransition(s1, XsdSchemaToken::Sequence, s2); + machine.addTransition(s1, XsdSchemaToken::Any, s2); + + machine.addTransition(s2, XsdSchemaToken::Element, s2); + machine.addTransition(s2, XsdSchemaToken::Group, s2); + machine.addTransition(s2, XsdSchemaToken::Choice, s2); + machine.addTransition(s2, XsdSchemaToken::Sequence, s2); + machine.addTransition(s2, XsdSchemaToken::Any, s2); + + m_stateMachines.insert(XsdTagScope::Choice, machine); + m_stateMachines.insert(XsdTagScope::LocalChoice, machine); + m_stateMachines.insert(XsdTagScope::Sequence, machine); + m_stateMachines.insert(XsdTagScope::LocalSequence, machine); + } + + { + XsdStateMachine<XsdSchemaToken::NodeName> machine(m_namePool); + + // setup state machine for (annotation?) : any/selector/field/notation/include/import/referred attribute group/anyAttribute/all facets/assert + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId startState = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::StartEndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s1 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + + machine.addTransition(startState, XsdSchemaToken::Annotation, s1); + + m_stateMachines.insert(XsdTagScope::Any, machine); + m_stateMachines.insert(XsdTagScope::Selector, machine); + m_stateMachines.insert(XsdTagScope::Field, machine); + m_stateMachines.insert(XsdTagScope::Notation, machine); + m_stateMachines.insert(XsdTagScope::Include, machine); + m_stateMachines.insert(XsdTagScope::Import, machine); + m_stateMachines.insert(XsdTagScope::ReferredAttributeGroup, machine); + m_stateMachines.insert(XsdTagScope::AnyAttribute, machine); + m_stateMachines.insert(XsdTagScope::MinExclusiveFacet, machine); + m_stateMachines.insert(XsdTagScope::MinInclusiveFacet, machine); + m_stateMachines.insert(XsdTagScope::MaxExclusiveFacet, machine); + m_stateMachines.insert(XsdTagScope::MaxInclusiveFacet, machine); + m_stateMachines.insert(XsdTagScope::TotalDigitsFacet, machine); + m_stateMachines.insert(XsdTagScope::FractionDigitsFacet, machine); + m_stateMachines.insert(XsdTagScope::LengthFacet, machine); + m_stateMachines.insert(XsdTagScope::MinLengthFacet, machine); + m_stateMachines.insert(XsdTagScope::MaxLengthFacet, machine); + m_stateMachines.insert(XsdTagScope::EnumerationFacet, machine); + m_stateMachines.insert(XsdTagScope::WhiteSpaceFacet, machine); + m_stateMachines.insert(XsdTagScope::PatternFacet, machine); + m_stateMachines.insert(XsdTagScope::Assert, machine); + m_stateMachines.insert(XsdTagScope::Assertion, machine); + } + + { + XsdStateMachine<XsdSchemaToken::NodeName> machine(m_namePool); + + // setup state machine for (annotation?, (selector, field+)) : unique/key/keyref + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId startState = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::StartState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s1 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::InternalState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s2 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::InternalState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s3 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + + machine.addTransition(startState, XsdSchemaToken::Annotation, s1); + machine.addTransition(startState, XsdSchemaToken::Selector, s2); + + machine.addTransition(s1, XsdSchemaToken::Selector, s2); + machine.addTransition(s2, XsdSchemaToken::Field, s3); + machine.addTransition(s3, XsdSchemaToken::Field, s3); + + m_stateMachines.insert(XsdTagScope::Unique, machine); + m_stateMachines.insert(XsdTagScope::Key, machine); + m_stateMachines.insert(XsdTagScope::KeyRef, machine); + } + + { + XsdStateMachine<XsdSchemaToken::NodeName> machine(m_namePool); + + // setup state machine for (annotation?, (simpleType | complexType)?) : alternative + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId startState = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::StartEndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s1 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s2 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + + machine.addTransition(startState, XsdSchemaToken::Annotation, s1); + machine.addTransition(startState, XsdSchemaToken::SimpleType, s2); + machine.addTransition(startState, XsdSchemaToken::ComplexType, s2); + + machine.addTransition(s1, XsdSchemaToken::SimpleType, s2); + machine.addTransition(s1, XsdSchemaToken::ComplexType, s2); + + m_stateMachines.insert(XsdTagScope::Alternative, machine); + } + + { + XsdStateMachine<XsdSchemaToken::NodeName> machine(m_namePool); + + // setup state machine for (appinfo | documentation)* : annotation + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId startState = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::StartEndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s1 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + + machine.addTransition(startState, XsdSchemaToken::Appinfo, s1); + machine.addTransition(startState, XsdSchemaToken::Documentation, s1); + + machine.addTransition(s1, XsdSchemaToken::Appinfo, s1); + machine.addTransition(s1, XsdSchemaToken::Documentation, s1); + + m_stateMachines.insert(XsdTagScope::Annotation, machine); + } + + { + XsdStateMachine<XsdSchemaToken::NodeName> machine(m_namePool); + + // setup state machine for (annotation?, (restriction | list | union)) : simpleType + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId startState = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::StartState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s1 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::InternalState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s2 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + + machine.addTransition(startState, XsdSchemaToken::Annotation, s1); + machine.addTransition(startState, XsdSchemaToken::Restriction, s2); + machine.addTransition(startState, XsdSchemaToken::List, s2); + machine.addTransition(startState, XsdSchemaToken::Union, s2); + + machine.addTransition(s1, XsdSchemaToken::Restriction, s2); + machine.addTransition(s1, XsdSchemaToken::List, s2); + machine.addTransition(s1, XsdSchemaToken::Union, s2); + + m_stateMachines.insert(XsdTagScope::GlobalSimpleType, machine); + m_stateMachines.insert(XsdTagScope::LocalSimpleType, machine); + } + + { + XsdStateMachine<XsdSchemaToken::NodeName> machine(m_namePool); + + // setup state machine for (annotation?, (simpleType?, (minExclusive | minInclusive | maxExclusive | maxInclusive | totalDigits | fractionDigits | length | minLength | maxLength | enumeration | whiteSpace | pattern | assertion)*)) : simple type restriction + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId startState = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::StartEndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s1 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s2 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s3 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + + machine.addTransition(startState, XsdSchemaToken::Annotation, s1); + machine.addTransition(startState, XsdSchemaToken::SimpleType, s2); + machine.addTransition(startState, XsdSchemaToken::MinExclusive, s3); + machine.addTransition(startState, XsdSchemaToken::MinInclusive, s3); + machine.addTransition(startState, XsdSchemaToken::MaxExclusive, s3); + machine.addTransition(startState, XsdSchemaToken::MaxInclusive, s3); + machine.addTransition(startState, XsdSchemaToken::TotalDigits, s3); + machine.addTransition(startState, XsdSchemaToken::FractionDigits, s3); + machine.addTransition(startState, XsdSchemaToken::Length, s3); + machine.addTransition(startState, XsdSchemaToken::MinLength, s3); + machine.addTransition(startState, XsdSchemaToken::MaxLength, s3); + machine.addTransition(startState, XsdSchemaToken::Enumeration, s3); + machine.addTransition(startState, XsdSchemaToken::WhiteSpace, s3); + machine.addTransition(startState, XsdSchemaToken::Pattern, s3); + machine.addTransition(startState, XsdSchemaToken::Assertion, s3); + + machine.addTransition(s1, XsdSchemaToken::SimpleType, s2); + machine.addTransition(s1, XsdSchemaToken::MinExclusive, s3); + machine.addTransition(s1, XsdSchemaToken::MinInclusive, s3); + machine.addTransition(s1, XsdSchemaToken::MaxExclusive, s3); + machine.addTransition(s1, XsdSchemaToken::MaxInclusive, s3); + machine.addTransition(s1, XsdSchemaToken::TotalDigits, s3); + machine.addTransition(s1, XsdSchemaToken::FractionDigits, s3); + machine.addTransition(s1, XsdSchemaToken::Length, s3); + machine.addTransition(s1, XsdSchemaToken::MinLength, s3); + machine.addTransition(s1, XsdSchemaToken::MaxLength, s3); + machine.addTransition(s1, XsdSchemaToken::Enumeration, s3); + machine.addTransition(s1, XsdSchemaToken::WhiteSpace, s3); + machine.addTransition(s1, XsdSchemaToken::Pattern, s3); + machine.addTransition(s1, XsdSchemaToken::Assertion, s3); + + machine.addTransition(s2, XsdSchemaToken::MinExclusive, s3); + machine.addTransition(s2, XsdSchemaToken::MinInclusive, s3); + machine.addTransition(s2, XsdSchemaToken::MaxExclusive, s3); + machine.addTransition(s2, XsdSchemaToken::MaxInclusive, s3); + machine.addTransition(s2, XsdSchemaToken::TotalDigits, s3); + machine.addTransition(s2, XsdSchemaToken::FractionDigits, s3); + machine.addTransition(s2, XsdSchemaToken::Length, s3); + machine.addTransition(s2, XsdSchemaToken::MinLength, s3); + machine.addTransition(s2, XsdSchemaToken::MaxLength, s3); + machine.addTransition(s2, XsdSchemaToken::Enumeration, s3); + machine.addTransition(s2, XsdSchemaToken::WhiteSpace, s3); + machine.addTransition(s2, XsdSchemaToken::Pattern, s3); + machine.addTransition(s2, XsdSchemaToken::Assertion, s3); + + machine.addTransition(s3, XsdSchemaToken::MinExclusive, s3); + machine.addTransition(s3, XsdSchemaToken::MinInclusive, s3); + machine.addTransition(s3, XsdSchemaToken::MaxExclusive, s3); + machine.addTransition(s3, XsdSchemaToken::MaxInclusive, s3); + machine.addTransition(s3, XsdSchemaToken::TotalDigits, s3); + machine.addTransition(s3, XsdSchemaToken::FractionDigits, s3); + machine.addTransition(s3, XsdSchemaToken::Length, s3); + machine.addTransition(s3, XsdSchemaToken::MinLength, s3); + machine.addTransition(s3, XsdSchemaToken::MaxLength, s3); + machine.addTransition(s3, XsdSchemaToken::Enumeration, s3); + machine.addTransition(s3, XsdSchemaToken::WhiteSpace, s3); + machine.addTransition(s3, XsdSchemaToken::Pattern, s3); + machine.addTransition(s3, XsdSchemaToken::Assertion, s3); + + m_stateMachines.insert(XsdTagScope::SimpleRestriction, machine); + } + + { + XsdStateMachine<XsdSchemaToken::NodeName> machine(m_namePool); + + // setup state machine for (annotation?, simpleType?) : list + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId startState = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::StartEndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s1 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s2 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + + machine.addTransition(startState, XsdSchemaToken::Annotation, s1); + machine.addTransition(startState, XsdSchemaToken::SimpleType, s2); + + machine.addTransition(s1, XsdSchemaToken::SimpleType, s2); + + m_stateMachines.insert(XsdTagScope::List, machine); + } + + { + XsdStateMachine<XsdSchemaToken::NodeName> machine(m_namePool); + + // setup state machine for (annotation?, simpleType*) : union + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId startState = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::StartEndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s1 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s2 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + + machine.addTransition(startState, XsdSchemaToken::Annotation, s1); + machine.addTransition(startState, XsdSchemaToken::SimpleType, s2); + + machine.addTransition(s1, XsdSchemaToken::SimpleType, s2); + machine.addTransition(s2, XsdSchemaToken::SimpleType, s2); + + m_stateMachines.insert(XsdTagScope::Union, machine); + } + + { + XsdStateMachine<XsdSchemaToken::NodeName> machine(m_namePool); + + // setup state machine for ((include | import | redefine |i override | annotation)*, (defaultOpenContent, annotation*)?, (((simpleType | complexType | group | attributeGroup) | element | attribute | notation), annotation*)*) : schema + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId startState = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::StartEndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s1 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s2 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s3 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s4 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s5 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + + machine.addTransition(startState, XsdSchemaToken::Include, s1); + machine.addTransition(startState, XsdSchemaToken::Import, s1); + machine.addTransition(startState, XsdSchemaToken::Redefine, s1); + machine.addTransition(startState, XsdSchemaToken::Override, s1); + machine.addTransition(startState, XsdSchemaToken::Annotation, s1); + machine.addTransition(startState, XsdSchemaToken::DefaultOpenContent, s2); + machine.addTransition(startState, XsdSchemaToken::SimpleType, s4); + machine.addTransition(startState, XsdSchemaToken::ComplexType, s4); + machine.addTransition(startState, XsdSchemaToken::Group, s4); + machine.addTransition(startState, XsdSchemaToken::AttributeGroup, s4); + machine.addTransition(startState, XsdSchemaToken::Element, s4); + machine.addTransition(startState, XsdSchemaToken::Attribute, s4); + machine.addTransition(startState, XsdSchemaToken::Notation, s4); + + machine.addTransition(s1, XsdSchemaToken::Include, s1); + machine.addTransition(s1, XsdSchemaToken::Import, s1); + machine.addTransition(s1, XsdSchemaToken::Redefine, s1); + machine.addTransition(s1, XsdSchemaToken::Override, s1); + machine.addTransition(s1, XsdSchemaToken::Annotation, s1); + machine.addTransition(s1, XsdSchemaToken::DefaultOpenContent, s2); + machine.addTransition(s1, XsdSchemaToken::SimpleType, s4); + machine.addTransition(s1, XsdSchemaToken::ComplexType, s4); + machine.addTransition(s1, XsdSchemaToken::Group, s4); + machine.addTransition(s1, XsdSchemaToken::AttributeGroup, s4); + machine.addTransition(s1, XsdSchemaToken::Element, s4); + machine.addTransition(s1, XsdSchemaToken::Attribute, s4); + machine.addTransition(s1, XsdSchemaToken::Notation, s4); + + machine.addTransition(s2, XsdSchemaToken::Annotation, s3); + machine.addTransition(s2, XsdSchemaToken::SimpleType, s4); + machine.addTransition(s2, XsdSchemaToken::ComplexType, s4); + machine.addTransition(s2, XsdSchemaToken::Group, s4); + machine.addTransition(s2, XsdSchemaToken::AttributeGroup, s4); + machine.addTransition(s2, XsdSchemaToken::Element, s4); + machine.addTransition(s2, XsdSchemaToken::Attribute, s4); + machine.addTransition(s2, XsdSchemaToken::Notation, s4); + + machine.addTransition(s3, XsdSchemaToken::SimpleType, s4); + machine.addTransition(s3, XsdSchemaToken::ComplexType, s4); + machine.addTransition(s3, XsdSchemaToken::Group, s4); + machine.addTransition(s3, XsdSchemaToken::AttributeGroup, s4); + machine.addTransition(s3, XsdSchemaToken::Element, s4); + machine.addTransition(s3, XsdSchemaToken::Attribute, s4); + machine.addTransition(s3, XsdSchemaToken::Notation, s4); + + machine.addTransition(s4, XsdSchemaToken::SimpleType, s4); + machine.addTransition(s4, XsdSchemaToken::ComplexType, s4); + machine.addTransition(s4, XsdSchemaToken::Group, s4); + machine.addTransition(s4, XsdSchemaToken::AttributeGroup, s4); + machine.addTransition(s4, XsdSchemaToken::Element, s4); + machine.addTransition(s4, XsdSchemaToken::Attribute, s4); + machine.addTransition(s4, XsdSchemaToken::Notation, s4); + machine.addTransition(s4, XsdSchemaToken::Annotation, s5); + + machine.addTransition(s5, XsdSchemaToken::SimpleType, s4); + machine.addTransition(s5, XsdSchemaToken::ComplexType, s4); + machine.addTransition(s5, XsdSchemaToken::Group, s4); + machine.addTransition(s5, XsdSchemaToken::AttributeGroup, s4); + machine.addTransition(s5, XsdSchemaToken::Element, s4); + machine.addTransition(s5, XsdSchemaToken::Attribute, s4); + machine.addTransition(s5, XsdSchemaToken::Notation, s4); + machine.addTransition(s5, XsdSchemaToken::Annotation, s5); + + m_stateMachines.insert(XsdTagScope::Schema, machine); + } + + { + XsdStateMachine<XsdSchemaToken::NodeName> machine(m_namePool); + + // setup state machine for (annotation?, any) : defaultOpenContent + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId startState = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::StartEndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s1 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::InternalState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s2 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + + machine.addTransition(startState, XsdSchemaToken::Annotation, s1); + machine.addTransition(startState, XsdSchemaToken::Any, s2); + + machine.addTransition(s1, XsdSchemaToken::Any, s2); + + m_stateMachines.insert(XsdTagScope::DefaultOpenContent, machine); + } + + { + XsdStateMachine<XsdSchemaToken::NodeName> machine(m_namePool); + + // setup state machine for (annotation | (simpleType | complexType | group | attributeGroup))* : redefine + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId startState = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::StartEndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s1 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + + machine.addTransition(startState, XsdSchemaToken::Annotation, s1); + machine.addTransition(startState, XsdSchemaToken::SimpleType, s1); + machine.addTransition(startState, XsdSchemaToken::ComplexType, s1); + machine.addTransition(startState, XsdSchemaToken::Group, s1); + machine.addTransition(startState, XsdSchemaToken::AttributeGroup, s1); + + machine.addTransition(s1, XsdSchemaToken::Annotation, s1); + machine.addTransition(s1, XsdSchemaToken::SimpleType, s1); + machine.addTransition(s1, XsdSchemaToken::ComplexType, s1); + machine.addTransition(s1, XsdSchemaToken::Group, s1); + machine.addTransition(s1, XsdSchemaToken::AttributeGroup, s1); + + m_stateMachines.insert(XsdTagScope::Redefine, machine); + } + + { + XsdStateMachine<XsdSchemaToken::NodeName> machine(m_namePool); + + // setup state machine for (annotation | (simpleType | complexType | group | attributeGroup | element | attribute | notation))* : override + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId startState = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::StartEndState); + const XsdStateMachine<XsdSchemaToken::NodeName>::StateId s1 = machine.addState(XsdStateMachine<XsdSchemaToken::NodeName>::EndState); + + machine.addTransition(startState, XsdSchemaToken::Annotation, s1); + machine.addTransition(startState, XsdSchemaToken::SimpleType, s1); + machine.addTransition(startState, XsdSchemaToken::ComplexType, s1); + machine.addTransition(startState, XsdSchemaToken::Group, s1); + machine.addTransition(startState, XsdSchemaToken::AttributeGroup, s1); + machine.addTransition(startState, XsdSchemaToken::Element, s1); + machine.addTransition(startState, XsdSchemaToken::Attribute, s1); + machine.addTransition(startState, XsdSchemaToken::Notation, s1); + + machine.addTransition(s1, XsdSchemaToken::Annotation, s1); + machine.addTransition(s1, XsdSchemaToken::SimpleType, s1); + machine.addTransition(s1, XsdSchemaToken::ComplexType, s1); + machine.addTransition(s1, XsdSchemaToken::Group, s1); + machine.addTransition(s1, XsdSchemaToken::AttributeGroup, s1); + machine.addTransition(s1, XsdSchemaToken::Element, s1); + machine.addTransition(s1, XsdSchemaToken::Attribute, s1); + machine.addTransition(s1, XsdSchemaToken::Notation, s1); + + m_stateMachines.insert(XsdTagScope::Override, machine); + } +} + +void XsdSchemaParser::setupBuiltinTypeNames() +{ + m_builtinTypeNames.reserve(48); + + m_builtinTypeNames.insert(BuiltinTypes::xsAnyType->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsAnySimpleType->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsUntyped->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsAnyAtomicType->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsUntypedAtomic->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsDateTime->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsDate->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsTime->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsDuration->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsYearMonthDuration->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsDayTimeDuration->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsFloat->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsDouble->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsInteger->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsDecimal->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsNonPositiveInteger->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsNegativeInteger->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsLong->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsInt->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsShort->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsByte->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsNonNegativeInteger->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsUnsignedLong->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsUnsignedInt->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsUnsignedShort->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsUnsignedByte->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsPositiveInteger->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsGYearMonth->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsGYear->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsGMonthDay->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsGDay->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsGMonth->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsBoolean->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsBase64Binary->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsHexBinary->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsAnyURI->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsQName->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsString->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsNormalizedString->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsToken->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsLanguage->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsNMTOKEN->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsName->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsNCName->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsID->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsIDREF->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsENTITY->name(m_namePool)); + m_builtinTypeNames.insert(BuiltinTypes::xsNOTATION->name(m_namePool)); +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdschemaparsercontext.cpp b/src/xmlpatterns/schema/qxsdschemaparsercontext.cpp new file mode 100644 index 0000000..0f711d8 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdschemaparsercontext.cpp @@ -0,0 +1,603 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdschemaparsercontext_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +XsdSchemaParserContext::XsdSchemaParserContext(const NamePool::Ptr &namePool, const XsdSchemaContext::Ptr &context) + : m_namePool(namePool) + , m_schema(new XsdSchema(m_namePool)) + , m_checker(new XsdSchemaChecker(context, this)) + , m_resolver(new XsdSchemaResolver(context, this)) + , m_elementDescriptions(setupElementDescriptions()) +{ +} + +NamePool::Ptr XsdSchemaParserContext::namePool() const +{ + return m_namePool; +} + +XsdSchemaResolver::Ptr XsdSchemaParserContext::resolver() const +{ + return m_resolver; +} + +XsdSchemaChecker::Ptr XsdSchemaParserContext::checker() const +{ + return m_checker; +} + +XsdSchema::Ptr XsdSchemaParserContext::schema() const +{ + return m_schema; +} + +ElementDescription<XsdSchemaToken, XsdTagScope::Type>::Hash XsdSchemaParserContext::elementDescriptions() const +{ + return m_elementDescriptions; +} + +QXmlName XsdSchemaParserContext::createAnonymousName(const QString &targetNamespace) const +{ + m_anonymousNameCounter.ref(); + + const QString name = QString::fromLatin1("__AnonymousClass_%1").arg((int)m_anonymousNameCounter); + + return m_namePool->allocateQName(targetNamespace, name); +} + +ElementDescription<XsdSchemaToken, XsdTagScope::Type>::Hash XsdSchemaParserContext::setupElementDescriptions() +{ + enum + { + ReservedForElements = 60 + }; + + ElementDescription<XsdSchemaToken, XsdTagScope::Type>::Hash elementDescriptions; + elementDescriptions.reserve(ReservedForElements); + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::Schema]; + description.optionalAttributes.reserve(10); + //description.tagToken = XsdSchemaToken::Schema; + description.optionalAttributes.insert(XsdSchemaToken::AttributeFormDefault); + description.optionalAttributes.insert(XsdSchemaToken::BlockDefault); + description.optionalAttributes.insert(XsdSchemaToken::DefaultAttributes); + description.optionalAttributes.insert(XsdSchemaToken::XPathDefaultNamespace); + description.optionalAttributes.insert(XsdSchemaToken::ElementFormDefault); + description.optionalAttributes.insert(XsdSchemaToken::FinalDefault); + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.optionalAttributes.insert(XsdSchemaToken::TargetNamespace); + description.optionalAttributes.insert(XsdSchemaToken::Version); + description.optionalAttributes.insert(XsdSchemaToken::XmlLanguage); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::Include]; + //description.tagToken = XsdSchemaToken::Include; + description.requiredAttributes.insert(XsdSchemaToken::SchemaLocation); + description.optionalAttributes.insert(XsdSchemaToken::Id); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::Import]; + //description.tagToken = XsdSchemaToken::Import; + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.optionalAttributes.insert(XsdSchemaToken::Namespace); + description.optionalAttributes.insert(XsdSchemaToken::SchemaLocation); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::Redefine]; + //description.tagToken = XsdSchemaToken::Redefine; + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.requiredAttributes.insert(XsdSchemaToken::SchemaLocation); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::Override]; + //description.tagToken = XsdSchemaToken::Override; + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.requiredAttributes.insert(XsdSchemaToken::SchemaLocation); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::Annotation]; + //description.tagToken = XsdSchemaToken::Annotation; + description.optionalAttributes.insert(XsdSchemaToken::Id); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::AppInfo]; + //description.tagToken = XsdSchemaToken::Appinfo; + description.optionalAttributes.insert(XsdSchemaToken::Source); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::Documentation]; + //description.tagToken = XsdSchemaToken::Documentation; + description.optionalAttributes.insert(XsdSchemaToken::Source); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::GlobalSimpleType]; + //description.tagToken = XsdSchemaToken::SimpleType; + description.optionalAttributes.insert(XsdSchemaToken::Final); + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.requiredAttributes.insert(XsdSchemaToken::Name); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::LocalSimpleType]; + //description.tagToken = XsdSchemaToken::SimpleType; + description.optionalAttributes.insert(XsdSchemaToken::Id); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::SimpleRestriction]; + //description.tagToken = XsdSchemaToken::Restriction; + description.optionalAttributes.insert(XsdSchemaToken::Base); + description.optionalAttributes.insert(XsdSchemaToken::Id); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::List]; + //description.tagToken = XsdSchemaToken::List; + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.optionalAttributes.insert(XsdSchemaToken::ItemType); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::Union]; + //description.tagToken = XsdSchemaToken::Union; + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.optionalAttributes.insert(XsdSchemaToken::MemberTypes); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::MinExclusiveFacet]; + //description.tagToken = XsdSchemaToken::MinExclusive; + description.optionalAttributes.insert(XsdSchemaToken::Fixed); + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.requiredAttributes.insert(XsdSchemaToken::Value); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::MinInclusiveFacet]; + //description.tagToken = XsdSchemaToken::MinInclusive; + description.optionalAttributes.insert(XsdSchemaToken::Fixed); + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.requiredAttributes.insert(XsdSchemaToken::Value); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::MaxExclusiveFacet]; + //description.tagToken = XsdSchemaToken::MaxExclusive; + description.optionalAttributes.insert(XsdSchemaToken::Fixed); + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.requiredAttributes.insert(XsdSchemaToken::Value); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::MaxInclusiveFacet]; + //description.tagToken = XsdSchemaToken::MaxInclusive; + description.optionalAttributes.insert(XsdSchemaToken::Fixed); + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.requiredAttributes.insert(XsdSchemaToken::Value); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::TotalDigitsFacet]; + //description.tagToken = XsdSchemaToken::TotalDigits; + description.optionalAttributes.insert(XsdSchemaToken::Fixed); + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.requiredAttributes.insert(XsdSchemaToken::Value); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::FractionDigitsFacet]; + //description.tagToken = XsdSchemaToken::FractionDigits; + description.optionalAttributes.insert(XsdSchemaToken::Fixed); + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.requiredAttributes.insert(XsdSchemaToken::Value); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::LengthFacet]; + //description.tagToken = XsdSchemaToken::Length; + description.optionalAttributes.insert(XsdSchemaToken::Fixed); + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.requiredAttributes.insert(XsdSchemaToken::Value); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::MinLengthFacet]; + //description.tagToken = XsdSchemaToken::MinLength; + description.optionalAttributes.insert(XsdSchemaToken::Fixed); + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.requiredAttributes.insert(XsdSchemaToken::Value); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::MaxLengthFacet]; + //description.tagToken = XsdSchemaToken::MaxLength; + description.optionalAttributes.insert(XsdSchemaToken::Fixed); + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.requiredAttributes.insert(XsdSchemaToken::Value); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::EnumerationFacet]; + //description.tagToken = XsdSchemaToken::Enumeration; + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.requiredAttributes.insert(XsdSchemaToken::Value); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::WhiteSpaceFacet]; + //description.tagToken = XsdSchemaToken::WhiteSpace; + description.optionalAttributes.insert(XsdSchemaToken::Fixed); + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.requiredAttributes.insert(XsdSchemaToken::Value); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::PatternFacet]; + //description.tagToken = XsdSchemaToken::Pattern; + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.requiredAttributes.insert(XsdSchemaToken::Value); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::GlobalComplexType]; + description.optionalAttributes.reserve(7); + //description.tagToken = XsdSchemaToken::ComplexType; + description.optionalAttributes.insert(XsdSchemaToken::Abstract); + description.optionalAttributes.insert(XsdSchemaToken::Block); + description.optionalAttributes.insert(XsdSchemaToken::DefaultAttributesApply); + description.optionalAttributes.insert(XsdSchemaToken::Final); + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.optionalAttributes.insert(XsdSchemaToken::Mixed); + description.requiredAttributes.insert(XsdSchemaToken::Name); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::LocalComplexType]; + //description.tagToken = XsdSchemaToken::ComplexType; + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.optionalAttributes.insert(XsdSchemaToken::Mixed); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::SimpleContent]; + //description.tagToken = XsdSchemaToken::SimpleContent; + description.optionalAttributes.insert(XsdSchemaToken::Id); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::SimpleContentRestriction]; + //description.tagToken = XsdSchemaToken::Restriction; + description.requiredAttributes.insert(XsdSchemaToken::Base); + description.optionalAttributes.insert(XsdSchemaToken::Id); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::SimpleContentExtension]; + //description.tagToken = XsdSchemaToken::Extension; + description.requiredAttributes.insert(XsdSchemaToken::Base); + description.optionalAttributes.insert(XsdSchemaToken::Id); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::ComplexContent]; + //description.tagToken = XsdSchemaToken::ComplexContent; + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.optionalAttributes.insert(XsdSchemaToken::Mixed); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::ComplexContentRestriction]; + //description.tagToken = XsdSchemaToken::Restriction; + description.requiredAttributes.insert(XsdSchemaToken::Base); + description.optionalAttributes.insert(XsdSchemaToken::Id); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::ComplexContentExtension]; + //description.tagToken = XsdSchemaToken::Extension; + description.requiredAttributes.insert(XsdSchemaToken::Base); + description.optionalAttributes.insert(XsdSchemaToken::Id); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::NamedGroup]; + //description.tagToken = XsdSchemaToken::Group; + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.requiredAttributes.insert(XsdSchemaToken::Name); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::ReferredGroup]; + description.optionalAttributes.reserve(4); + //description.tagToken = XsdSchemaToken::Group; + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.optionalAttributes.insert(XsdSchemaToken::MaxOccurs); + description.optionalAttributes.insert(XsdSchemaToken::MinOccurs); + description.requiredAttributes.insert(XsdSchemaToken::Ref); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::All]; + //description.tagToken = XsdSchemaToken::All; + description.optionalAttributes.insert(XsdSchemaToken::Id); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::LocalAll]; + //description.tagToken = XsdSchemaToken::All; + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.optionalAttributes.insert(XsdSchemaToken::MaxOccurs); + description.optionalAttributes.insert(XsdSchemaToken::MinOccurs); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::Choice]; + //description.tagToken = XsdSchemaToken::Choice; + description.optionalAttributes.insert(XsdSchemaToken::Id); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::LocalChoice]; + //description.tagToken = XsdSchemaToken::Choice; + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.optionalAttributes.insert(XsdSchemaToken::MaxOccurs); + description.optionalAttributes.insert(XsdSchemaToken::MinOccurs); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::Sequence]; + //description.tagToken = XsdSchemaToken::Sequence; + description.optionalAttributes.insert(XsdSchemaToken::Id); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::LocalSequence]; + //description.tagToken = XsdSchemaToken::Sequence; + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.optionalAttributes.insert(XsdSchemaToken::MaxOccurs); + description.optionalAttributes.insert(XsdSchemaToken::MinOccurs); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::GlobalAttribute]; + description.optionalAttributes.reserve(5); + //description.tagToken = XsdSchemaToken::Attribute; + description.optionalAttributes.insert(XsdSchemaToken::Default); + description.optionalAttributes.insert(XsdSchemaToken::Fixed); + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.requiredAttributes.insert(XsdSchemaToken::Name); + description.optionalAttributes.insert(XsdSchemaToken::Type); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::LocalAttribute]; + description.optionalAttributes.reserve(8); + //description.tagToken = XsdSchemaToken::Attribute; + description.optionalAttributes.insert(XsdSchemaToken::Default); + description.optionalAttributes.insert(XsdSchemaToken::Fixed); + description.optionalAttributes.insert(XsdSchemaToken::Form); + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.optionalAttributes.insert(XsdSchemaToken::Name); + description.optionalAttributes.insert(XsdSchemaToken::Ref); + description.optionalAttributes.insert(XsdSchemaToken::Type); + description.optionalAttributes.insert(XsdSchemaToken::Use); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::NamedAttributeGroup]; + //description.tagToken = XsdSchemaToken::AttributeGroup; + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.requiredAttributes.insert(XsdSchemaToken::Name); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::ReferredAttributeGroup]; + //description.tagToken = XsdSchemaToken::AttributeGroup; + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.requiredAttributes.insert(XsdSchemaToken::Ref); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::LocalElement]; + description.optionalAttributes.reserve(11); + //description.tagToken = XsdSchemaToken::Element; + description.optionalAttributes.insert(XsdSchemaToken::Block); + description.optionalAttributes.insert(XsdSchemaToken::Default); + description.optionalAttributes.insert(XsdSchemaToken::Fixed); + description.optionalAttributes.insert(XsdSchemaToken::Form); + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.optionalAttributes.insert(XsdSchemaToken::MinOccurs); + description.optionalAttributes.insert(XsdSchemaToken::MaxOccurs); + description.optionalAttributes.insert(XsdSchemaToken::Name); + description.optionalAttributes.insert(XsdSchemaToken::Nillable); + description.optionalAttributes.insert(XsdSchemaToken::Ref); + description.optionalAttributes.insert(XsdSchemaToken::Type); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::GlobalElement]; + description.optionalAttributes.reserve(10); + //description.tagToken = XsdSchemaToken::Element; + description.optionalAttributes.insert(XsdSchemaToken::Abstract); + description.optionalAttributes.insert(XsdSchemaToken::Block); + description.optionalAttributes.insert(XsdSchemaToken::Default); + description.optionalAttributes.insert(XsdSchemaToken::Final); + description.optionalAttributes.insert(XsdSchemaToken::Fixed); + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.requiredAttributes.insert(XsdSchemaToken::Name); + description.optionalAttributes.insert(XsdSchemaToken::Nillable); + description.optionalAttributes.insert(XsdSchemaToken::SubstitutionGroup); + description.optionalAttributes.insert(XsdSchemaToken::Type); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::Unique]; + //description.tagToken = XsdSchemaToken::Unique; + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.requiredAttributes.insert(XsdSchemaToken::Name); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::Key]; + //description.tagToken = XsdSchemaToken::Key; + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.requiredAttributes.insert(XsdSchemaToken::Name); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::KeyRef]; + //description.tagToken = XsdSchemaToken::Keyref; + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.requiredAttributes.insert(XsdSchemaToken::Name); + description.requiredAttributes.insert(XsdSchemaToken::Refer); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::Selector]; + //description.tagToken = XsdSchemaToken::Selector; + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.requiredAttributes.insert(XsdSchemaToken::Xpath); + description.optionalAttributes.insert(XsdSchemaToken::XPathDefaultNamespace); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::Field]; + //description.tagToken = XsdSchemaToken::Field; + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.requiredAttributes.insert(XsdSchemaToken::Xpath); + description.optionalAttributes.insert(XsdSchemaToken::XPathDefaultNamespace); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::Notation]; + description.optionalAttributes.reserve(4); + //description.tagToken = XsdSchemaToken::Notation; + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.requiredAttributes.insert(XsdSchemaToken::Name); + description.optionalAttributes.insert(XsdSchemaToken::Public); + description.optionalAttributes.insert(XsdSchemaToken::System); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::Any]; + description.optionalAttributes.reserve(7); + //description.tagToken = XsdSchemaToken::Any; + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.optionalAttributes.insert(XsdSchemaToken::MaxOccurs); + description.optionalAttributes.insert(XsdSchemaToken::MinOccurs); + description.optionalAttributes.insert(XsdSchemaToken::Namespace); + description.optionalAttributes.insert(XsdSchemaToken::NotNamespace); + description.optionalAttributes.insert(XsdSchemaToken::NotQName); + description.optionalAttributes.insert(XsdSchemaToken::ProcessContents); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::AnyAttribute]; + description.optionalAttributes.reserve(5); + //description.tagToken = XsdSchemaToken::AnyAttribute; + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.optionalAttributes.insert(XsdSchemaToken::Namespace); + description.optionalAttributes.insert(XsdSchemaToken::NotNamespace); + description.optionalAttributes.insert(XsdSchemaToken::NotQName); + description.optionalAttributes.insert(XsdSchemaToken::ProcessContents); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::Alternative]; + //description.tagToken = XsdSchemaToken::Alternative; + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.optionalAttributes.insert(XsdSchemaToken::Test); + description.optionalAttributes.insert(XsdSchemaToken::Type); + description.optionalAttributes.insert(XsdSchemaToken::XPathDefaultNamespace); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::OpenContent]; + //description.tagToken = XsdSchemaToken::OpenContent; + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.optionalAttributes.insert(XsdSchemaToken::Mode); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::DefaultOpenContent]; + //description.tagToken = XsdSchemaToken::DefaultOpenContent; + description.optionalAttributes.insert(XsdSchemaToken::AppliesToEmpty); + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.optionalAttributes.insert(XsdSchemaToken::Mode); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::Assert]; + //description.tagToken = XsdSchemaToken::Assert; + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.requiredAttributes.insert(XsdSchemaToken::Test); + description.optionalAttributes.insert(XsdSchemaToken::XPathDefaultNamespace); + } + + { + ElementDescription<XsdSchemaToken, XsdTagScope::Type> &description = elementDescriptions[XsdTagScope::Assertion]; + //description.tagToken = XsdSchemaToken::Assertion; + description.optionalAttributes.insert(XsdSchemaToken::Id); + description.requiredAttributes.insert(XsdSchemaToken::Test); + description.optionalAttributes.insert(XsdSchemaToken::XPathDefaultNamespace); + } + + Q_ASSERT_X(elementDescriptions.count() == ReservedForElements, Q_FUNC_INFO, + qPrintable(QString::fromLatin1("Expected is %1, actual is %2.").arg(ReservedForElements).arg(elementDescriptions.count()))); + + return elementDescriptions; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdschemaparsercontext_p.h b/src/xmlpatterns/schema/qxsdschemaparsercontext_p.h new file mode 100644 index 0000000..572d5e3 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdschemaparsercontext_p.h @@ -0,0 +1,231 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdSchemaParserContext_H +#define Patternist_XsdSchemaParserContext_H + +#include "qmaintainingreader_p.h" // for definition of ElementDescription +#include "qxsdschematoken_p.h" +#include "qxsdschema_p.h" +#include "qxsdschemachecker_p.h" +#include "qxsdschemacontext_p.h" +#include "qxsdschemaresolver_p.h" + +#include <QtCore/QSharedData> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short A namespace class that contains identifiers for the different + * scopes a tag from the xml schema spec can appear in. + */ + class XsdTagScope + { + public: + enum Type + { + Schema, + Include, + Import, + Redefine, + Annotation, + AppInfo, + Documentation, + GlobalSimpleType, + LocalSimpleType, + SimpleRestriction, + List, + Union, + MinExclusiveFacet, + MinInclusiveFacet, + MaxExclusiveFacet, + MaxInclusiveFacet, + TotalDigitsFacet, + FractionDigitsFacet, + LengthFacet, + MinLengthFacet, + MaxLengthFacet, + EnumerationFacet, + WhiteSpaceFacet, + PatternFacet, + GlobalComplexType, + LocalComplexType, + SimpleContent, + SimpleContentRestriction, + SimpleContentExtension, + ComplexContent, + ComplexContentRestriction, + ComplexContentExtension, + NamedGroup, + ReferredGroup, + All, + LocalAll, + Choice, + LocalChoice, + Sequence, + LocalSequence, + GlobalAttribute, + LocalAttribute, + NamedAttributeGroup, + ReferredAttributeGroup, + GlobalElement, + LocalElement, + Unique, + Key, + KeyRef, + Selector, + Field, + Notation, + Any, + AnyAttribute, + Alternative, + Assert, + Assertion, + OpenContent, + DefaultOpenContent, + Override + }; + }; + + /** + * A hash that keeps the mapping between the single components that can appear + * in a schema document (e.g. elements, attributes, type definitions) and their + * source locations inside the document. + */ + typedef QHash<NamedSchemaComponent::Ptr, QSourceLocation> ComponentLocationHash; + + /** + * @short A context for schema parsing. + * + * This class provides a context for all components that are + * nedded for parsing and compiling the XML schema. + * + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdSchemaParserContext : public QSharedData + { + public: + /** + * A smart pointer wrapping XsdSchemaParserContext instances. + */ + typedef QExplicitlySharedDataPointer<XsdSchemaParserContext> Ptr; + + /** + * Creates a new schema parser context object. + * + * @param namePool The name pool where all names of the schema will be stored in. + * @param context The schema context to use for error reporting etc. + */ + XsdSchemaParserContext(const NamePool::Ptr &namePool, const XsdSchemaContext::Ptr &context); + + /** + * Returns the name pool of the schema parser context. + */ + NamePool::Ptr namePool() const; + + /** + * Returns the schema resolver of the schema context. + */ + XsdSchemaResolver::Ptr resolver() const; + + /** + * Returns the schema resolver of the schema context. + */ + XsdSchemaChecker::Ptr checker() const; + + /** + * Returns the schema object of the schema context. + */ + XsdSchema::Ptr schema() const; + + /** + * Returns the element descriptions for the schema parser. + * + * The element descriptions are a fast lookup table for + * verifying whether certain attributes are allowed for + * a given element type. + */ + ElementDescription<XsdSchemaToken, XsdTagScope::Type>::Hash elementDescriptions() const; + + /** + * Returns an unique name that is used by the schema parser + * for anonymous types. + * + * @param targetNamespace The namespace of the name. + */ + QXmlName createAnonymousName(const QString &targetNamespace) const; + + private: + /** + * Fills the element description hash with the required and prohibited + * attributes. + */ + static ElementDescription<XsdSchemaToken, XsdTagScope::Type>::Hash setupElementDescriptions(); + + NamePool::Ptr m_namePool; + XsdSchema::Ptr m_schema; + XsdSchemaChecker::Ptr m_checker; + XsdSchemaResolver::Ptr m_resolver; + const ElementDescription<XsdSchemaToken, XsdTagScope::Type>::Hash m_elementDescriptions; + mutable QAtomicInt m_anonymousNameCounter; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdschemaresolver.cpp b/src/xmlpatterns/schema/qxsdschemaresolver.cpp new file mode 100644 index 0000000..9290b6e --- /dev/null +++ b/src/xmlpatterns/schema/qxsdschemaresolver.cpp @@ -0,0 +1,1736 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdschemaresolver_p.h" + +#include "qderivedinteger_p.h" +#include "qderivedstring_p.h" +#include "qqnamevalue_p.h" +#include "qxsdattributereference_p.h" +#include "qxsdparticlechecker_p.h" +#include "qxsdreference_p.h" +#include "qxsdschemacontext_p.h" +#include "qxsdschemahelper_p.h" +#include "qxsdschemaparsercontext_p.h" +#include "qxsdschematypesfactory_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +XsdSchemaResolver::XsdSchemaResolver(const QExplicitlySharedDataPointer<XsdSchemaContext> &context, const XsdSchemaParserContext *parserContext) + : m_context(context) + , m_checker(parserContext->checker()) + , m_namePool(parserContext->namePool()) + , m_schema(parserContext->schema()) +{ + m_keyReferences.reserve(20); + m_simpleRestrictionBases.reserve(20); + m_simpleListTypes.reserve(20); + m_simpleUnionTypes.reserve(20); + m_elementTypes.reserve(20); + m_complexBaseTypes.reserve(20); + m_attributeTypes.reserve(20); + m_alternativeTypes.reserve(20); + m_alternativeTypeElements.reserve(20); + m_substitutionGroupAffiliations.reserve(20); + + m_predefinedSchemaTypes = m_context->schemaTypeFactory()->types().values(); +} + +XsdSchemaResolver::~XsdSchemaResolver() +{ +} + +void XsdSchemaResolver::resolve() +{ + m_checker->addComponentLocationHash(m_componentLocationHash); + + // resolve the base types for all types + resolveSimpleRestrictionBaseTypes(); + resolveComplexBaseTypes(); + + // do the basic checks which depend on having a base type available + m_checker->basicCheck(); + + // resolve further types that only map a type name to a type object + resolveSimpleListType(); + resolveSimpleUnionTypes(); + resolveElementTypes(); + resolveAttributeTypes(); + resolveAlternativeTypes(); + + // resolve objects that do not need information about inheritance + resolveKeyReferences(); + resolveSubstitutionGroupAffiliations(); + + // resolve objects that do need information about inheritance + resolveSimpleRestrictions(); + resolveSimpleContentComplexTypes(); + + // resolve objects which replace place holders + resolveTermReferences(); + resolveAttributeTermReferences(); + + // resolve additional objects that do need information about inheritance + resolveAttributeInheritance(); + resolveComplexContentComplexTypes(); + resolveSubstitutionGroups(); + + resolveEnumerationFacetValues(); + + checkRedefinedGroups(); + checkRedefinedAttributeGroups(); + + // check the constraining facets before we resolve them + m_checker->checkConstrainingFacets(); + + // add it again, as we may have added new components in the meantime + m_checker->addComponentLocationHash(m_componentLocationHash); + + m_checker->check(); +} + +void XsdSchemaResolver::addKeyReference(const XsdElement::Ptr &element, const XsdIdentityConstraint::Ptr &keyRef, const QXmlName &reference, const QSourceLocation &location) +{ + KeyReference item; + item.element = element; + item.keyRef = keyRef; + item.reference = reference; + item.location = location; + + m_keyReferences.append(item); +} + +void XsdSchemaResolver::addSimpleRestrictionBase(const XsdSimpleType::Ptr &simpleType, const QXmlName &baseName, const QSourceLocation &location) +{ + SimpleRestrictionBase item; + item.simpleType = simpleType; + item.baseName = baseName; + item.location = location; + + m_simpleRestrictionBases.append(item); +} + +void XsdSchemaResolver::removeSimpleRestrictionBase(const XsdSimpleType::Ptr &type) +{ + for (int i = 0; i < m_simpleRestrictionBases.count(); ++i) { + if (m_simpleRestrictionBases.at(i).simpleType == type) { + m_simpleRestrictionBases.remove(i); + break; + } + } +} + +void XsdSchemaResolver::addSimpleListType(const XsdSimpleType::Ptr &simpleType, const QXmlName &typeName, const QSourceLocation &location) +{ + SimpleListType item; + item.simpleType = simpleType; + item.typeName = typeName; + item.location = location; + + m_simpleListTypes.append(item); +} + +void XsdSchemaResolver::addSimpleUnionTypes(const XsdSimpleType::Ptr &simpleType, const QList<QXmlName> &typeNames, const QSourceLocation &location) +{ + SimpleUnionType item; + item.simpleType = simpleType; + item.typeNames = typeNames; + item.location = location; + + m_simpleUnionTypes.append(item); +} + +void XsdSchemaResolver::addElementType(const XsdElement::Ptr &element, const QXmlName &typeName, const QSourceLocation &location) +{ + ElementType item; + item.element = element; + item.typeName = typeName; + item.location = location; + + m_elementTypes.append(item); +} + +void XsdSchemaResolver::addComplexBaseType(const XsdComplexType::Ptr &complexType, const QXmlName &baseName, const QSourceLocation &location, const XsdFacet::Hash &facets) +{ + ComplexBaseType item; + item.complexType = complexType; + item.baseName = baseName; + item.location = location; + item.facets = facets; + + m_complexBaseTypes.append(item); +} + +void XsdSchemaResolver::removeComplexBaseType(const XsdComplexType::Ptr &type) +{ + for (int i = 0; i < m_complexBaseTypes.count(); ++i) { + if (m_complexBaseTypes.at(i).complexType == type) { + m_complexBaseTypes.remove(i); + break; + } + } +} + +void XsdSchemaResolver::addComplexContentType(const XsdComplexType::Ptr &complexType, const XsdParticle::Ptr &content, bool mixed) +{ + ComplexContentType item; + item.complexType = complexType; + item.explicitContent = content; + item.effectiveMixed = mixed; + m_complexContentTypes.append(item); +} + +void XsdSchemaResolver::addAttributeType(const XsdAttribute::Ptr &attribute, const QXmlName &typeName, const QSourceLocation &location) +{ + AttributeType item; + item.attribute = attribute; + item.typeName = typeName; + item.location = location; + + m_attributeTypes.append(item); +} + +void XsdSchemaResolver::addAlternativeType(const XsdAlternative::Ptr &alternative, const QXmlName &typeName, const QSourceLocation &location) +{ + AlternativeType item; + item.alternative = alternative; + item.typeName = typeName; + item.location = location; + + m_alternativeTypes.append(item); +} + +void XsdSchemaResolver::addAlternativeType(const XsdAlternative::Ptr &alternative, const XsdElement::Ptr &element) +{ + AlternativeTypeElement item; + item.alternative = alternative; + item.element = element; + + m_alternativeTypeElements.append(item); +} + +void XsdSchemaResolver::addSubstitutionGroupAffiliation(const XsdElement::Ptr &element, const QList<QXmlName> &elementNames, const QSourceLocation &location) +{ + SubstitutionGroupAffiliation item; + item.element = element; + item.elementNames = elementNames; + item.location = location; + + m_substitutionGroupAffiliations.append(item); +} + +void XsdSchemaResolver::addSubstitutionGroupType(const XsdElement::Ptr &element) +{ + m_substitutionGroupTypes.append(element); +} + +void XsdSchemaResolver::addComponentLocationHash(const ComponentLocationHash &hash) +{ + m_componentLocationHash.unite(hash); +} + +void XsdSchemaResolver::addEnumerationFacetValue(const AtomicValue::Ptr &facetValue, const NamespaceSupport &namespaceSupport) +{ + m_enumerationFacetValues.insert(facetValue, namespaceSupport); +} + +void XsdSchemaResolver::addRedefinedGroups(const XsdModelGroup::Ptr &redefinedGroup, const XsdModelGroup::Ptr &group) +{ + RedefinedGroups item; + item.redefinedGroup = redefinedGroup; + item.group = group; + + m_redefinedGroups.append(item); +} + +void XsdSchemaResolver::addRedefinedAttributeGroups(const XsdAttributeGroup::Ptr &redefinedGroup, const XsdAttributeGroup::Ptr &group) +{ + RedefinedAttributeGroups item; + item.redefinedGroup = redefinedGroup; + item.group = group; + + m_redefinedAttributeGroups.append(item); +} + +void XsdSchemaResolver::addAllGroupCheck(const XsdReference::Ptr &reference) +{ + m_allGroups.insert(reference); +} + +void XsdSchemaResolver::copyDataTo(const XsdSchemaResolver::Ptr &other) const +{ + other->m_keyReferences << m_keyReferences; + other->m_simpleRestrictionBases << m_simpleRestrictionBases; + other->m_simpleListTypes << m_simpleListTypes; + other->m_simpleUnionTypes << m_simpleUnionTypes; + other->m_elementTypes << m_elementTypes; + other->m_complexBaseTypes << m_complexBaseTypes; + other->m_complexContentTypes << m_complexContentTypes; + other->m_attributeTypes << m_attributeTypes; + other->m_alternativeTypes << m_alternativeTypes; + other->m_alternativeTypeElements << m_alternativeTypeElements; + other->m_substitutionGroupAffiliations << m_substitutionGroupAffiliations; + other->m_substitutionGroupTypes << m_substitutionGroupTypes; +} + +QXmlName XsdSchemaResolver::baseTypeNameOfType(const SchemaType::Ptr &type) const +{ + for (int i = 0; i < m_simpleRestrictionBases.count(); ++i) { + if (m_simpleRestrictionBases.at(i).simpleType == type) + return m_simpleRestrictionBases.at(i).baseName; + } + + for (int i = 0; i < m_complexBaseTypes.count(); ++i) { + if (m_complexBaseTypes.at(i).complexType == type) + return m_complexBaseTypes.at(i).baseName; + } + + return QXmlName(); +} + +QXmlName XsdSchemaResolver::typeNameOfAttribute(const XsdAttribute::Ptr &attribute) const +{ + for (int i = 0; i < m_attributeTypes.count(); ++i) { + if (m_attributeTypes.at(i).attribute == attribute) + return m_attributeTypes.at(i).typeName; + } + + return QXmlName(); +} + +void XsdSchemaResolver::setDefaultOpenContent(const XsdComplexType::OpenContent::Ptr &openContent, bool appliesToEmpty) +{ + m_defaultOpenContent = openContent; + m_defaultOpenContentAppliesToEmpty = appliesToEmpty; +} + +void XsdSchemaResolver::resolveKeyReferences() +{ + for (int i = 0; i < m_keyReferences.count(); ++i) { + const KeyReference ref = m_keyReferences.at(i); + + const XsdIdentityConstraint::Ptr constraint = m_schema->identityConstraint(ref.reference); + if (!constraint) { + m_context->error(QtXmlPatterns::tr("%1 references unknown %2 or %3 element %4") + .arg(formatKeyword(ref.keyRef->displayName(m_namePool))) + .arg(formatElement("key")) + .arg(formatElement("unique")) + .arg(formatKeyword(m_namePool, ref.reference)), + XsdSchemaContext::XSDError, ref.location); + return; + } + + if (constraint->category() != XsdIdentityConstraint::Key && constraint->category() != XsdIdentityConstraint::Unique) { // only key and unique can be referenced + m_context->error(QtXmlPatterns::tr("%1 references identity constraint %2 that is no %3 or %4 element") + .arg(formatKeyword(ref.keyRef->displayName(m_namePool))) + .arg(formatKeyword(m_namePool, ref.reference)) + .arg(formatElement("key")) + .arg(formatElement("unique")), + XsdSchemaContext::XSDError, ref.location); + return; + } + + if (constraint->fields().count() != ref.keyRef->fields().count()) { + m_context->error(QtXmlPatterns::tr("%1 has a different number of fields from the identity constraint %2 that it references") + .arg(formatKeyword(ref.keyRef->displayName(m_namePool))) + .arg(formatKeyword(m_namePool, ref.reference)), + XsdSchemaContext::XSDError, ref.location); + return; + } + + ref.keyRef->setReferencedKey(constraint); + } +} + +void XsdSchemaResolver::resolveSimpleRestrictionBaseTypes() +{ + // iterate over all simple types that are derived by restriction + for (int i = 0; i < m_simpleRestrictionBases.count(); ++i) { + const SimpleRestrictionBase item = m_simpleRestrictionBases.at(i); + + // find the base type + SchemaType::Ptr type = m_schema->type(item.baseName); + if (!type) { + // maybe it's a basic type... + type = m_context->schemaTypeFactory()->createSchemaType(item.baseName); + if (!type) { + m_context->error(QtXmlPatterns::tr("base type %1 of %2 element cannot be resolved") + .arg(formatType(m_namePool, item.baseName)) + .arg(formatElement("restriction")), + XsdSchemaContext::XSDError, item.location); + return; + } + } + + item.simpleType->setWxsSuperType(type); + } +} + +void XsdSchemaResolver::resolveSimpleRestrictions() +{ + XsdSimpleType::List simpleTypes; + + // first collect the global simple types + const SchemaType::List types = m_schema->types(); + for (int i = 0; i < types.count(); ++i) { + if (types.at(i)->isSimpleType() && (types.at(i)->derivationMethod() == SchemaType::DerivationRestriction)) + simpleTypes.append(types.at(i)); + } + + // then collect all anonymous simple types + const SchemaType::List anonymousTypes = m_schema->anonymousTypes(); + for (int i = 0; i < anonymousTypes.count(); ++i) { + if (anonymousTypes.at(i)->isSimpleType() && (anonymousTypes.at(i)->derivationMethod() == SchemaType::DerivationRestriction)) + simpleTypes.append(anonymousTypes.at(i)); + } + + QSet<XsdSimpleType::Ptr> visitedTypes; + for (int i = 0; i < simpleTypes.count(); ++i) { + resolveSimpleRestrictions(simpleTypes.at(i), visitedTypes); + } +} + +void XsdSchemaResolver::resolveSimpleRestrictions(const XsdSimpleType::Ptr &simpleType, QSet<XsdSimpleType::Ptr> &visitedTypes) +{ + if (visitedTypes.contains(simpleType)) + return; + else + visitedTypes.insert(simpleType); + + if (simpleType->derivationMethod() != XsdSimpleType::DerivationRestriction) + return; + + // as xs:NMTOKENS, xs:ENTITIES and xs:IDREFS are provided by our XsdSchemaTypesFactory, they are + // setup correctly already and shouldn't be handled here + if (m_predefinedSchemaTypes.contains(simpleType)) + return; + + const SchemaType::Ptr baseType = simpleType->wxsSuperType(); + Q_ASSERT(baseType); + + if (baseType->isDefinedBySchema()) + resolveSimpleRestrictions(XsdSimpleType::Ptr(baseType), visitedTypes); + + simpleType->setCategory(baseType->category()); + + if (simpleType->category() == XsdSimpleType::SimpleTypeAtomic) { + QSet<AnySimpleType::Ptr> visitedPrimitiveTypes; + const AnySimpleType::Ptr primitiveType = findPrimitiveType(baseType, visitedPrimitiveTypes); + simpleType->setPrimitiveType(primitiveType); + } else if (simpleType->category() == XsdSimpleType::SimpleTypeList) { + const XsdSimpleType::Ptr simpleBaseType = baseType; + simpleType->setItemType(simpleBaseType->itemType()); + } else if (simpleType->category() == XsdSimpleType::SimpleTypeUnion) { + const XsdSimpleType::Ptr simpleBaseType = baseType; + simpleType->setMemberTypes(simpleBaseType->memberTypes()); + } +} + +void XsdSchemaResolver::resolveSimpleListType() +{ + // iterate over all simple types where the item type shall be resolved + for (int i = 0; i < m_simpleListTypes.count(); ++i) { + const SimpleListType item = m_simpleListTypes.at(i); + + // try to resolve the name + SchemaType::Ptr type = m_schema->type(item.typeName); + if (!type) { + // maybe it's a basic type... + type = m_context->schemaTypeFactory()->createSchemaType(item.typeName); + if (!type) { + m_context->error(QtXmlPatterns::tr("item type %1 of %2 element cannot be resolved") + .arg(formatType(m_namePool, item.typeName)) + .arg(formatElement("list")), + XsdSchemaContext::XSDError, item.location); + return; + } + } + + item.simpleType->setItemType(type); + } +} + +void XsdSchemaResolver::resolveSimpleUnionTypes() +{ + // iterate over all simple types where the union member types shall be resolved + for (int i = 0; i < m_simpleUnionTypes.count(); ++i) { + const SimpleUnionType item = m_simpleUnionTypes.at(i); + + AnySimpleType::List memberTypes; + + // iterate over all union member type names + const QList<QXmlName> typeNames = item.typeNames; + for (int j = 0; j < typeNames.count(); ++j) { + const QXmlName typeName = typeNames.at(j); + + // try to resolve the name + SchemaType::Ptr type = m_schema->type(typeName); + if (!type) { + // maybe it's a basic type... + type = m_context->schemaTypeFactory()->createSchemaType(typeName); + if (!type) { + m_context->error(QtXmlPatterns::tr("member type %1 of %2 element cannot be resolved") + .arg(formatType(m_namePool, typeName)) + .arg(formatElement("union")), + XsdSchemaContext::XSDError, item.location); + return; + } + } + + memberTypes.append(type); + } + + // append the types that have been defined as <simpleType> children + memberTypes << item.simpleType->memberTypes(); + + item.simpleType->setMemberTypes(memberTypes); + } +} + +void XsdSchemaResolver::resolveElementTypes() +{ + for (int i = 0; i < m_elementTypes.count(); ++i) { + const ElementType item = m_elementTypes.at(i); + + SchemaType::Ptr type = m_schema->type(item.typeName); + if (!type) { + // maybe it's a basic type... + type = m_context->schemaTypeFactory()->createSchemaType(item.typeName); + if (!type) { + m_context->error(QtXmlPatterns::tr("type %1 of %2 element cannot be resolved") + .arg(formatType(m_namePool, item.typeName)) + .arg(formatElement("element")), + XsdSchemaContext::XSDError, item.location); + return; + } + } + + item.element->setType(type); + } +} + +void XsdSchemaResolver::resolveComplexBaseTypes() +{ + for (int i = 0; i < m_complexBaseTypes.count(); ++i) { + const ComplexBaseType item = m_complexBaseTypes.at(i); + + SchemaType::Ptr type = m_schema->type(item.baseName); + if (!type) { + // maybe it's a basic type... + type = m_context->schemaTypeFactory()->createSchemaType(item.baseName); + if (!type) { + m_context->error(QtXmlPatterns::tr("base type %1 of complex type cannot be resolved").arg(formatType(m_namePool, item.baseName)), XsdSchemaContext::XSDError, item.location); + return; + } + } + + if (item.complexType->contentType()->variety() == XsdComplexType::ContentType::Simple) { + if (type->isComplexType() && type->isDefinedBySchema()) { + const XsdComplexType::Ptr baseType = type; + if (baseType->contentType()->variety() != XsdComplexType::ContentType::Simple) { + m_context->error(QtXmlPatterns::tr("%1 cannot have complex base type that has a %2") + .arg(formatElement("simpleContent")) + .arg(formatElement("complexContent")), + XsdSchemaContext::XSDError, item.location); + return; + } + } + } + + item.complexType->setWxsSuperType(type); + } +} + +void XsdSchemaResolver::resolveSimpleContentComplexTypes() +{ + XsdComplexType::List complexTypes; + + // first collect the global complex types + const SchemaType::List types = m_schema->types(); + for (int i = 0; i < types.count(); ++i) { + if (types.at(i)->isComplexType() && types.at(i)->isDefinedBySchema()) + complexTypes.append(types.at(i)); + } + + // then collect all anonymous simple types + const SchemaType::List anonymousTypes = m_schema->anonymousTypes(); + for (int i = 0; i < anonymousTypes.count(); ++i) { + if (anonymousTypes.at(i)->isComplexType() && anonymousTypes.at(i)->isDefinedBySchema()) + complexTypes.append(anonymousTypes.at(i)); + } + + QSet<XsdComplexType::Ptr> visitedTypes; + for (int i = 0; i < complexTypes.count(); ++i) { + if (XsdComplexType::Ptr(complexTypes.at(i))->contentType()->variety() == XsdComplexType::ContentType::Simple) + resolveSimpleContentComplexTypes(complexTypes.at(i), visitedTypes); + } +} + +void XsdSchemaResolver::resolveSimpleContentComplexTypes(const XsdComplexType::Ptr &complexType, QSet<XsdComplexType::Ptr> &visitedTypes) +{ + if (visitedTypes.contains(complexType)) + return; + else + visitedTypes.insert(complexType); + + const SchemaType::Ptr baseType = complexType->wxsSuperType(); + + // at this point simple types have been resolved already, so we care about + // complex types here only + + // http://www.w3.org/TR/xmlschema11-1/#dcl.ctd.ctsc + // 1 + if (baseType->isComplexType() && baseType->isDefinedBySchema()) { + const XsdComplexType::Ptr complexBaseType = baseType; + + resolveSimpleContentComplexTypes(complexBaseType, visitedTypes); + + if (complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Simple) { + if (complexType->derivationMethod() == XsdComplexType::DerivationRestriction) { + if (complexType->contentType()->simpleType()) { + // 1.1 contains the content of the <simpleType> already + } else { + // 1.2 + const XsdSimpleType::Ptr anonType(new XsdSimpleType()); + anonType->setCategory(complexBaseType->contentType()->simpleType()->category()); + anonType->setDerivationMethod(XsdSimpleType::DerivationRestriction); + anonType->setWxsSuperType(complexBaseType->contentType()->simpleType()); + anonType->setFacets(complexTypeFacets(complexType)); + + QSet<AnySimpleType::Ptr> visitedPrimitiveTypes; + const AnySimpleType::Ptr primitiveType = findPrimitiveType(anonType->wxsSuperType(), visitedPrimitiveTypes); + anonType->setPrimitiveType(primitiveType); + + complexType->contentType()->setSimpleType(anonType); + + m_schema->addAnonymousType(anonType); + m_componentLocationHash.insert(anonType, m_componentLocationHash.value(complexType)); + } + } else if (complexBaseType->derivationMethod() == XsdComplexType::DerivationExtension) { // 3 + complexType->contentType()->setSimpleType(complexBaseType->contentType()->simpleType()); + } + } else if (complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Mixed && + complexType->derivationMethod() == XsdComplexType::DerivationRestriction && + XsdSchemaHelper::isParticleEmptiable(complexBaseType->contentType()->particle())) { // 2 + // simple type was already set in parser + + const XsdSimpleType::Ptr anonType(new XsdSimpleType()); + anonType->setCategory(complexType->contentType()->simpleType()->category()); + anonType->setDerivationMethod(XsdSimpleType::DerivationRestriction); + anonType->setWxsSuperType(complexType->contentType()->simpleType()); + anonType->setFacets(complexTypeFacets(complexType)); + + QSet<AnySimpleType::Ptr> visitedPrimitiveTypes; + const AnySimpleType::Ptr primitiveType = findPrimitiveType(anonType->wxsSuperType(), visitedPrimitiveTypes); + anonType->setPrimitiveType(primitiveType); + + complexType->contentType()->setSimpleType(anonType); + + m_schema->addAnonymousType(anonType); + m_componentLocationHash.insert(anonType, m_componentLocationHash.value(complexType)); + } else { + complexType->contentType()->setSimpleType(BuiltinTypes::xsAnySimpleType); + } + } else if (baseType->isSimpleType()) { // 4 + complexType->contentType()->setSimpleType(baseType); + } else { // 5 + complexType->contentType()->setSimpleType(BuiltinTypes::xsAnySimpleType); + } +} + +void XsdSchemaResolver::resolveComplexContentComplexTypes() +{ + XsdComplexType::List complexTypes; + + // first collect the global complex types + const SchemaType::List types = m_schema->types(); + for (int i = 0; i < types.count(); ++i) { + if (types.at(i)->isComplexType() && types.at(i)->isDefinedBySchema()) + complexTypes.append(types.at(i)); + } + + // then collect all anonymous simple types + const SchemaType::List anonymousTypes = m_schema->anonymousTypes(); + for (int i = 0; i < anonymousTypes.count(); ++i) { + if (anonymousTypes.at(i)->isComplexType() && anonymousTypes.at(i)->isDefinedBySchema()) + complexTypes.append(anonymousTypes.at(i)); + } + + QSet<XsdComplexType::Ptr> visitedTypes; + for (int i = 0; i < complexTypes.count(); ++i) { + if (XsdComplexType::Ptr(complexTypes.at(i))->contentType()->variety() != XsdComplexType::ContentType::Simple) + resolveComplexContentComplexTypes(complexTypes.at(i), visitedTypes); + } +} + +void XsdSchemaResolver::resolveComplexContentComplexTypes(const XsdComplexType::Ptr &complexType, QSet<XsdComplexType::Ptr> &visitedTypes) +{ + if (visitedTypes.contains(complexType)) + return; + else + visitedTypes.insert(complexType); + + ComplexContentType item; + bool foundCorrespondingItem = false; + for (int i = 0; i < m_complexContentTypes.count(); ++i) { + if (m_complexContentTypes.at(i).complexType == complexType) { + item = m_complexContentTypes.at(i); + foundCorrespondingItem = true; + break; + } + } + + if (!foundCorrespondingItem) + return; + + const SchemaType::Ptr baseType = complexType->wxsSuperType(); + + // at this point simple types have been resolved already, so we care about + // complex types here only + if (baseType->isComplexType() && baseType->isDefinedBySchema()) + resolveComplexContentComplexTypes(XsdComplexType::Ptr(baseType), visitedTypes); + + + // @see http://www.w3.org/TR/xmlschema11-1/#dcl.ctd.ctcc.common + + // 3 + XsdParticle::Ptr effectiveContent; + if (!item.explicitContent) { // 3.1 + if (item.effectiveMixed == true) { // 3.1.1 + const XsdParticle::Ptr particle(new XsdParticle()); + particle->setMinimumOccurs(1); + particle->setMaximumOccurs(1); + particle->setMaximumOccursUnbounded(false); + + const XsdModelGroup::Ptr sequence(new XsdModelGroup()); + sequence->setCompositor(XsdModelGroup::SequenceCompositor); + particle->setTerm(sequence); + + effectiveContent = particle; + } else { // 3.1.2 + effectiveContent = XsdParticle::Ptr(); + } + } else { // 3.2 + effectiveContent = item.explicitContent; + } + + // 4 + XsdComplexType::ContentType::Ptr explicitContentType(new XsdComplexType::ContentType()); + if (item.complexType->derivationMethod() == XsdComplexType::DerivationRestriction) { // 4.1 + if (!effectiveContent) { // 4.1.1 + explicitContentType->setVariety(XsdComplexType::ContentType::Empty); + } else { // 4.1.2 + if (item.effectiveMixed == true) + explicitContentType->setVariety(XsdComplexType::ContentType::Mixed); + else + explicitContentType->setVariety(XsdComplexType::ContentType::ElementOnly); + + explicitContentType->setParticle(effectiveContent); + } + } else if (item.complexType->derivationMethod() == XsdComplexType::DerivationExtension) { // 4.2 + const SchemaType::Ptr baseType = item.complexType->wxsSuperType(); + if (baseType->isSimpleType() || (baseType->isComplexType() && baseType->isDefinedBySchema() && (XsdComplexType::Ptr(baseType)->contentType()->variety() == XsdComplexType::ContentType::Empty || + XsdComplexType::Ptr(baseType)->contentType()->variety() == XsdComplexType::ContentType::Simple))) { // 4.2.1 + if (!effectiveContent) { + explicitContentType->setVariety(XsdComplexType::ContentType::Empty); + } else { + if (item.effectiveMixed == true) + explicitContentType->setVariety(XsdComplexType::ContentType::Mixed); + else + explicitContentType->setVariety(XsdComplexType::ContentType::ElementOnly); + + explicitContentType->setParticle(effectiveContent); + } + } else if (baseType->isComplexType() && baseType->isDefinedBySchema() && (XsdComplexType::Ptr(baseType)->contentType()->variety() == XsdComplexType::ContentType::ElementOnly || + XsdComplexType::Ptr(baseType)->contentType()->variety() == XsdComplexType::ContentType::Mixed) && !effectiveContent) { // 4.2.2 + const XsdComplexType::Ptr complexBaseType(baseType); + + explicitContentType = complexBaseType->contentType(); + } else { // 4.2.3 + explicitContentType->setVariety(item.effectiveMixed ? XsdComplexType::ContentType::Mixed : XsdComplexType::ContentType::ElementOnly); + + XsdParticle::Ptr baseParticle; + if (baseType == BuiltinTypes::xsAnyType) { + // we need a workaround here, since the xsAnyType is no real (aka XsdComplexType) complex type... + + baseParticle = XsdParticle::Ptr(new XsdParticle()); + baseParticle->setMinimumOccurs(1); + baseParticle->setMaximumOccurs(1); + baseParticle->setMaximumOccursUnbounded(false); + + const XsdModelGroup::Ptr group(new XsdModelGroup()); + group->setCompositor(XsdModelGroup::SequenceCompositor); + + const XsdParticle::Ptr particle(new XsdParticle()); + particle->setMinimumOccurs(0); + particle->setMaximumOccursUnbounded(true); + + const XsdWildcard::Ptr wildcard(new XsdWildcard()); + wildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Any); + wildcard->setProcessContents(XsdWildcard::Lax); + + particle->setTerm(wildcard); + XsdParticle::List particles; + particles.append(particle); + group->setParticles(particles); + baseParticle->setTerm(group); + } else { + const XsdComplexType::Ptr complexBaseType(baseType); + baseParticle = complexBaseType->contentType()->particle(); + } + if (baseParticle && baseParticle->term()->isModelGroup() && (XsdModelGroup::Ptr(baseParticle->term())->compositor() == XsdModelGroup::AllCompositor) && + (!item.explicitContent)) { // 4.2.3.1 + + explicitContentType->setParticle(baseParticle); + } else if (baseParticle && baseParticle->term()->isModelGroup() && (XsdModelGroup::Ptr(baseParticle->term())->compositor() == XsdModelGroup::AllCompositor) && + (effectiveContent->term()->isModelGroup() && (XsdModelGroup::Ptr(effectiveContent->term())->compositor() == XsdModelGroup::AllCompositor))) { // 4.2.3.2 + const XsdParticle::Ptr particle(new XsdParticle()); + particle->setMinimumOccurs(effectiveContent->minimumOccurs()); + particle->setMaximumOccurs(1); + particle->setMaximumOccursUnbounded(false); + + const XsdModelGroup::Ptr group(new XsdModelGroup()); + group->setCompositor(XsdModelGroup::AllCompositor); + XsdParticle::List particles = XsdModelGroup::Ptr(baseParticle->term())->particles(); + particles << XsdModelGroup::Ptr(effectiveContent->term())->particles(); + group->setParticles(particles); + particle->setTerm(group); + + explicitContentType->setParticle(particle); + } else { // 4.2.3.3 + const XsdParticle::Ptr particle(new XsdParticle()); + particle->setMinimumOccurs(1); + particle->setMaximumOccurs(1); + particle->setMaximumOccursUnbounded(false); + + const XsdModelGroup::Ptr group(new XsdModelGroup()); + group->setCompositor(XsdModelGroup::SequenceCompositor); + + if (effectiveContent && effectiveContent->term()->isModelGroup() && XsdModelGroup::Ptr(effectiveContent->term())->compositor() == XsdModelGroup::AllCompositor) { + m_context->error(QtXmlPatterns::tr("content model of complex type %1 contains %2 element so it cannot be derived by extension from a non-empty type") + .arg(formatType(m_namePool, complexType)).arg(formatKeyword("all")), XsdSchemaContext::XSDError, sourceLocation(complexType)); + return; + } + + if (baseParticle && baseParticle->term()->isModelGroup() && XsdModelGroup::Ptr(baseParticle->term())->compositor() == XsdModelGroup::AllCompositor) { + m_context->error(QtXmlPatterns::tr("complex type %1 cannot be derived by extension from %2 as the latter contains %3 element in its content model") + .arg(formatType(m_namePool, complexType)) + .arg(formatType(m_namePool, baseType)) + .arg(formatKeyword("all")), XsdSchemaContext::XSDError, sourceLocation(complexType)); + return; + } + + XsdParticle::List particles; + if (baseParticle) + particles << baseParticle; + if (effectiveContent) + particles << effectiveContent; + group->setParticles(particles); + particle->setTerm(group); + + explicitContentType->setParticle(particle); + } + + if (baseType->isDefinedBySchema()) { // xs:anyType has no open content + const XsdComplexType::Ptr complexBaseType(baseType); + explicitContentType->setOpenContent(complexBaseType->contentType()->openContent()); + } + } + } + + // 5 + XsdComplexType::OpenContent::Ptr wildcardElement; + if (item.complexType->contentType()->openContent()) { // 5.1 + wildcardElement = item.complexType->contentType()->openContent(); + } else { + if (m_defaultOpenContent) { // 5.2 + if ((explicitContentType->variety() != XsdComplexType::ContentType::Empty) || // 5.2.1 + (explicitContentType->variety() == XsdComplexType::ContentType::Empty && m_defaultOpenContentAppliesToEmpty)) { // 5.2.2 + wildcardElement = m_defaultOpenContent; + } + } + } + + // 6 + if (!wildcardElement) { // 6.1 + item.complexType->setContentType(explicitContentType); + } else { + if (wildcardElement->mode() == XsdComplexType::OpenContent::None) { // 6.2 + const XsdComplexType::ContentType::Ptr contentType(new XsdComplexType::ContentType()); + contentType->setVariety(explicitContentType->variety()); + contentType->setParticle(explicitContentType->particle()); + + item.complexType->setContentType(contentType); + } else { // 6.3 + const XsdComplexType::ContentType::Ptr contentType(new XsdComplexType::ContentType()); + + if (explicitContentType->variety() == XsdComplexType::ContentType::Empty) + contentType->setVariety(XsdComplexType::ContentType::ElementOnly); + else + contentType->setVariety(explicitContentType->variety()); + + if (explicitContentType->variety() == XsdComplexType::ContentType::Empty) { + const XsdParticle::Ptr particle(new XsdParticle()); + particle->setMinimumOccurs(1); + particle->setMaximumOccurs(1); + const XsdModelGroup::Ptr sequence(new XsdModelGroup()); + sequence->setCompositor(XsdModelGroup::SequenceCompositor); + particle->setTerm(sequence); + contentType->setParticle(particle); + } else { + contentType->setParticle(explicitContentType->particle()); + } + + const XsdComplexType::OpenContent::Ptr openContent(new XsdComplexType::OpenContent()); + if (wildcardElement) + openContent->setMode(wildcardElement->mode()); + else + openContent->setMode(XsdComplexType::OpenContent::Interleave); + + if (wildcardElement) + openContent->setWildcard(wildcardElement->wildcard()); + + item.complexType->setContentType(contentType); + } + } +} + +void XsdSchemaResolver::resolveAttributeTypes() +{ + for (int i = 0; i < m_attributeTypes.count(); ++i) { + const AttributeType item = m_attributeTypes.at(i); + + SchemaType::Ptr type = m_schema->type(item.typeName); + if (!type) { + // maybe it's a basic type... + type = m_context->schemaTypeFactory()->createSchemaType(item.typeName); + if (!type) { + m_context->error(QtXmlPatterns::tr("type %1 of %2 element cannot be resolved") + .arg(formatType(m_namePool, item.typeName)) + .arg(formatElement("attribute")), + XsdSchemaContext::XSDError, item.location); + return; + } + } + + if (!type->isSimpleType() && type->category() != SchemaType::None) { + m_context->error(QtXmlPatterns::tr("type of %1 element must be a simple type, %2 is not") + .arg(formatElement("attribute")) + .arg(formatType(m_namePool, item.typeName)), + XsdSchemaContext::XSDError, item.location); + return; + } + + item.attribute->setType(type); + } +} + +void XsdSchemaResolver::resolveAlternativeTypes() +{ + for (int i = 0; i < m_alternativeTypes.count(); ++i) { + const AlternativeType item = m_alternativeTypes.at(i); + + SchemaType::Ptr type = m_schema->type(item.typeName); + if (!type) { + // maybe it's a basic type... + type = m_context->schemaTypeFactory()->createSchemaType(item.typeName); + if (!type) { + m_context->error(QtXmlPatterns::tr("type %1 of %2 element cannot be resolved") + .arg(formatType(m_namePool, item.typeName)) + .arg(formatElement("alternative")), + XsdSchemaContext::XSDError, item.location); + return; + } + } + + item.alternative->setType(type); + } + + for (int i = 0; i < m_alternativeTypeElements.count(); ++i) { + const AlternativeTypeElement item = m_alternativeTypeElements.at(i); + item.alternative->setType(item.element->type()); + } +} + +bool hasCircularSubstitutionGroup(const XsdElement::Ptr ¤t, const XsdElement::Ptr &head, const NamePool::Ptr &namePool) +{ + if (current == head) + return true; + else { + const XsdElement::List elements = current->substitutionGroupAffiliations(); + for (int i = 0; i < elements.count(); ++i) { + if (hasCircularSubstitutionGroup(elements.at(i), head, namePool)) + return true; + } + } + + return false; +} + +void XsdSchemaResolver::resolveSubstitutionGroupAffiliations() +{ + for (int i = 0; i < m_substitutionGroupAffiliations.count(); ++i) { + const SubstitutionGroupAffiliation item = m_substitutionGroupAffiliations.at(i); + + XsdElement::List affiliations; + for (int j = 0; j < item.elementNames.count(); ++j) { + const XsdElement::Ptr element = m_schema->element(item.elementNames.at(j)); + if (!element) { + m_context->error(QtXmlPatterns::tr("substitution group %1 of %2 element cannot be resolved") + .arg(formatKeyword(m_namePool, item.elementNames.at(j))) + .arg(formatElement("element")), + XsdSchemaContext::XSDError, item.location); + return; + } + + // @see http://www.w3.org/TR/xmlschema11-1/#e-props-correct 5) + if (hasCircularSubstitutionGroup(element, item.element, m_namePool)) { + m_context->error(QtXmlPatterns::tr("substitution group %1 has circular definition").arg(formatKeyword(m_namePool, item.elementNames.at(j))), XsdSchemaContext::XSDError, item.location); + return; + } + + affiliations.append(element); + } + + item.element->setSubstitutionGroupAffiliations(affiliations); + } + + for (int i = 0; i < m_substitutionGroupTypes.count(); ++i) { + const XsdElement::Ptr element = m_substitutionGroupTypes.at(i); + element->setType(element->substitutionGroupAffiliations().first()->type()); + } +} + +bool isSubstGroupHeadOf(const XsdElement::Ptr &head, const XsdElement::Ptr &element, const NamePool::Ptr &namePool) +{ + if (head->name(namePool) == element->name(namePool)) + return true; + + const XsdElement::List affiliations = element->substitutionGroupAffiliations(); + for (int i = 0; i < affiliations.count(); ++i) { + if (isSubstGroupHeadOf(head, affiliations.at(i), namePool)) + return true; + } + + return false; +} + +void XsdSchemaResolver::resolveSubstitutionGroups() +{ + const XsdElement::List elements = m_schema->elements(); + for (int i = 0; i < elements.count(); ++i) { + const XsdElement::Ptr element = elements.at(i); + + // the element is always itself in the substitution group + element->addSubstitutionGroup(element); + + for (int j = 0; j < elements.count(); ++j) { + if (i == j) + continue; + + if (isSubstGroupHeadOf(element, elements.at(j), m_namePool)) + element->addSubstitutionGroup(elements.at(j)); + } + } +} + +void XsdSchemaResolver::resolveTermReferences() +{ + // first the global complex types + const SchemaType::List types = m_schema->types(); + for (int i = 0; i < types.count(); ++i) { + if (!(types.at(i)->isComplexType()) || !types.at(i)->isDefinedBySchema()) + continue; + + const XsdComplexType::Ptr complexType = types.at(i); + if (complexType->contentType()->variety() != XsdComplexType::ContentType::ElementOnly && complexType->contentType()->variety() != XsdComplexType::ContentType::Mixed) + continue; + + resolveTermReference(complexType->contentType()->particle(), QSet<QXmlName>()); + } + + // then all anonymous complex types + const SchemaType::List anonymousTypes = m_schema->anonymousTypes(); + for (int i = 0; i < anonymousTypes.count(); ++i) { + if (!(anonymousTypes.at(i)->isComplexType()) || !anonymousTypes.at(i)->isDefinedBySchema()) + continue; + + const XsdComplexType::Ptr complexType = anonymousTypes.at(i); + if (complexType->contentType()->variety() != XsdComplexType::ContentType::ElementOnly && complexType->contentType()->variety() != XsdComplexType::ContentType::Mixed) + continue; + + resolveTermReference(complexType->contentType()->particle(), QSet<QXmlName>()); + } + + const XsdModelGroup::List groups = m_schema->elementGroups(); + for (int i = 0; i < groups.count(); ++i) { + const XsdParticle::Ptr particle(new XsdParticle()); + particle->setTerm(groups.at(i)); + resolveTermReference(particle, QSet<QXmlName>()); + } +} + +void XsdSchemaResolver::resolveTermReference(const XsdParticle::Ptr &particle, QSet<QXmlName> visitedGroups) +{ + if (!particle) + return; + + const XsdTerm::Ptr term = particle->term(); + + // if it is a model group, we iterate over it recursive... + if (term->isModelGroup()) { + const XsdModelGroup::Ptr modelGroup = term; + const XsdParticle::List particles = modelGroup->particles(); + + for (int i = 0; i < particles.count(); ++i) { + resolveTermReference(particles.at(i), visitedGroups); + } + + // check for unique names of elements inside all compositor + if (modelGroup->compositor() != XsdModelGroup::ChoiceCompositor) { + for (int i = 0; i < particles.count(); ++i) { + const XsdParticle::Ptr particle = particles.at(i); + const XsdTerm::Ptr term = particle->term(); + + if (!(term->isElement())) + continue; + + for (int j = 0; j < particles.count(); ++j) { + const XsdParticle::Ptr otherParticle = particles.at(j); + const XsdTerm::Ptr otherTerm = otherParticle->term(); + + if (otherTerm->isElement() && i != j) { + const XsdElement::Ptr element = term; + const XsdElement::Ptr otherElement = otherTerm; + + if (element->name(m_namePool) == otherElement->name(m_namePool)) { + if (modelGroup->compositor() == XsdModelGroup::AllCompositor) { + m_context->error(QtXmlPatterns::tr("duplicated element names %1 in %2 element") + .arg(formatKeyword(element->displayName(m_namePool))) + .arg(formatElement("all")), + XsdSchemaContext::XSDError, sourceLocation(modelGroup)); + return; + } else if (modelGroup->compositor() == XsdModelGroup::SequenceCompositor) { + if (element->type() != otherElement->type()) { // not same variety + m_context->error(QtXmlPatterns::tr("duplicated element names %1 in %2 element") + .arg(formatKeyword(element->displayName(m_namePool))) + .arg(formatElement("sequence")), + XsdSchemaContext::XSDError, sourceLocation(modelGroup)); + return; + } + } + } + } + } + } + } + + return; + } + + // ...otherwise we have reached the end of recursion... + if (!term->isReference()) + return; + + // ...or we have reached a reference term that must be resolved + const XsdReference::Ptr reference = term; + switch (reference->type()) { + case XsdReference::Element: + { + const XsdElement::Ptr element = m_schema->element(reference->referenceName()); + if (element) { + particle->setTerm(element); + } else { + m_context->error(QtXmlPatterns::tr("reference %1 of %2 element cannot be resolved") + .arg(formatKeyword(m_namePool, reference->referenceName())) + .arg(formatElement("element")), + XsdSchemaContext::XSDError, reference->sourceLocation()); + return; + } + } + break; + case XsdReference::ModelGroup: + { + const XsdModelGroup::Ptr modelGroup = m_schema->elementGroup(reference->referenceName()); + if (modelGroup) { + if (visitedGroups.contains(modelGroup->name(m_namePool))) { + m_context->error(QtXmlPatterns::tr("circular group reference for %1").arg(formatKeyword(modelGroup->displayName(m_namePool))), + XsdSchemaContext::XSDError, reference->sourceLocation()); + } else { + visitedGroups.insert(modelGroup->name(m_namePool)); + } + + particle->setTerm(modelGroup); + + // start recursive iteration here as well to get all references resolved + const XsdParticle::List particles = modelGroup->particles(); + for (int i = 0; i < particles.count(); ++i) { + resolveTermReference(particles.at(i), visitedGroups); + } + + if (modelGroup->compositor() == XsdModelGroup::AllCompositor) { + if (m_allGroups.contains(reference)) { + m_context->error(QtXmlPatterns::tr("%1 element is not allowed in this scope").arg(formatElement("all")), + XsdSchemaContext::XSDError, reference->sourceLocation()); + return; + } + if (particle->maximumOccursUnbounded() || particle->maximumOccurs() != 1) { + m_context->error(QtXmlPatterns::tr("%1 element cannot have %2 attribute with value other than %3") + .arg(formatElement("all")) + .arg(formatAttribute("maxOccurs")) + .arg(formatData("1")), + XsdSchemaContext::XSDError, reference->sourceLocation()); + return; + } + if (particle->minimumOccurs() != 0 && particle->minimumOccurs() != 1) { + m_context->error(QtXmlPatterns::tr("%1 element cannot have %2 attribute with value other than %3 or %4") + .arg(formatElement("all")) + .arg(formatAttribute("minOccurs")) + .arg(formatData("0")) + .arg(formatData("1")), + XsdSchemaContext::XSDError, reference->sourceLocation()); + return; + } + } + } else { + m_context->error(QtXmlPatterns::tr("reference %1 of %2 element cannot be resolved") + .arg(formatKeyword(m_namePool, reference->referenceName())) + .arg(formatElement("group")), + XsdSchemaContext::XSDError, reference->sourceLocation()); + return; + } + } + break; + } +} + +void XsdSchemaResolver::resolveAttributeTermReferences() +{ + // first all global attribute groups + const XsdAttributeGroup::List attributeGroups = m_schema->attributeGroups(); + for (int i = 0; i < attributeGroups.count(); ++i) { + XsdWildcard::Ptr wildcard = attributeGroups.at(i)->wildcard(); + const XsdAttributeUse::List uses = resolveAttributeTermReferences(attributeGroups.at(i)->attributeUses(), wildcard, QSet<QXmlName>()); + attributeGroups.at(i)->setAttributeUses(uses); + attributeGroups.at(i)->setWildcard(wildcard); + } + + // then the global complex types + const SchemaType::List types = m_schema->types(); + for (int i = 0; i < types.count(); ++i) { + if (!(types.at(i)->isComplexType()) || !types.at(i)->isDefinedBySchema()) + continue; + + const XsdComplexType::Ptr complexType = types.at(i); + const XsdAttributeUse::List attributeUses = complexType->attributeUses(); + + XsdWildcard::Ptr wildcard = complexType->attributeWildcard(); + const XsdAttributeUse::List uses = resolveAttributeTermReferences(attributeUses, wildcard, QSet<QXmlName>()); + complexType->setAttributeUses(uses); + complexType->setAttributeWildcard(wildcard); + } + + // and afterwards all anonymous complex types + const SchemaType::List anonymousTypes = m_schema->anonymousTypes(); + for (int i = 0; i < anonymousTypes.count(); ++i) { + if (!(anonymousTypes.at(i)->isComplexType()) || !anonymousTypes.at(i)->isDefinedBySchema()) + continue; + + const XsdComplexType::Ptr complexType = anonymousTypes.at(i); + const XsdAttributeUse::List attributeUses = complexType->attributeUses(); + + XsdWildcard::Ptr wildcard = complexType->attributeWildcard(); + const XsdAttributeUse::List uses = resolveAttributeTermReferences(attributeUses, wildcard, QSet<QXmlName>()); + complexType->setAttributeUses(uses); + complexType->setAttributeWildcard(wildcard); + } +} + +XsdAttributeUse::List XsdSchemaResolver::resolveAttributeTermReferences(const XsdAttributeUse::List &attributeUses, XsdWildcard::Ptr &wildcard, QSet<QXmlName> visitedAttributeGroups) +{ + XsdAttributeUse::List resolvedAttributeUses; + + for (int i = 0; i < attributeUses.count(); ++i) { + const XsdAttributeUse::Ptr attributeUse = attributeUses.at(i); + if (attributeUse->isAttributeUse()) { + // it is a real attribute use, so no need to resolve it + resolvedAttributeUses.append(attributeUse); + } else if (attributeUse->isReference()) { + // it is just a reference, so resolve it to the real attribute use + + const XsdAttributeReference::Ptr reference = attributeUse; + if (reference->type() == XsdAttributeReference::AttributeUse) { + + // lookup the real attribute + const XsdAttribute::Ptr attribute = m_schema->attribute(reference->referenceName()); + if (!attribute) { + m_context->error(QtXmlPatterns::tr("reference %1 of %2 element cannot be resolved") + .arg(formatKeyword(m_namePool, reference->referenceName())) + .arg(formatElement("attribute")), + XsdSchemaContext::XSDError, reference->sourceLocation()); + return XsdAttributeUse::List(); + } + + // if both, reference and definition have a fixed or default value set, then they must be equal + if (attribute->valueConstraint() && attributeUse->valueConstraint()) { + if (attribute->valueConstraint()->value() != attributeUse->valueConstraint()->value()) { + m_context->error(QtXmlPatterns::tr("%1 or %2 attribute of reference %3 does not match with the attribute declaration %4") + .arg(formatAttribute("fixed")) + .arg(formatAttribute("default")) + .arg(formatKeyword(m_namePool, reference->referenceName())) + .arg(formatKeyword(attribute->displayName(m_namePool))), + XsdSchemaContext::XSDError, reference->sourceLocation()); + return XsdAttributeUse::List(); + } + } + + attributeUse->setAttribute(attribute); + if (!attributeUse->valueConstraint() && attribute->valueConstraint()) + attributeUse->setValueConstraint(XsdAttributeUse::ValueConstraint::fromAttributeValueConstraint(attribute->valueConstraint())); + + resolvedAttributeUses.append(attributeUse); + } else if (reference->type() == XsdAttributeReference::AttributeGroup) { + const XsdAttributeGroup::Ptr attributeGroup = m_schema->attributeGroup(reference->referenceName()); + if (!attributeGroup) { + m_context->error(QtXmlPatterns::tr("reference %1 of %2 element cannot be resolved") + .arg(formatKeyword(m_namePool, reference->referenceName())) + .arg(formatElement("attributeGroup")), + XsdSchemaContext::XSDError, reference->sourceLocation()); + return XsdAttributeUse::List(); + } + if (visitedAttributeGroups.contains(attributeGroup->name(m_namePool))) { + m_context->error(QtXmlPatterns::tr("attribute group %1 has circular reference").arg(formatKeyword(m_namePool, reference->referenceName())), + XsdSchemaContext::XSDError, reference->sourceLocation()); + return XsdAttributeUse::List(); + } else { + visitedAttributeGroups.insert(attributeGroup->name(m_namePool)); + } + + // resolve attribute wildcards as defined in http://www.w3.org/TR/xmlschema11-1/#declare-attributeGroup-wildcard + XsdWildcard::Ptr childWildcard; + resolvedAttributeUses << resolveAttributeTermReferences(attributeGroup->attributeUses(), childWildcard, visitedAttributeGroups); + if (!childWildcard) { + if (attributeGroup->wildcard()) { + if (wildcard) { + const XsdWildcard::ProcessContents contents = wildcard->processContents(); + wildcard = XsdSchemaHelper::wildcardIntersection(wildcard, attributeGroup->wildcard()); + wildcard->setProcessContents(contents); + } else { + wildcard = attributeGroup->wildcard(); + } + } + } else { + XsdWildcard::Ptr newWildcard; + if (attributeGroup->wildcard()) { + const XsdWildcard::ProcessContents contents = attributeGroup->wildcard()->processContents(); + newWildcard = XsdSchemaHelper::wildcardIntersection(attributeGroup->wildcard(), childWildcard); + newWildcard->setProcessContents(contents); + } else { + newWildcard = childWildcard; + } + + if (wildcard) { + const XsdWildcard::ProcessContents contents = wildcard->processContents(); + wildcard = XsdSchemaHelper::wildcardIntersection(wildcard, newWildcard); + wildcard->setProcessContents(contents); + } else { + wildcard = newWildcard; + } + } + } + } + } + + return resolvedAttributeUses; +} + +void XsdSchemaResolver::resolveAttributeInheritance() +{ + // collect the global and anonymous complex types + SchemaType::List types = m_schema->types(); + types << m_schema->anonymousTypes(); + + QSet<XsdComplexType::Ptr> visitedTypes; + for (int i = 0; i < types.count(); ++i) { + if (!(types.at(i)->isComplexType()) || !types.at(i)->isDefinedBySchema()) + continue; + + const XsdComplexType::Ptr complexType = types.at(i); + + resolveAttributeInheritance(complexType, visitedTypes); + } +} + +bool isValidWildcardRestriction(const XsdWildcard::Ptr &wildcard, const XsdWildcard::Ptr &baseWildcard) +{ + if (wildcard->namespaceConstraint()->variety() == baseWildcard->namespaceConstraint()->variety()) { + if (!XsdSchemaHelper::checkWildcardProcessContents(baseWildcard, wildcard)) + return false; + } + + if (wildcard->namespaceConstraint()->variety() == XsdWildcard::NamespaceConstraint::Any && + baseWildcard->namespaceConstraint()->variety() != XsdWildcard::NamespaceConstraint::Any ) { + return false; + } + if (baseWildcard->namespaceConstraint()->variety() == XsdWildcard::NamespaceConstraint::Not && + wildcard->namespaceConstraint()->variety() == XsdWildcard::NamespaceConstraint::Enumeration) { + if (!baseWildcard->namespaceConstraint()->namespaces().intersect(wildcard->namespaceConstraint()->namespaces()).isEmpty()) + return false; + } + if (baseWildcard->namespaceConstraint()->variety() == XsdWildcard::NamespaceConstraint::Enumeration && + wildcard->namespaceConstraint()->variety() == XsdWildcard::NamespaceConstraint::Enumeration) { + if (!wildcard->namespaceConstraint()->namespaces().subtract(baseWildcard->namespaceConstraint()->namespaces()).isEmpty()) + return false; + } + + return true; +} + +/* + * Since we inherit the attributes from our base class we have to walk up in the + * inheritance hierarchy first and resolve the attribute inheritance top-down. + */ +void XsdSchemaResolver::resolveAttributeInheritance(const XsdComplexType::Ptr &complexType, QSet<XsdComplexType::Ptr> &visitedTypes) +{ + if (visitedTypes.contains(complexType)) + return; + else + visitedTypes.insert(complexType); + + const SchemaType::Ptr baseType = complexType->wxsSuperType(); + Q_ASSERT(baseType); + + if (!(baseType->isComplexType()) || !baseType->isDefinedBySchema()) + return; + + const XsdComplexType::Ptr complexBaseType = baseType; + + resolveAttributeInheritance(complexBaseType, visitedTypes); + + // @see http://www.w3.org/TR/xmlschema11-1/#dcl.ctd.attuses + + // 1 and 2 (the attribute groups have been resolved here already) + const XsdAttributeUse::List uses = complexBaseType->attributeUses(); + + if (complexType->derivationMethod() == XsdComplexType::DerivationRestriction) { // 3.2 + const XsdAttributeUse::List currentUses = complexType->attributeUses(); + + // 3.2.1 and 3.2.2 As we also keep the prohibited attributes as objects, the algorithm below + // handles both the same way + + // add only these attribute uses of the base type that match one of the following criteria: + // 1: there is no attribute use with the same name in type + // 2: there is no attribute with the same name marked as prohibited in type + for (int j = 0; j < uses.count(); ++j) { + const XsdAttributeUse::Ptr use = uses.at(j); + bool found = false; + for (int k = 0; k < currentUses.count(); ++k) { + if (use->attribute()->name(m_namePool) == currentUses.at(k)->attribute()->name(m_namePool)) { + found = true; + + // check if prohibited usage is violated + if ((use->useType() == XsdAttributeUse::ProhibitedUse) && (currentUses.at(k)->useType() != XsdAttributeUse::ProhibitedUse)) { + m_context->error(QtXmlPatterns::tr("%1 attribute in %2 must have %3 use like in base type %4") + .arg(formatAttribute(use->attribute()->displayName(m_namePool))) + .arg(formatType(m_namePool, complexType)) + .arg(formatData("prohibited")) + .arg(formatType(m_namePool, complexBaseType)), + XsdSchemaContext::XSDError, sourceLocation(complexType)); + return; + } + + break; + } + } + + if (!found && uses.at(j)->useType() != XsdAttributeUse::ProhibitedUse) { + complexType->addAttributeUse(uses.at(j)); + } + } + } else if (complexType->derivationMethod() == XsdComplexType::DerivationExtension) { // 3.1 + QHash<QXmlName, XsdAttributeUse::Ptr> availableUses; + + // fill hash with attribute uses of current type for faster lookup + { + const XsdAttributeUse::List attributeUses = complexType->attributeUses(); + + for (int i = 0; i < attributeUses.count(); ++i) { + availableUses.insert(attributeUses.at(i)->attribute()->name(m_namePool), attributeUses.at(i)); + } + } + + // just add the attribute uses of the base type + for (int i = 0; i < uses.count(); ++i) { + const XsdAttributeUse::Ptr currentAttributeUse = uses.at(i); + + // if the base type defines the attribute as prohibited but we override it in current type, then don't copy the prohibited attribute use + if ((currentAttributeUse->useType() == XsdAttributeUse::ProhibitedUse) && availableUses.contains(currentAttributeUse->attribute()->name(m_namePool))) + continue; + + complexType->addAttributeUse(uses.at(i)); + } + } + + // handle attribute wildcards: @see http://www.w3.org/TR/xmlschema11-1/#dcl.ctd.anyatt + + // 1 + const XsdWildcard::Ptr completeWildcard(complexType->attributeWildcard()); + + if (complexType->derivationMethod() == XsdComplexType::DerivationRestriction) { + if (complexType->wxsSuperType()->isComplexType() && complexType->wxsSuperType()->isDefinedBySchema()) { + const XsdComplexType::Ptr complexBaseType(complexType->wxsSuperType()); + if (complexType->attributeWildcard()) { + if (complexBaseType->attributeWildcard()) { + if (!isValidWildcardRestriction(complexType->attributeWildcard(), complexBaseType->attributeWildcard())) { + m_context->error(QtXmlPatterns::tr("attribute wildcard of %1 is not a valid restriction of attribute wildcard of base type %2") + .arg(formatType(m_namePool, complexType)) + .arg(formatType(m_namePool, complexBaseType)), + XsdSchemaContext::XSDError, sourceLocation(complexType)); + return; + } + } else { + m_context->error(QtXmlPatterns::tr("%1 has attribute wildcard but its base type %2 has not") + .arg(formatType(m_namePool, complexType)) + .arg(formatType(m_namePool, complexBaseType)), + XsdSchemaContext::XSDError, sourceLocation(complexType)); + return; + } + } + } + complexType->setAttributeWildcard(completeWildcard); // 2.1 + } else if (complexType->derivationMethod() == XsdComplexType::DerivationExtension) { + XsdWildcard::Ptr baseWildcard; // 2.2.1 + if (complexType->wxsSuperType()->isComplexType() && complexType->wxsSuperType()->isDefinedBySchema()) + baseWildcard = XsdComplexType::Ptr(complexType->wxsSuperType())->attributeWildcard(); // 2.2.1.1 + else + baseWildcard = XsdWildcard::Ptr(); // 2.2.1.2 + + if (!baseWildcard) { + complexType->setAttributeWildcard(completeWildcard); // 2.2.2.1 + } else if (!completeWildcard) { + complexType->setAttributeWildcard(baseWildcard); // 2.2.2.2 + } else { + XsdWildcard::Ptr unionWildcard = XsdSchemaHelper::wildcardUnion(completeWildcard, baseWildcard); + if (unionWildcard) { + unionWildcard->setProcessContents(completeWildcard->processContents()); + complexType->setAttributeWildcard(unionWildcard); // 2.2.2.3 + } else { + m_context->error(QtXmlPatterns::tr("union of attribute wildcard of type %1 and attribute wildcard of its base type %2 is not expressible") + .arg(formatType(m_namePool, complexType)) + .arg(formatType(m_namePool, complexBaseType)), + XsdSchemaContext::XSDError, sourceLocation(complexType)); + return; + } + } + } +} + +void XsdSchemaResolver::resolveEnumerationFacetValues() +{ + XsdSimpleType::List simpleTypes; + + // first collect the global simple types + const SchemaType::List types = m_schema->types(); + for (int i = 0; i < types.count(); ++i) { + if (types.at(i)->isSimpleType()) + simpleTypes.append(types.at(i)); + } + + // then collect all anonymous simple types + const SchemaType::List anonymousTypes = m_schema->anonymousTypes(); + for (int i = 0; i < anonymousTypes.count(); ++i) { + if (anonymousTypes.at(i)->isSimpleType()) + simpleTypes.append(anonymousTypes.at(i)); + } + // process all simple types + for (int i = 0; i < simpleTypes.count(); ++i) { + const XsdSimpleType::Ptr simpleType = simpleTypes.at(i); + + // we resolve the enumeration values only for xs:QName and xs:NOTATION based types + if (BuiltinTypes::xsQName->wxsTypeMatches(simpleType) || + BuiltinTypes::xsNOTATION->wxsTypeMatches(simpleType)) { + const XsdFacet::Hash facets = simpleType->facets(); + if (facets.contains(XsdFacet::Enumeration)) { + AtomicValue::List newValues; + + const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration); + const AtomicValue::List values = facet->multiValue(); + for (int j = 0; j < values.count(); ++j) { + const AtomicValue::Ptr value = values.at(j); + + Q_ASSERT(m_enumerationFacetValues.contains(value)); + const NamespaceSupport support( m_enumerationFacetValues.value(value) ); + + const QString qualifiedName = value->as<DerivedString<TypeString> >()->stringValue(); + if (!XPathHelper::isQName(qualifiedName)) { + m_context->error(QtXmlPatterns::tr("enumeration facet contains invalid content: {%1} is not a value of type %2") + .arg(formatData(qualifiedName)) + .arg(formatType(m_namePool, BuiltinTypes::xsQName)), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + + QXmlName qNameValue; + bool result = support.processName(qualifiedName, NamespaceSupport::ElementName, qNameValue); + if (!result) { + m_context->error(QtXmlPatterns::tr("namespace prefix of qualified name %1 is not defined").arg(formatData(qualifiedName)), + XsdSchemaContext::XSDError, sourceLocation(simpleType)); + return; + } + + newValues.append(QNameValue::fromValue(m_namePool, qNameValue)); + } + facet->setMultiValue(newValues); + } + } + } +} + +QSourceLocation XsdSchemaResolver::sourceLocation(const NamedSchemaComponent::Ptr component) const +{ + if (m_componentLocationHash.contains(component)) { + return m_componentLocationHash.value(component); + } else { + QSourceLocation location; + location.setLine(1); + location.setColumn(1); + location.setUri(QString::fromLatin1("dummyUri")); + + return location; + } +} + +XsdFacet::Hash XsdSchemaResolver::complexTypeFacets(const XsdComplexType::Ptr &complexType) const +{ + for (int i = 0; i < m_complexBaseTypes.count(); ++i) { + if (m_complexBaseTypes.at(i).complexType == complexType) + return m_complexBaseTypes.at(i).facets; + } + + return XsdFacet::Hash(); +} + +void XsdSchemaResolver::checkRedefinedGroups() +{ + for (int i = 0; i < m_redefinedGroups.count(); ++i) { + const RedefinedGroups item = m_redefinedGroups.at(i); + + // create dummy particles... + const XsdParticle::Ptr redefinedParticle(new XsdParticle()); + redefinedParticle->setTerm(item.redefinedGroup); + const XsdParticle::Ptr particle(new XsdParticle()); + particle->setTerm(item.group); + + // so that we can pass them to XsdParticleChecker::subsumes() + QString errorMsg; + if (!XsdParticleChecker::subsumes(particle, redefinedParticle, m_context, errorMsg)) { + m_context->error(QtXmlPatterns::tr("%1 element %2 is not a valid restriction of the %3 element it redefines: %4") + .arg(formatElement("group")) + .arg(formatData(item.redefinedGroup->displayName(m_namePool))) + .arg(formatElement("group")) + .arg(errorMsg), + XsdSchemaContext::XSDError, sourceLocation(item.redefinedGroup)); + return; + } + } +} + +void XsdSchemaResolver::checkRedefinedAttributeGroups() +{ + for (int i = 0; i < m_redefinedAttributeGroups.count(); ++i) { + const RedefinedAttributeGroups item = m_redefinedAttributeGroups.at(i); + + QString errorMsg; + if (!XsdSchemaHelper::isValidAttributeGroupRestriction(item.redefinedGroup, item.group, m_context, errorMsg)) { + m_context->error(QtXmlPatterns::tr("%1 element %2 is not a valid restriction of the %3 element it redefines: %4") + .arg(formatElement("attributeGroup")) + .arg(formatData(item.redefinedGroup->displayName(m_namePool))) + .arg(formatElement("attributeGroup")) + .arg(errorMsg), + XsdSchemaContext::XSDError, sourceLocation(item.redefinedGroup)); + return; + } + } +} + +AnySimpleType::Ptr XsdSchemaResolver::findPrimitiveType(const AnySimpleType::Ptr &type, QSet<AnySimpleType::Ptr> &visitedTypes) +{ + if (visitedTypes.contains(type)) { + // found invalid circular reference... + return AnySimpleType::Ptr(); + } else { + visitedTypes.insert(type); + } + + const QXmlName typeName = type->name(m_namePool); + if (typeName == BuiltinTypes::xsString->name(m_namePool) || + typeName == BuiltinTypes::xsBoolean->name(m_namePool) || + typeName == BuiltinTypes::xsFloat->name(m_namePool) || + typeName == BuiltinTypes::xsDouble->name(m_namePool) || + typeName == BuiltinTypes::xsDecimal->name(m_namePool) || + typeName == BuiltinTypes::xsDuration->name(m_namePool) || + typeName == BuiltinTypes::xsDateTime->name(m_namePool) || + typeName == BuiltinTypes::xsTime->name(m_namePool) || + typeName == BuiltinTypes::xsDate->name(m_namePool) || + typeName == BuiltinTypes::xsGYearMonth->name(m_namePool) || + typeName == BuiltinTypes::xsGYear->name(m_namePool) || + typeName == BuiltinTypes::xsGMonthDay->name(m_namePool) || + typeName == BuiltinTypes::xsGDay->name(m_namePool) || + typeName == BuiltinTypes::xsGMonth->name(m_namePool) || + typeName == BuiltinTypes::xsHexBinary->name(m_namePool) || + typeName == BuiltinTypes::xsBase64Binary->name(m_namePool) || + typeName == BuiltinTypes::xsAnyURI->name(m_namePool) || + typeName == BuiltinTypes::xsQName->name(m_namePool) || + typeName == BuiltinTypes::xsNOTATION->name(m_namePool) || + typeName == BuiltinTypes::xsAnySimpleType->name(m_namePool)) + return type; + else { + if (type->wxsSuperType()) + return findPrimitiveType(type->wxsSuperType(), visitedTypes); + else { + return AnySimpleType::Ptr(); + } + } +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdschemaresolver_p.h b/src/xmlpatterns/schema/qxsdschemaresolver_p.h new file mode 100644 index 0000000..60901b5 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdschemaresolver_p.h @@ -0,0 +1,578 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdSchemaResolver_H +#define Patternist_XsdSchemaResolver_H + +#include "qnamespacesupport_p.h" +#include "qschematype_p.h" +#include "qschematypefactory_p.h" +#include "qxsdalternative_p.h" +#include "qxsdattribute_p.h" +#include "qxsdattributegroup_p.h" +#include "qxsdelement_p.h" +#include "qxsdmodelgroup_p.h" +#include "qxsdnotation_p.h" +#include "qxsdreference_p.h" +#include "qxsdschema_p.h" +#include "qxsdschemachecker_p.h" +#include "qxsdsimpletype_p.h" + +#include <QtCore/QExplicitlySharedDataPointer> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + class XsdSchemaContext; + class XsdSchemaParserContext; + + /** + * @short Encapsulates the resolving of type/element references in a schema after parsing has finished. + * + * This class collects task for resolving types or element references. After the parsing has finished, + * one can start the resolve process by calling resolve(). + * + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdSchemaResolver : public QSharedData + { + public: + typedef QExplicitlySharedDataPointer<XsdSchemaResolver> Ptr; + + /** + * Creates a new schema resolver. + * + * @param context The schema context used for error reporting etc.. + * @param parserContext The schema parser context where all objects to resolve belong to. + */ + XsdSchemaResolver(const QExplicitlySharedDataPointer<XsdSchemaContext> &context, const XsdSchemaParserContext *parserContext); + + /** + * Destroys the schema resolver. + */ + ~XsdSchemaResolver(); + + /** + * Starts the resolve process. + */ + void resolve(); + + /** + * Adds a resolve task for key references. + * + * The resolver will try to set the referencedKey property of @p keyRef to the <em>key</em> or <em>unique</em> object + * of @p element that has the given @p name. + */ + void addKeyReference(const XsdElement::Ptr &element, const XsdIdentityConstraint::Ptr &keyRef, const QXmlName &name, const QSourceLocation &location); + + /** + * Adds a resolve task for the base type of restriction of a simple type. + * + * The resolver will set the base type of @p simpleType to the type named by @p baseName. + */ + void addSimpleRestrictionBase(const XsdSimpleType::Ptr &simpleType, const QXmlName &baseName, const QSourceLocation &location); + + /** + * Removes the resolve task for the base type of restriction of the simple @p type. + */ + void removeSimpleRestrictionBase(const XsdSimpleType::Ptr &type); + + /** + * Adds a resolve task for the list type of a simple type. + * + * The resolver will set the itemType property of @p simpleType to the type named by @p typeName. + */ + void addSimpleListType(const XsdSimpleType::Ptr &simpleType, const QXmlName &typeName, const QSourceLocation &location); + + /** + * Adds a resolve task for the member types of a simple type. + * + * The resolver will set the memberTypes property of @p simpleType to the types named by @p typeNames. + */ + void addSimpleUnionTypes(const XsdSimpleType::Ptr &simpleType, const QList<QXmlName> &typeNames, const QSourceLocation &location); + + /** + * Adds a resolve task for the type of an element. + * + * The resolver will set the type of the @p element to the type named by @p typeName. + */ + void addElementType(const XsdElement::Ptr &element, const QXmlName &typeName, const QSourceLocation &location); + + /** + * Adds a resolve task for the base type of a complex type. + * + * The resolver will set the base type of @p complexType to the type named by @p baseName. + */ + void addComplexBaseType(const XsdComplexType::Ptr &complexType, const QXmlName &baseName, const QSourceLocation &location, const XsdFacet::Hash &facets = XsdFacet::Hash()); + + /** + * Removes the resolve task for the base type of the complex @p type. + */ + void removeComplexBaseType(const XsdComplexType::Ptr &type); + + /** + * Adds a resolve task for the content type of a complex type. + * + * The resolver will set the content type properties for @p complexType based on the + * given explicit @p content and effective @p mixed value. + */ + void addComplexContentType(const XsdComplexType::Ptr &complexType, const XsdParticle::Ptr &content, bool mixed); + + /** + * Adds a resolve task for the type of an attribute. + * + * The resolver will set the type of the @p attribute to the type named by @p typeName. + */ + void addAttributeType(const XsdAttribute::Ptr &attribute, const QXmlName &typeName, const QSourceLocation &location); + + /** + * Adds a resolve task for the type of an alternative. + * + * The resolver will set the type of the @p alternative to the type named by @p typeName. + */ + void addAlternativeType(const XsdAlternative::Ptr &alternative, const QXmlName &typeName, const QSourceLocation &location); + + /** + * Adds a resolve task for the type of an alternative. + * + * The resolver will set the type of the @p alternative to the type of the @p element after + * the type of the @p element has been resolved. + */ + void addAlternativeType(const XsdAlternative::Ptr &alternative, const XsdElement::Ptr &element); + + /** + * Adds a resolve task for the substituion group affiliations of an element. + * + * The resolver will set the substitution group affiliations of the @p element to the + * top-level element named by @p elementNames. + */ + void addSubstitutionGroupAffiliation(const XsdElement::Ptr &element, const QList<QXmlName> &elementName, const QSourceLocation &location); + + /** + * Adds a resolve task for an element that has no type specified, only a substitution group + * affiliation. + * + * The resolver will set the type of the substitution group affiliation as type for the element. + */ + void addSubstitutionGroupType(const XsdElement::Ptr &element); + + /** + * Adds the component location hash, so the resolver is able to report meaning full + * error messages. + */ + void addComponentLocationHash(const QHash<NamedSchemaComponent::Ptr, QSourceLocation> &hash); + + /** + * Add a resolve task for enumeration facet values. + * + * In case the enumeration is of type QName or NOTATION, we have to resolve the QName later, + * so we store the namespace bindings together with the facet value here and resolve it as soon as + * we have all type information available. + */ + void addEnumerationFacetValue(const AtomicValue::Ptr &facetValue, const NamespaceSupport &namespaceSupport); + + /** + * Add a check job for redefined groups. + * + * When an element group is redefined, we have to check whether the redefined group is a valid + * restriction of the group it redefines. As we need all type information for that, we keep them + * here for later checking. + */ + void addRedefinedGroups(const XsdModelGroup::Ptr &redefinedGroup, const XsdModelGroup::Ptr &group); + + /** + * Add a check job for redefined attribute groups. + * + * When an attribute group is redefined, we have to check whether the redefined group is a valid + * restriction of the group it redefines. As we need all type information for that, we keep them + * here for later checking. + */ + void addRedefinedAttributeGroups(const XsdAttributeGroup::Ptr &redefinedGroup, const XsdAttributeGroup::Ptr &group); + + /** + * Adds a check for nested <em>all</em> groups. + */ + void addAllGroupCheck(const XsdReference::Ptr &reference); + + /** + * Copies the data to resolve to an @p other resolver. + * + * @note That functionality is only used by the redefine algorithm in the XsdSchemaParser. + */ + void copyDataTo(const XsdSchemaResolver::Ptr &other) const; + + /** + * Returns the to resolve base type name for the given @p type. + * + * @note That functionality is only used by the redefine algorithm in the XsdSchemaParser. + */ + QXmlName baseTypeNameOfType(const SchemaType::Ptr &type) const; + + /** + * Returns the to resolve type name for the given @p attribute. + * + * @note That functionality is only used by the redefine algorithm in the XsdSchemaParser. + */ + QXmlName typeNameOfAttribute(const XsdAttribute::Ptr &attribute) const; + + /** + * Sets the defaultOpenContent object from the schema parser. + */ + void setDefaultOpenContent(const XsdComplexType::OpenContent::Ptr &openContent, bool appliesToEmpty); + + private: + /** + * Resolves key references. + */ + void resolveKeyReferences(); + + /** + * Resolves the base types of simple types derived by restriction. + */ + void resolveSimpleRestrictionBaseTypes(); + + /** + * Resolves the other properties except the base type + * of all simple restrictions. + */ + void resolveSimpleRestrictions(); + + /** + * Resolves the other properties except the base type + * of the given simple restriction. + * + * @param simpleType The restricted type to resolve. + * @param visitedTypes A set of already resolved types, used for termination of recursion. + */ + void resolveSimpleRestrictions(const XsdSimpleType::Ptr &simpleType, QSet<XsdSimpleType::Ptr> &visitedTypes); + + /** + * Resolves the item type property of simple types derived by list. + */ + void resolveSimpleListType(); + + /** + * Resolves the member types property of simple types derived by union. + */ + void resolveSimpleUnionTypes(); + + /** + * Resolves element types. + */ + void resolveElementTypes(); + + /** + * Resolves base type of complex types. + */ + void resolveComplexBaseTypes(); + + /** + * Resolves the simple content model of a complex type + * depending on its base type. + */ + void resolveSimpleContentComplexTypes(); + + /** + * Resolves the complex content model of a complex type + * depending on its base type. + */ + void resolveComplexContentComplexTypes(); + + /** + * Resolves the simple content model of a complex type + * depending on its base type. + * + * @param complexType The complex type to resolve. + * @param visitedTypes A set of already resolved types, used for termination of recursion. + */ + void resolveSimpleContentComplexTypes(const XsdComplexType::Ptr &complexType, QSet<XsdComplexType::Ptr> &visitedTypes); + + /** + * Resolves the complex content model of a complex type + * depending on its base type. + * + * @param complexType The complex type to resolve. + * @param visitedTypes A set of already resolved types, used for termination of recursion. + */ + void resolveComplexContentComplexTypes(const XsdComplexType::Ptr &complexType, QSet<XsdComplexType::Ptr> &visitedTypes); + + /** + * Resolves attribute types. + */ + void resolveAttributeTypes(); + + /** + * Resolves alternative types. + */ + void resolveAlternativeTypes(); + + /** + * Resolves substitution group affiliations. + */ + void resolveSubstitutionGroupAffiliations(); + + /** + * Resolves substitution groups. + */ + void resolveSubstitutionGroups(); + + /** + * Resolves all XsdReferences in the schema by their corresponding XsdElement or XsdModelGroup terms. + */ + void resolveTermReferences(); + + /** + * Resolves all XsdReferences in the @p particle recursive by their corresponding XsdElement or XsdModelGroup terms. + */ + void resolveTermReference(const XsdParticle::Ptr &particle, QSet<QXmlName> visitedGroups); + + /** + * Resolves all XsdAttributeReferences in the schema by their corresponding XsdAttributeUse objects. + */ + void resolveAttributeTermReferences(); + + /** + * Resolves all XsdAttributeReferences in the list of @p attributeUses by their corresponding XsdAttributeUse objects. + */ + XsdAttributeUse::List resolveAttributeTermReferences(const XsdAttributeUse::List &attributeUses, XsdWildcard::Ptr &wildcard, QSet<QXmlName> visitedAttributeGroups); + + /** + * Resolves the attribute inheritance of complex types. + * + * @note This method must be called after all base types have been resolved. + */ + void resolveAttributeInheritance(); + + /** + * Resolves the attribute inheritance of the given complex types. + * + * @param complexType The complex type to resolve. + * @param visitedTypes A set of already resolved types, used for termination of recursion. + * + * @note This method must be called after all base types have been resolved. + */ + void resolveAttributeInheritance(const XsdComplexType::Ptr &complexType, QSet<XsdComplexType::Ptr> &visitedTypes); + + /** + * Resolves the enumeration facet values for QName and NOTATION based facets. + */ + void resolveEnumerationFacetValues(); + + /** + * Returns the source location of the given schema @p component or a dummy + * source location if the component is not found in the component location hash. + */ + QSourceLocation sourceLocation(const NamedSchemaComponent::Ptr component) const; + + /** + * Returns the facets that are marked for the given complex @p type with a simple + * type restriction. + */ + XsdFacet::Hash complexTypeFacets(const XsdComplexType::Ptr &complexType) const; + + /** + * Finds the primitive type for the given simple @p type. + * + * The type is found by walking up the inheritance tree, until one of the builtin + * primitive type definitions is reached. + */ + AnySimpleType::Ptr findPrimitiveType(const AnySimpleType::Ptr &type, QSet<AnySimpleType::Ptr> &visitedTypes); + + /** + * Checks the redefined groups. + */ + void checkRedefinedGroups(); + + /** + * Checks the redefined attribute groups. + */ + void checkRedefinedAttributeGroups(); + + class KeyReference + { + public: + XsdElement::Ptr element; + XsdIdentityConstraint::Ptr keyRef; + QXmlName reference; + QSourceLocation location; + }; + + class SimpleRestrictionBase + { + public: + XsdSimpleType::Ptr simpleType; + QXmlName baseName; + QSourceLocation location; + }; + + class SimpleListType + { + public: + XsdSimpleType::Ptr simpleType; + QXmlName typeName; + QSourceLocation location; + }; + + class SimpleUnionType + { + public: + XsdSimpleType::Ptr simpleType; + QList<QXmlName> typeNames; + QSourceLocation location; + }; + + class ElementType + { + public: + XsdElement::Ptr element; + QXmlName typeName; + QSourceLocation location; + }; + + class ComplexBaseType + { + public: + XsdComplexType::Ptr complexType; + QXmlName baseName; + QSourceLocation location; + XsdFacet::Hash facets; + }; + + class ComplexContentType + { + public: + XsdComplexType::Ptr complexType; + XsdParticle::Ptr explicitContent; + bool effectiveMixed; + }; + + class AttributeType + { + public: + XsdAttribute::Ptr attribute; + QXmlName typeName; + QSourceLocation location; + }; + + class AlternativeType + { + public: + XsdAlternative::Ptr alternative; + QXmlName typeName; + QSourceLocation location; + }; + + class AlternativeTypeElement + { + public: + XsdAlternative::Ptr alternative; + XsdElement::Ptr element; + }; + + class SubstitutionGroupAffiliation + { + public: + XsdElement::Ptr element; + QList<QXmlName> elementNames; + QSourceLocation location; + }; + + class RedefinedGroups + { + public: + XsdModelGroup::Ptr redefinedGroup; + XsdModelGroup::Ptr group; + }; + + class RedefinedAttributeGroups + { + public: + XsdAttributeGroup::Ptr redefinedGroup; + XsdAttributeGroup::Ptr group; + }; + + QVector<KeyReference> m_keyReferences; + QVector<SimpleRestrictionBase> m_simpleRestrictionBases; + QVector<SimpleListType> m_simpleListTypes; + QVector<SimpleUnionType> m_simpleUnionTypes; + QVector<ElementType> m_elementTypes; + QVector<ComplexBaseType> m_complexBaseTypes; + QVector<ComplexContentType> m_complexContentTypes; + QVector<AttributeType> m_attributeTypes; + QVector<AlternativeType> m_alternativeTypes; + QVector<AlternativeTypeElement> m_alternativeTypeElements; + QVector<SubstitutionGroupAffiliation> m_substitutionGroupAffiliations; + QVector<XsdElement::Ptr> m_substitutionGroupTypes; + QVector<RedefinedGroups> m_redefinedGroups; + QVector<RedefinedAttributeGroups> m_redefinedAttributeGroups; + QHash<AtomicValue::Ptr, NamespaceSupport> m_enumerationFacetValues; + QSet<XsdReference::Ptr> m_allGroups; + + QExplicitlySharedDataPointer<XsdSchemaContext> m_context; + QExplicitlySharedDataPointer<XsdSchemaChecker> m_checker; + NamePool::Ptr m_namePool; + XsdSchema::Ptr m_schema; + QHash<NamedSchemaComponent::Ptr, QSourceLocation> m_componentLocationHash; + XsdComplexType::OpenContent::Ptr m_defaultOpenContent; + bool m_defaultOpenContentAppliesToEmpty; + SchemaType::List m_predefinedSchemaTypes; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdschematoken.cpp b/src/xmlpatterns/schema/qxsdschematoken.cpp new file mode 100644 index 0000000..b462731 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdschematoken.cpp @@ -0,0 +1,2981 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* NOTE: This file is AUTO GENERATED by qautomaton2cpp.xsl. */ + +#include "qxsdschematoken_p.h" + +QT_BEGIN_NAMESPACE + +XsdSchemaToken::NodeName XsdSchemaToken::classifier2(const QChar *data) + + { + + static const unsigned short string[] = + { + 105, 100 + }; + if(memcmp(&data[0], &string, sizeof(QChar) * 2) == 0) + + + return Id; + + + return NoKeyword; + } + XsdSchemaToken::NodeName XsdSchemaToken::classifier3(const QChar *data) + + { + if (data[0] == 97) + + + { + if (data[1] == 108) + + + { + + if(data[2] == 108) + + + return All; + + } + + else if (data[1] == 110) + + + { + + if(data[2] == 121) + + + return Any; + + } + + + } + + else if (data[0] == 107) + + + { + + static const unsigned short string[] = + { + 101, 121 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 2) == 0) + + + return Key; + + } + + else if (data[0] == 114) + + + { + + static const unsigned short string[] = + { + 101, 102 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 2) == 0) + + + return Ref; + + } + + else if (data[0] == 117) + + + { + + static const unsigned short string[] = + { + 115, 101 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 2) == 0) + + + return Use; + + } + + + + return NoKeyword; + } + XsdSchemaToken::NodeName XsdSchemaToken::classifier4(const QChar *data) + + { + if (data[0] == 98) + + + { + + static const unsigned short string[] = + { + 97, 115, 101 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 3) == 0) + + + return Base; + + } + + else if (data[0] == 102) + + + { + + static const unsigned short string[] = + { + 111, 114, 109 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 3) == 0) + + + return Form; + + } + + else if (data[0] == 108) + + + { + + static const unsigned short string[] = + { + 105, 115, 116 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 3) == 0) + + + return List; + + } + + else if (data[0] == 109) + + + { + + static const unsigned short string[] = + { + 111, 100, 101 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 3) == 0) + + + return Mode; + + } + + else if (data[0] == 110) + + + { + + static const unsigned short string[] = + { + 97, 109, 101 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 3) == 0) + + + return Name; + + } + + else if (data[0] == 116) + + + { + if (data[1] == 101) + + + { + + static const unsigned short string[] = + { + 115, 116 + }; + if(memcmp(&data[2], &string, sizeof(QChar) * 2) == 0) + + + return Test; + + } + + else if (data[1] == 121) + + + { + + static const unsigned short string[] = + { + 112, 101 + }; + if(memcmp(&data[2], &string, sizeof(QChar) * 2) == 0) + + + return Type; + + } + + + } + + + + return NoKeyword; + } + XsdSchemaToken::NodeName XsdSchemaToken::classifier5(const QChar *data) + + { + if (data[0] == 98) + + + { + + static const unsigned short string[] = + { + 108, 111, 99, 107 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 4) == 0) + + + return Block; + + } + + else if (data[0] == 102) + + + { + if (data[1] == 105) + + + { + if (data[2] == 101) + + + { + + static const unsigned short string[] = + { + 108, 100 + }; + if(memcmp(&data[3], &string, sizeof(QChar) * 2) == 0) + + + return Field; + + } + + else if (data[2] == 110) + + + { + + static const unsigned short string[] = + { + 97, 108 + }; + if(memcmp(&data[3], &string, sizeof(QChar) * 2) == 0) + + + return Final; + + } + + else if (data[2] == 120) + + + { + + static const unsigned short string[] = + { + 101, 100 + }; + if(memcmp(&data[3], &string, sizeof(QChar) * 2) == 0) + + + return Fixed; + + } + + + } + + + } + + else if (data[0] == 103) + + + { + + static const unsigned short string[] = + { + 114, 111, 117, 112 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 4) == 0) + + + return Group; + + } + + else if (data[0] == 109) + + + { + + static const unsigned short string[] = + { + 105, 120, 101, 100 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 4) == 0) + + + return Mixed; + + } + + else if (data[0] == 114) + + + { + + static const unsigned short string[] = + { + 101, 102, 101, 114 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 4) == 0) + + + return Refer; + + } + + else if (data[0] == 117) + + + { + + static const unsigned short string[] = + { + 110, 105, 111, 110 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 4) == 0) + + + return Union; + + } + + else if (data[0] == 118) + + + { + + static const unsigned short string[] = + { + 97, 108, 117, 101 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 4) == 0) + + + return Value; + + } + + else if (data[0] == 120) + + + { + + static const unsigned short string[] = + { + 112, 97, 116, 104 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 4) == 0) + + + return Xpath; + + } + + + + return NoKeyword; + } + XsdSchemaToken::NodeName XsdSchemaToken::classifier6(const QChar *data) + + { + if (data[0] == 97) + + + { + + static const unsigned short string[] = + { + 115, 115, 101, 114, 116 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 5) == 0) + + + return Assert; + + } + + else if (data[0] == 99) + + + { + + static const unsigned short string[] = + { + 104, 111, 105, 99, 101 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 5) == 0) + + + return Choice; + + } + + else if (data[0] == 105) + + + { + + static const unsigned short string[] = + { + 109, 112, 111, 114, 116 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 5) == 0) + + + return Import; + + } + + else if (data[0] == 107) + + + { + + static const unsigned short string[] = + { + 101, 121, 114, 101, 102 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 5) == 0) + + + return Keyref; + + } + + else if (data[0] == 108) + + + { + + static const unsigned short string[] = + { + 101, 110, 103, 116, 104 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 5) == 0) + + + return Length; + + } + + else if (data[0] == 112) + + + { + + static const unsigned short string[] = + { + 117, 98, 108, 105, 99 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 5) == 0) + + + return Public; + + } + + else if (data[0] == 115) + + + { + if (data[1] == 99) + + + { + + static const unsigned short string[] = + { + 104, 101, 109, 97 + }; + if(memcmp(&data[2], &string, sizeof(QChar) * 4) == 0) + + + return Schema; + + } + + else if (data[1] == 111) + + + { + + static const unsigned short string[] = + { + 117, 114, 99, 101 + }; + if(memcmp(&data[2], &string, sizeof(QChar) * 4) == 0) + + + return Source; + + } + + else if (data[1] == 121) + + + { + + static const unsigned short string[] = + { + 115, 116, 101, 109 + }; + if(memcmp(&data[2], &string, sizeof(QChar) * 4) == 0) + + + return System; + + } + + + } + + else if (data[0] == 117) + + + { + + static const unsigned short string[] = + { + 110, 105, 113, 117, 101 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 5) == 0) + + + return Unique; + + } + + + + return NoKeyword; + } + XsdSchemaToken::NodeName XsdSchemaToken::classifier7(const QChar *data) + + { + if (data[0] == 97) + + + { + + static const unsigned short string[] = + { + 112, 112, 105, 110, 102, 111 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 6) == 0) + + + return Appinfo; + + } + + else if (data[0] == 100) + + + { + + static const unsigned short string[] = + { + 101, 102, 97, 117, 108, 116 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 6) == 0) + + + return Default; + + } + + else if (data[0] == 101) + + + { + + static const unsigned short string[] = + { + 108, 101, 109, 101, 110, 116 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 6) == 0) + + + return Element; + + } + + else if (data[0] == 105) + + + { + + static const unsigned short string[] = + { + 110, 99, 108, 117, 100, 101 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 6) == 0) + + + return Include; + + } + + else if (data[0] == 112) + + + { + + static const unsigned short string[] = + { + 97, 116, 116, 101, 114, 110 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 6) == 0) + + + return Pattern; + + } + + else if (data[0] == 114) + + + { + + static const unsigned short string[] = + { + 101, 112, 108, 97, 99, 101 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 6) == 0) + + + return Replace; + + } + + else if (data[0] == 118) + + + { + + static const unsigned short string[] = + { + 101, 114, 115, 105, 111, 110 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 6) == 0) + + + return Version; + + } + + + + return NoKeyword; + } + XsdSchemaToken::NodeName XsdSchemaToken::classifier8(const QChar *data) + + { + if (data[0] == 97) + + + { + + static const unsigned short string[] = + { + 98, 115, 116, 114, 97, 99, 116 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 7) == 0) + + + return Abstract; + + } + + else if (data[0] == 99) + + + { + + static const unsigned short string[] = + { + 111, 108, 108, 97, 112, 115, 101 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 7) == 0) + + + return Collapse; + + } + + else if (data[0] == 105) + + + { + + static const unsigned short string[] = + { + 116, 101, 109, 84, 121, 112, 101 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 7) == 0) + + + return ItemType; + + } + + else if (data[0] == 110) + + + { + if (data[1] == 105) + + + { + + static const unsigned short string[] = + { + 108, 108, 97, 98, 108, 101 + }; + if(memcmp(&data[2], &string, sizeof(QChar) * 6) == 0) + + + return Nillable; + + } + + else if (data[1] == 111) + + + { + if (data[2] == 116) + + + { + if (data[3] == 97) + + + { + + static const unsigned short string[] = + { + 116, 105, 111, 110 + }; + if(memcmp(&data[4], &string, sizeof(QChar) * 4) == 0) + + + return Notation; + + } + + else if (data[3] == 81) + + + { + + static const unsigned short string[] = + { + 78, 97, 109, 101 + }; + if(memcmp(&data[4], &string, sizeof(QChar) * 4) == 0) + + + return NotQName; + + } + + + } + + + } + + + } + + else if (data[0] == 111) + + + { + + static const unsigned short string[] = + { + 118, 101, 114, 114, 105, 100, 101 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 7) == 0) + + + return Override; + + } + + else if (data[0] == 112) + + + { + + static const unsigned short string[] = + { + 114, 101, 115, 101, 114, 118, 101 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 7) == 0) + + + return Preserve; + + } + + else if (data[0] == 114) + + + { + + static const unsigned short string[] = + { + 101, 100, 101, 102, 105, 110, 101 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 7) == 0) + + + return Redefine; + + } + + else if (data[0] == 115) + + + { + if (data[1] == 101) + + + { + if (data[2] == 108) + + + { + + static const unsigned short string[] = + { + 101, 99, 116, 111, 114 + }; + if(memcmp(&data[3], &string, sizeof(QChar) * 5) == 0) + + + return Selector; + + } + + else if (data[2] == 113) + + + { + + static const unsigned short string[] = + { + 117, 101, 110, 99, 101 + }; + if(memcmp(&data[3], &string, sizeof(QChar) * 5) == 0) + + + return Sequence; + + } + + + } + + + } + + else if (data[0] == 120) + + + { + + static const unsigned short string[] = + { + 109, 108, 58, 108, 97, 110, 103 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 7) == 0) + + + return XmlLanguage; + + } + + + + return NoKeyword; + } + XsdSchemaToken::NodeName XsdSchemaToken::classifier9(const QChar *data) + + { + if (data[0] == 97) + + + { + if (data[1] == 115) + + + { + + static const unsigned short string[] = + { + 115, 101, 114, 116, 105, 111, 110 + }; + if(memcmp(&data[2], &string, sizeof(QChar) * 7) == 0) + + + return Assertion; + + } + + else if (data[1] == 116) + + + { + + static const unsigned short string[] = + { + 116, 114, 105, 98, 117, 116, 101 + }; + if(memcmp(&data[2], &string, sizeof(QChar) * 7) == 0) + + + return Attribute; + + } + + + } + + else if (data[0] == 101) + + + { + + static const unsigned short string[] = + { + 120, 116, 101, 110, 115, 105, 111, 110 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 8) == 0) + + + return Extension; + + } + + else if (data[0] == 109) + + + { + if (data[1] == 97) + + + { + if (data[2] == 120) + + + { + if (data[3] == 76) + + + { + + static const unsigned short string[] = + { + 101, 110, 103, 116, 104 + }; + if(memcmp(&data[4], &string, sizeof(QChar) * 5) == 0) + + + return MaxLength; + + } + + else if (data[3] == 79) + + + { + + static const unsigned short string[] = + { + 99, 99, 117, 114, 115 + }; + if(memcmp(&data[4], &string, sizeof(QChar) * 5) == 0) + + + return MaxOccurs; + + } + + + } + + + } + + else if (data[1] == 105) + + + { + if (data[2] == 110) + + + { + if (data[3] == 76) + + + { + + static const unsigned short string[] = + { + 101, 110, 103, 116, 104 + }; + if(memcmp(&data[4], &string, sizeof(QChar) * 5) == 0) + + + return MinLength; + + } + + else if (data[3] == 79) + + + { + + static const unsigned short string[] = + { + 99, 99, 117, 114, 115 + }; + if(memcmp(&data[4], &string, sizeof(QChar) * 5) == 0) + + + return MinOccurs; + + } + + + } + + + } + + + } + + else if (data[0] == 110) + + + { + + static const unsigned short string[] = + { + 97, 109, 101, 115, 112, 97, 99, 101 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 8) == 0) + + + return Namespace; + + } + + + + return NoKeyword; + } + XsdSchemaToken::NodeName XsdSchemaToken::classifier10(const QChar *data) + + { + if (data[0] == 97) + + + { + + static const unsigned short string[] = + { + 110, 110, 111, 116, 97, 116, 105, 111, 110 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 9) == 0) + + + return Annotation; + + } + + else if (data[0] == 115) + + + { + + static const unsigned short string[] = + { + 105, 109, 112, 108, 101, 84, 121, 112, 101 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 9) == 0) + + + return SimpleType; + + } + + else if (data[0] == 119) + + + { + + static const unsigned short string[] = + { + 104, 105, 116, 101, 83, 112, 97, 99, 101 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 9) == 0) + + + return WhiteSpace; + + } + + + + return NoKeyword; + } + XsdSchemaToken::NodeName XsdSchemaToken::classifier11(const QChar *data) + + { + if (data[0] == 97) + + + { + + static const unsigned short string[] = + { + 108, 116, 101, 114, 110, 97, 116, 105, 118, 101 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 10) == 0) + + + return Alternative; + + } + + else if (data[0] == 99) + + + { + + static const unsigned short string[] = + { + 111, 109, 112, 108, 101, 120, 84, 121, 112, 101 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 10) == 0) + + + return ComplexType; + + } + + else if (data[0] == 101) + + + { + + static const unsigned short string[] = + { + 110, 117, 109, 101, 114, 97, 116, 105, 111, 110 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 10) == 0) + + + return Enumeration; + + } + + else if (data[0] == 109) + + + { + + static const unsigned short string[] = + { + 101, 109, 98, 101, 114, 84, 121, 112, 101, 115 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 10) == 0) + + + return MemberTypes; + + } + + else if (data[0] == 111) + + + { + + static const unsigned short string[] = + { + 112, 101, 110, 67, 111, 110, 116, 101, 110, 116 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 10) == 0) + + + return OpenContent; + + } + + else if (data[0] == 114) + + + { + + static const unsigned short string[] = + { + 101, 115, 116, 114, 105, 99, 116, 105, 111, 110 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 10) == 0) + + + return Restriction; + + } + + else if (data[0] == 116) + + + { + + static const unsigned short string[] = + { + 111, 116, 97, 108, 68, 105, 103, 105, 116, 115 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 10) == 0) + + + return TotalDigits; + + } + + + + return NoKeyword; + } + XsdSchemaToken::NodeName XsdSchemaToken::classifier12(const QChar *data) + + { + if (data[0] == 97) + + + { + + static const unsigned short string[] = + { + 110, 121, 65, 116, 116, 114, 105, 98, 117, 116, 101 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 11) == 0) + + + return AnyAttribute; + + } + + else if (data[0] == 98) + + + { + + static const unsigned short string[] = + { + 108, 111, 99, 107, 68, 101, 102, 97, 117, 108, 116 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 11) == 0) + + + return BlockDefault; + + } + + else if (data[0] == 102) + + + { + + static const unsigned short string[] = + { + 105, 110, 97, 108, 68, 101, 102, 97, 117, 108, 116 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 11) == 0) + + + return FinalDefault; + + } + + else if (data[0] == 109) + + + { + if (data[1] == 97) + + + { + if (data[2] == 120) + + + { + if (data[3] == 69) + + + { + + static const unsigned short string[] = + { + 120, 99, 108, 117, 115, 105, 118, 101 + }; + if(memcmp(&data[4], &string, sizeof(QChar) * 8) == 0) + + + return MaxExclusive; + + } + + else if (data[3] == 73) + + + { + + static const unsigned short string[] = + { + 110, 99, 108, 117, 115, 105, 118, 101 + }; + if(memcmp(&data[4], &string, sizeof(QChar) * 8) == 0) + + + return MaxInclusive; + + } + + + } + + + } + + else if (data[1] == 105) + + + { + if (data[2] == 110) + + + { + if (data[3] == 69) + + + { + + static const unsigned short string[] = + { + 120, 99, 108, 117, 115, 105, 118, 101 + }; + if(memcmp(&data[4], &string, sizeof(QChar) * 8) == 0) + + + return MinExclusive; + + } + + else if (data[3] == 73) + + + { + + static const unsigned short string[] = + { + 110, 99, 108, 117, 115, 105, 118, 101 + }; + if(memcmp(&data[4], &string, sizeof(QChar) * 8) == 0) + + + return MinInclusive; + + } + + + } + + + } + + + } + + else if (data[0] == 110) + + + { + + static const unsigned short string[] = + { + 111, 116, 78, 97, 109, 101, 115, 112, 97, 99, 101 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 11) == 0) + + + return NotNamespace; + + } + + + + return NoKeyword; + } + XsdSchemaToken::NodeName XsdSchemaToken::classifier13(const QChar *data) + + { + if (data[0] == 100) + + + { + + static const unsigned short string[] = + { + 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 12) == 0) + + + return Documentation; + + } + + else if (data[0] == 115) + + + { + + static const unsigned short string[] = + { + 105, 109, 112, 108, 101, 67, 111, 110, 116, 101, 110, 116 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 12) == 0) + + + return SimpleContent; + + } + + + + return NoKeyword; + } + XsdSchemaToken::NodeName XsdSchemaToken::classifier14(const QChar *data) + + { + if (data[0] == 97) + + + { + if (data[1] == 112) + + + { + + static const unsigned short string[] = + { + 112, 108, 105, 101, 115, 84, 111, 69, 109, 112, 116, 121 + }; + if(memcmp(&data[2], &string, sizeof(QChar) * 12) == 0) + + + return AppliesToEmpty; + + } + + else if (data[1] == 116) + + + { + + static const unsigned short string[] = + { + 116, 114, 105, 98, 117, 116, 101, 71, 114, 111, 117, 112 + }; + if(memcmp(&data[2], &string, sizeof(QChar) * 12) == 0) + + + return AttributeGroup; + + } + + + } + + else if (data[0] == 99) + + + { + + static const unsigned short string[] = + { + 111, 109, 112, 108, 101, 120, 67, 111, 110, 116, 101, 110, 116 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 13) == 0) + + + return ComplexContent; + + } + + else if (data[0] == 102) + + + { + + static const unsigned short string[] = + { + 114, 97, 99, 116, 105, 111, 110, 68, 105, 103, 105, 116, 115 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 13) == 0) + + + return FractionDigits; + + } + + else if (data[0] == 115) + + + { + + static const unsigned short string[] = + { + 99, 104, 101, 109, 97, 76, 111, 99, 97, 116, 105, 111, 110 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 13) == 0) + + + return SchemaLocation; + + } + + + + return NoKeyword; + } + XsdSchemaToken::NodeName XsdSchemaToken::classifier15(const QChar *data) + + { + if (data[0] == 112) + + + { + + static const unsigned short string[] = + { + 114, 111, 99, 101, 115, 115, 67, 111, 110, 116, 101, 110, 116, 115 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 14) == 0) + + + return ProcessContents; + + } + + else if (data[0] == 116) + + + { + + static const unsigned short string[] = + { + 97, 114, 103, 101, 116, 78, 97, 109, 101, 115, 112, 97, 99, 101 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 14) == 0) + + + return TargetNamespace; + + } + + + + return NoKeyword; + } + XsdSchemaToken::NodeName XsdSchemaToken::classifier17(const QChar *data) + + { + if (data[0] == 100) + + + { + + static const unsigned short string[] = + { + 101, 102, 97, 117, 108, 116, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 16) == 0) + + + return DefaultAttributes; + + } + + else if (data[0] == 115) + + + { + + static const unsigned short string[] = + { + 117, 98, 115, 116, 105, 116, 117, 116, 105, 111, 110, 71, 114, 111, 117, 112 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 16) == 0) + + + return SubstitutionGroup; + + } + + + + return NoKeyword; + } + XsdSchemaToken::NodeName XsdSchemaToken::classifier18(const QChar *data) + + { + if (data[0] == 100) + + + { + + static const unsigned short string[] = + { + 101, 102, 97, 117, 108, 116, 79, 112, 101, 110, 67, 111, 110, 116, 101, 110, 116 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 17) == 0) + + + return DefaultOpenContent; + + } + + else if (data[0] == 101) + + + { + + static const unsigned short string[] = + { + 108, 101, 109, 101, 110, 116, 70, 111, 114, 109, 68, 101, 102, 97, 117, 108, 116 + }; + if(memcmp(&data[1], &string, sizeof(QChar) * 17) == 0) + + + return ElementFormDefault; + + } + + + + return NoKeyword; + } + XsdSchemaToken::NodeName XsdSchemaToken::classifier20(const QChar *data) + + { + + static const unsigned short string[] = + { + 97, 116, 116, 114, 105, 98, 117, 116, 101, 70, 111, 114, 109, 68, 101, 102, 97, 117, 108, 116 + }; + if(memcmp(&data[0], &string, sizeof(QChar) * 20) == 0) + + + return AttributeFormDefault; + + + return NoKeyword; + } + XsdSchemaToken::NodeName XsdSchemaToken::classifier21(const QChar *data) + + { + + static const unsigned short string[] = + { + 120, 112, 97, 116, 104, 68, 101, 102, 97, 117, 108, 116, 78, 97, 109, 101, 115, 112, 97, 99, 101 + }; + if(memcmp(&data[0], &string, sizeof(QChar) * 21) == 0) + + + return XPathDefaultNamespace; + + + return NoKeyword; + } + XsdSchemaToken::NodeName XsdSchemaToken::classifier22(const QChar *data) + + { + + static const unsigned short string[] = + { + 100, 101, 102, 97, 117, 108, 116, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 65, 112, 112, 108, 121 + }; + if(memcmp(&data[0], &string, sizeof(QChar) * 22) == 0) + + + return DefaultAttributesApply; + + + return NoKeyword; + } + XsdSchemaToken::NodeName XsdSchemaToken::classifier32(const QChar *data) + + { + + static const unsigned short string[] = + { + 104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 119, 51, 46, 111, 114, 103, 47, 50, 48, 48, 49, 47, 88, 77, 76, 83, 99, 104, 101, 109, 97 + }; + if(memcmp(&data[0], &string, sizeof(QChar) * 32) == 0) + + + return XML_NS_SCHEMA_URI; + + + return NoKeyword; + } + XsdSchemaToken::NodeName XsdSchemaToken::toToken(const QChar *data, int length) + { + switch(length) + { + + case 2: + return classifier2(data); + + + case 3: + return classifier3(data); + + + case 4: + return classifier4(data); + + + case 5: + return classifier5(data); + + + case 6: + return classifier6(data); + + + case 7: + return classifier7(data); + + + case 8: + return classifier8(data); + + + case 9: + return classifier9(data); + + + case 10: + return classifier10(data); + + + case 11: + return classifier11(data); + + + case 12: + return classifier12(data); + + + case 13: + return classifier13(data); + + + case 14: + return classifier14(data); + + + case 15: + return classifier15(data); + + + case 17: + return classifier17(data); + + + case 18: + return classifier18(data); + + + case 20: + return classifier20(data); + + + case 21: + return classifier21(data); + + + case 22: + return classifier22(data); + + + case 32: + return classifier32(data); + + + default: + return NoKeyword; + } + } + + + QString XsdSchemaToken::toString(NodeName token) + { + const unsigned short *data = 0; + int length = 0; + + switch(token) + { + + case Abstract: + { + static const unsigned short staticallyStoredAbstract[] = + { + 97, 98, 115, 116, 114, 97, 99, 116, 0 + }; + data = staticallyStoredAbstract; + length = 8; + break; + } + + case All: + { + static const unsigned short staticallyStoredAll[] = + { + 97, 108, 108, 0 + }; + data = staticallyStoredAll; + length = 3; + break; + } + + case Alternative: + { + static const unsigned short staticallyStoredAlternative[] = + { + 97, 108, 116, 101, 114, 110, 97, 116, 105, 118, 101, 0 + }; + data = staticallyStoredAlternative; + length = 11; + break; + } + + case Annotation: + { + static const unsigned short staticallyStoredAnnotation[] = + { + 97, 110, 110, 111, 116, 97, 116, 105, 111, 110, 0 + }; + data = staticallyStoredAnnotation; + length = 10; + break; + } + + case Any: + { + static const unsigned short staticallyStoredAny[] = + { + 97, 110, 121, 0 + }; + data = staticallyStoredAny; + length = 3; + break; + } + + case AnyAttribute: + { + static const unsigned short staticallyStoredAnyAttribute[] = + { + 97, 110, 121, 65, 116, 116, 114, 105, 98, 117, 116, 101, 0 + }; + data = staticallyStoredAnyAttribute; + length = 12; + break; + } + + case Appinfo: + { + static const unsigned short staticallyStoredAppinfo[] = + { + 97, 112, 112, 105, 110, 102, 111, 0 + }; + data = staticallyStoredAppinfo; + length = 7; + break; + } + + case AppliesToEmpty: + { + static const unsigned short staticallyStoredAppliesToEmpty[] = + { + 97, 112, 112, 108, 105, 101, 115, 84, 111, 69, 109, 112, 116, 121, 0 + }; + data = staticallyStoredAppliesToEmpty; + length = 14; + break; + } + + case Assert: + { + static const unsigned short staticallyStoredAssert[] = + { + 97, 115, 115, 101, 114, 116, 0 + }; + data = staticallyStoredAssert; + length = 6; + break; + } + + case Assertion: + { + static const unsigned short staticallyStoredAssertion[] = + { + 97, 115, 115, 101, 114, 116, 105, 111, 110, 0 + }; + data = staticallyStoredAssertion; + length = 9; + break; + } + + case Attribute: + { + static const unsigned short staticallyStoredAttribute[] = + { + 97, 116, 116, 114, 105, 98, 117, 116, 101, 0 + }; + data = staticallyStoredAttribute; + length = 9; + break; + } + + case AttributeFormDefault: + { + static const unsigned short staticallyStoredAttributeFormDefault[] = + { + 97, 116, 116, 114, 105, 98, 117, 116, 101, 70, 111, 114, 109, 68, 101, 102, 97, 117, 108, 116, 0 + }; + data = staticallyStoredAttributeFormDefault; + length = 20; + break; + } + + case AttributeGroup: + { + static const unsigned short staticallyStoredAttributeGroup[] = + { + 97, 116, 116, 114, 105, 98, 117, 116, 101, 71, 114, 111, 117, 112, 0 + }; + data = staticallyStoredAttributeGroup; + length = 14; + break; + } + + case Base: + { + static const unsigned short staticallyStoredBase[] = + { + 98, 97, 115, 101, 0 + }; + data = staticallyStoredBase; + length = 4; + break; + } + + case Block: + { + static const unsigned short staticallyStoredBlock[] = + { + 98, 108, 111, 99, 107, 0 + }; + data = staticallyStoredBlock; + length = 5; + break; + } + + case BlockDefault: + { + static const unsigned short staticallyStoredBlockDefault[] = + { + 98, 108, 111, 99, 107, 68, 101, 102, 97, 117, 108, 116, 0 + }; + data = staticallyStoredBlockDefault; + length = 12; + break; + } + + case Choice: + { + static const unsigned short staticallyStoredChoice[] = + { + 99, 104, 111, 105, 99, 101, 0 + }; + data = staticallyStoredChoice; + length = 6; + break; + } + + case Collapse: + { + static const unsigned short staticallyStoredCollapse[] = + { + 99, 111, 108, 108, 97, 112, 115, 101, 0 + }; + data = staticallyStoredCollapse; + length = 8; + break; + } + + case ComplexContent: + { + static const unsigned short staticallyStoredComplexContent[] = + { + 99, 111, 109, 112, 108, 101, 120, 67, 111, 110, 116, 101, 110, 116, 0 + }; + data = staticallyStoredComplexContent; + length = 14; + break; + } + + case ComplexType: + { + static const unsigned short staticallyStoredComplexType[] = + { + 99, 111, 109, 112, 108, 101, 120, 84, 121, 112, 101, 0 + }; + data = staticallyStoredComplexType; + length = 11; + break; + } + + case Default: + { + static const unsigned short staticallyStoredDefault[] = + { + 100, 101, 102, 97, 117, 108, 116, 0 + }; + data = staticallyStoredDefault; + length = 7; + break; + } + + case DefaultAttributes: + { + static const unsigned short staticallyStoredDefaultAttributes[] = + { + 100, 101, 102, 97, 117, 108, 116, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 0 + }; + data = staticallyStoredDefaultAttributes; + length = 17; + break; + } + + case DefaultAttributesApply: + { + static const unsigned short staticallyStoredDefaultAttributesApply[] = + { + 100, 101, 102, 97, 117, 108, 116, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 65, 112, 112, 108, 121, 0 + }; + data = staticallyStoredDefaultAttributesApply; + length = 22; + break; + } + + case DefaultOpenContent: + { + static const unsigned short staticallyStoredDefaultOpenContent[] = + { + 100, 101, 102, 97, 117, 108, 116, 79, 112, 101, 110, 67, 111, 110, 116, 101, 110, 116, 0 + }; + data = staticallyStoredDefaultOpenContent; + length = 18; + break; + } + + case Documentation: + { + static const unsigned short staticallyStoredDocumentation[] = + { + 100, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 0 + }; + data = staticallyStoredDocumentation; + length = 13; + break; + } + + case Element: + { + static const unsigned short staticallyStoredElement[] = + { + 101, 108, 101, 109, 101, 110, 116, 0 + }; + data = staticallyStoredElement; + length = 7; + break; + } + + case ElementFormDefault: + { + static const unsigned short staticallyStoredElementFormDefault[] = + { + 101, 108, 101, 109, 101, 110, 116, 70, 111, 114, 109, 68, 101, 102, 97, 117, 108, 116, 0 + }; + data = staticallyStoredElementFormDefault; + length = 18; + break; + } + + case Enumeration: + { + static const unsigned short staticallyStoredEnumeration[] = + { + 101, 110, 117, 109, 101, 114, 97, 116, 105, 111, 110, 0 + }; + data = staticallyStoredEnumeration; + length = 11; + break; + } + + case Extension: + { + static const unsigned short staticallyStoredExtension[] = + { + 101, 120, 116, 101, 110, 115, 105, 111, 110, 0 + }; + data = staticallyStoredExtension; + length = 9; + break; + } + + case Field: + { + static const unsigned short staticallyStoredField[] = + { + 102, 105, 101, 108, 100, 0 + }; + data = staticallyStoredField; + length = 5; + break; + } + + case Final: + { + static const unsigned short staticallyStoredFinal[] = + { + 102, 105, 110, 97, 108, 0 + }; + data = staticallyStoredFinal; + length = 5; + break; + } + + case FinalDefault: + { + static const unsigned short staticallyStoredFinalDefault[] = + { + 102, 105, 110, 97, 108, 68, 101, 102, 97, 117, 108, 116, 0 + }; + data = staticallyStoredFinalDefault; + length = 12; + break; + } + + case Fixed: + { + static const unsigned short staticallyStoredFixed[] = + { + 102, 105, 120, 101, 100, 0 + }; + data = staticallyStoredFixed; + length = 5; + break; + } + + case Form: + { + static const unsigned short staticallyStoredForm[] = + { + 102, 111, 114, 109, 0 + }; + data = staticallyStoredForm; + length = 4; + break; + } + + case FractionDigits: + { + static const unsigned short staticallyStoredFractionDigits[] = + { + 102, 114, 97, 99, 116, 105, 111, 110, 68, 105, 103, 105, 116, 115, 0 + }; + data = staticallyStoredFractionDigits; + length = 14; + break; + } + + case Group: + { + static const unsigned short staticallyStoredGroup[] = + { + 103, 114, 111, 117, 112, 0 + }; + data = staticallyStoredGroup; + length = 5; + break; + } + + case Id: + { + static const unsigned short staticallyStoredId[] = + { + 105, 100, 0 + }; + data = staticallyStoredId; + length = 2; + break; + } + + case Import: + { + static const unsigned short staticallyStoredImport[] = + { + 105, 109, 112, 111, 114, 116, 0 + }; + data = staticallyStoredImport; + length = 6; + break; + } + + case Include: + { + static const unsigned short staticallyStoredInclude[] = + { + 105, 110, 99, 108, 117, 100, 101, 0 + }; + data = staticallyStoredInclude; + length = 7; + break; + } + + case ItemType: + { + static const unsigned short staticallyStoredItemType[] = + { + 105, 116, 101, 109, 84, 121, 112, 101, 0 + }; + data = staticallyStoredItemType; + length = 8; + break; + } + + case Key: + { + static const unsigned short staticallyStoredKey[] = + { + 107, 101, 121, 0 + }; + data = staticallyStoredKey; + length = 3; + break; + } + + case Keyref: + { + static const unsigned short staticallyStoredKeyref[] = + { + 107, 101, 121, 114, 101, 102, 0 + }; + data = staticallyStoredKeyref; + length = 6; + break; + } + + case Length: + { + static const unsigned short staticallyStoredLength[] = + { + 108, 101, 110, 103, 116, 104, 0 + }; + data = staticallyStoredLength; + length = 6; + break; + } + + case List: + { + static const unsigned short staticallyStoredList[] = + { + 108, 105, 115, 116, 0 + }; + data = staticallyStoredList; + length = 4; + break; + } + + case MaxExclusive: + { + static const unsigned short staticallyStoredMaxExclusive[] = + { + 109, 97, 120, 69, 120, 99, 108, 117, 115, 105, 118, 101, 0 + }; + data = staticallyStoredMaxExclusive; + length = 12; + break; + } + + case MaxInclusive: + { + static const unsigned short staticallyStoredMaxInclusive[] = + { + 109, 97, 120, 73, 110, 99, 108, 117, 115, 105, 118, 101, 0 + }; + data = staticallyStoredMaxInclusive; + length = 12; + break; + } + + case MaxLength: + { + static const unsigned short staticallyStoredMaxLength[] = + { + 109, 97, 120, 76, 101, 110, 103, 116, 104, 0 + }; + data = staticallyStoredMaxLength; + length = 9; + break; + } + + case MaxOccurs: + { + static const unsigned short staticallyStoredMaxOccurs[] = + { + 109, 97, 120, 79, 99, 99, 117, 114, 115, 0 + }; + data = staticallyStoredMaxOccurs; + length = 9; + break; + } + + case MemberTypes: + { + static const unsigned short staticallyStoredMemberTypes[] = + { + 109, 101, 109, 98, 101, 114, 84, 121, 112, 101, 115, 0 + }; + data = staticallyStoredMemberTypes; + length = 11; + break; + } + + case MinExclusive: + { + static const unsigned short staticallyStoredMinExclusive[] = + { + 109, 105, 110, 69, 120, 99, 108, 117, 115, 105, 118, 101, 0 + }; + data = staticallyStoredMinExclusive; + length = 12; + break; + } + + case MinInclusive: + { + static const unsigned short staticallyStoredMinInclusive[] = + { + 109, 105, 110, 73, 110, 99, 108, 117, 115, 105, 118, 101, 0 + }; + data = staticallyStoredMinInclusive; + length = 12; + break; + } + + case MinLength: + { + static const unsigned short staticallyStoredMinLength[] = + { + 109, 105, 110, 76, 101, 110, 103, 116, 104, 0 + }; + data = staticallyStoredMinLength; + length = 9; + break; + } + + case MinOccurs: + { + static const unsigned short staticallyStoredMinOccurs[] = + { + 109, 105, 110, 79, 99, 99, 117, 114, 115, 0 + }; + data = staticallyStoredMinOccurs; + length = 9; + break; + } + + case Mixed: + { + static const unsigned short staticallyStoredMixed[] = + { + 109, 105, 120, 101, 100, 0 + }; + data = staticallyStoredMixed; + length = 5; + break; + } + + case Mode: + { + static const unsigned short staticallyStoredMode[] = + { + 109, 111, 100, 101, 0 + }; + data = staticallyStoredMode; + length = 4; + break; + } + + case Name: + { + static const unsigned short staticallyStoredName[] = + { + 110, 97, 109, 101, 0 + }; + data = staticallyStoredName; + length = 4; + break; + } + + case Namespace: + { + static const unsigned short staticallyStoredNamespace[] = + { + 110, 97, 109, 101, 115, 112, 97, 99, 101, 0 + }; + data = staticallyStoredNamespace; + length = 9; + break; + } + + case Nillable: + { + static const unsigned short staticallyStoredNillable[] = + { + 110, 105, 108, 108, 97, 98, 108, 101, 0 + }; + data = staticallyStoredNillable; + length = 8; + break; + } + + case NotNamespace: + { + static const unsigned short staticallyStoredNotNamespace[] = + { + 110, 111, 116, 78, 97, 109, 101, 115, 112, 97, 99, 101, 0 + }; + data = staticallyStoredNotNamespace; + length = 12; + break; + } + + case NotQName: + { + static const unsigned short staticallyStoredNotQName[] = + { + 110, 111, 116, 81, 78, 97, 109, 101, 0 + }; + data = staticallyStoredNotQName; + length = 8; + break; + } + + case Notation: + { + static const unsigned short staticallyStoredNotation[] = + { + 110, 111, 116, 97, 116, 105, 111, 110, 0 + }; + data = staticallyStoredNotation; + length = 8; + break; + } + + case OpenContent: + { + static const unsigned short staticallyStoredOpenContent[] = + { + 111, 112, 101, 110, 67, 111, 110, 116, 101, 110, 116, 0 + }; + data = staticallyStoredOpenContent; + length = 11; + break; + } + + case Override: + { + static const unsigned short staticallyStoredOverride[] = + { + 111, 118, 101, 114, 114, 105, 100, 101, 0 + }; + data = staticallyStoredOverride; + length = 8; + break; + } + + case Pattern: + { + static const unsigned short staticallyStoredPattern[] = + { + 112, 97, 116, 116, 101, 114, 110, 0 + }; + data = staticallyStoredPattern; + length = 7; + break; + } + + case Preserve: + { + static const unsigned short staticallyStoredPreserve[] = + { + 112, 114, 101, 115, 101, 114, 118, 101, 0 + }; + data = staticallyStoredPreserve; + length = 8; + break; + } + + case ProcessContents: + { + static const unsigned short staticallyStoredProcessContents[] = + { + 112, 114, 111, 99, 101, 115, 115, 67, 111, 110, 116, 101, 110, 116, 115, 0 + }; + data = staticallyStoredProcessContents; + length = 15; + break; + } + + case Public: + { + static const unsigned short staticallyStoredPublic[] = + { + 112, 117, 98, 108, 105, 99, 0 + }; + data = staticallyStoredPublic; + length = 6; + break; + } + + case Redefine: + { + static const unsigned short staticallyStoredRedefine[] = + { + 114, 101, 100, 101, 102, 105, 110, 101, 0 + }; + data = staticallyStoredRedefine; + length = 8; + break; + } + + case Ref: + { + static const unsigned short staticallyStoredRef[] = + { + 114, 101, 102, 0 + }; + data = staticallyStoredRef; + length = 3; + break; + } + + case Refer: + { + static const unsigned short staticallyStoredRefer[] = + { + 114, 101, 102, 101, 114, 0 + }; + data = staticallyStoredRefer; + length = 5; + break; + } + + case Replace: + { + static const unsigned short staticallyStoredReplace[] = + { + 114, 101, 112, 108, 97, 99, 101, 0 + }; + data = staticallyStoredReplace; + length = 7; + break; + } + + case Restriction: + { + static const unsigned short staticallyStoredRestriction[] = + { + 114, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 0 + }; + data = staticallyStoredRestriction; + length = 11; + break; + } + + case Schema: + { + static const unsigned short staticallyStoredSchema[] = + { + 115, 99, 104, 101, 109, 97, 0 + }; + data = staticallyStoredSchema; + length = 6; + break; + } + + case SchemaLocation: + { + static const unsigned short staticallyStoredSchemaLocation[] = + { + 115, 99, 104, 101, 109, 97, 76, 111, 99, 97, 116, 105, 111, 110, 0 + }; + data = staticallyStoredSchemaLocation; + length = 14; + break; + } + + case Selector: + { + static const unsigned short staticallyStoredSelector[] = + { + 115, 101, 108, 101, 99, 116, 111, 114, 0 + }; + data = staticallyStoredSelector; + length = 8; + break; + } + + case Sequence: + { + static const unsigned short staticallyStoredSequence[] = + { + 115, 101, 113, 117, 101, 110, 99, 101, 0 + }; + data = staticallyStoredSequence; + length = 8; + break; + } + + case SimpleContent: + { + static const unsigned short staticallyStoredSimpleContent[] = + { + 115, 105, 109, 112, 108, 101, 67, 111, 110, 116, 101, 110, 116, 0 + }; + data = staticallyStoredSimpleContent; + length = 13; + break; + } + + case SimpleType: + { + static const unsigned short staticallyStoredSimpleType[] = + { + 115, 105, 109, 112, 108, 101, 84, 121, 112, 101, 0 + }; + data = staticallyStoredSimpleType; + length = 10; + break; + } + + case Source: + { + static const unsigned short staticallyStoredSource[] = + { + 115, 111, 117, 114, 99, 101, 0 + }; + data = staticallyStoredSource; + length = 6; + break; + } + + case SubstitutionGroup: + { + static const unsigned short staticallyStoredSubstitutionGroup[] = + { + 115, 117, 98, 115, 116, 105, 116, 117, 116, 105, 111, 110, 71, 114, 111, 117, 112, 0 + }; + data = staticallyStoredSubstitutionGroup; + length = 17; + break; + } + + case System: + { + static const unsigned short staticallyStoredSystem[] = + { + 115, 121, 115, 116, 101, 109, 0 + }; + data = staticallyStoredSystem; + length = 6; + break; + } + + case TargetNamespace: + { + static const unsigned short staticallyStoredTargetNamespace[] = + { + 116, 97, 114, 103, 101, 116, 78, 97, 109, 101, 115, 112, 97, 99, 101, 0 + }; + data = staticallyStoredTargetNamespace; + length = 15; + break; + } + + case Test: + { + static const unsigned short staticallyStoredTest[] = + { + 116, 101, 115, 116, 0 + }; + data = staticallyStoredTest; + length = 4; + break; + } + + case TotalDigits: + { + static const unsigned short staticallyStoredTotalDigits[] = + { + 116, 111, 116, 97, 108, 68, 105, 103, 105, 116, 115, 0 + }; + data = staticallyStoredTotalDigits; + length = 11; + break; + } + + case Type: + { + static const unsigned short staticallyStoredType[] = + { + 116, 121, 112, 101, 0 + }; + data = staticallyStoredType; + length = 4; + break; + } + + case Union: + { + static const unsigned short staticallyStoredUnion[] = + { + 117, 110, 105, 111, 110, 0 + }; + data = staticallyStoredUnion; + length = 5; + break; + } + + case Unique: + { + static const unsigned short staticallyStoredUnique[] = + { + 117, 110, 105, 113, 117, 101, 0 + }; + data = staticallyStoredUnique; + length = 6; + break; + } + + case Use: + { + static const unsigned short staticallyStoredUse[] = + { + 117, 115, 101, 0 + }; + data = staticallyStoredUse; + length = 3; + break; + } + + case Value: + { + static const unsigned short staticallyStoredValue[] = + { + 118, 97, 108, 117, 101, 0 + }; + data = staticallyStoredValue; + length = 5; + break; + } + + case Version: + { + static const unsigned short staticallyStoredVersion[] = + { + 118, 101, 114, 115, 105, 111, 110, 0 + }; + data = staticallyStoredVersion; + length = 7; + break; + } + + case WhiteSpace: + { + static const unsigned short staticallyStoredWhiteSpace[] = + { + 119, 104, 105, 116, 101, 83, 112, 97, 99, 101, 0 + }; + data = staticallyStoredWhiteSpace; + length = 10; + break; + } + + case XML_NS_SCHEMA_URI: + { + static const unsigned short staticallyStoredXML_NS_SCHEMA_URI[] = + { + 104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 119, 51, 46, 111, 114, 103, 47, 50, 48, 48, 49, 47, 88, 77, 76, 83, 99, 104, 101, 109, 97, 0 + }; + data = staticallyStoredXML_NS_SCHEMA_URI; + length = 32; + break; + } + + case XPathDefaultNamespace: + { + static const unsigned short staticallyStoredXPathDefaultNamespace[] = + { + 120, 112, 97, 116, 104, 68, 101, 102, 97, 117, 108, 116, 78, 97, 109, 101, 115, 112, 97, 99, 101, 0 + }; + data = staticallyStoredXPathDefaultNamespace; + length = 21; + break; + } + + case XmlLanguage: + { + static const unsigned short staticallyStoredXmlLanguage[] = + { + 120, 109, 108, 58, 108, 97, 110, 103, 0 + }; + data = staticallyStoredXmlLanguage; + length = 8; + break; + } + + case Xpath: + { + static const unsigned short staticallyStoredXpath[] = + { + 120, 112, 97, 116, 104, 0 + }; + data = staticallyStoredXpath; + length = 5; + break; + } + + default: + /* It's either the default token, or an undefined enum + * value. We silence a compiler warning, and return the + * empty string. */ + ; + } + + union + { + const unsigned short *data; + const QChar *asQChar; + } converter; + converter.data = data; + + return QString::fromRawData(converter.asQChar, length); + } + +QT_END_NAMESPACE + diff --git a/src/xmlpatterns/schema/qxsdschematoken_p.h b/src/xmlpatterns/schema/qxsdschematoken_p.h new file mode 100644 index 0000000..f54f633 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdschematoken_p.h @@ -0,0 +1,209 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +/* NOTE: This file is AUTO GENERATED by qautomaton2cpp.xsl. */ + +#ifndef QPatternist_XsdSchemaToken_h +#define QPatternist_XsdSchemaToken_h + +#include <QtCore/QString> + +QT_BEGIN_NAMESPACE + +class XsdSchemaToken + { + public: + enum NodeName + + { + NoKeyword, +Abstract, +All, +Alternative, +Annotation, +Any, +AnyAttribute, +Appinfo, +AppliesToEmpty, +Assert, +Assertion, +Attribute, +AttributeFormDefault, +AttributeGroup, +Base, +Block, +BlockDefault, +Choice, +Collapse, +ComplexContent, +ComplexType, +Default, +DefaultAttributes, +DefaultAttributesApply, +DefaultOpenContent, +Documentation, +Element, +ElementFormDefault, +Enumeration, +Extension, +Field, +Final, +FinalDefault, +Fixed, +Form, +FractionDigits, +Group, +Id, +Import, +Include, +ItemType, +Key, +Keyref, +Length, +List, +MaxExclusive, +MaxInclusive, +MaxLength, +MaxOccurs, +MemberTypes, +MinExclusive, +MinInclusive, +MinLength, +MinOccurs, +Mixed, +Mode, +Name, +Namespace, +Nillable, +NotNamespace, +NotQName, +Notation, +OpenContent, +Override, +Pattern, +Preserve, +ProcessContents, +Public, +Redefine, +Ref, +Refer, +Replace, +Restriction, +Schema, +SchemaLocation, +Selector, +Sequence, +SimpleContent, +SimpleType, +Source, +SubstitutionGroup, +System, +TargetNamespace, +Test, +TotalDigits, +Type, +Union, +Unique, +Use, +Value, +Version, +WhiteSpace, +XML_NS_SCHEMA_URI, +XPathDefaultNamespace, +XmlLanguage, +Xpath + }; + + static inline NodeName toToken(const QString &value); +static inline NodeName toToken(const QStringRef &value); +static NodeName toToken(const QChar *data, int length); +static QString toString(NodeName token); + + + private: + static inline NodeName classifier2(const QChar *data); +static inline NodeName classifier3(const QChar *data); +static inline NodeName classifier4(const QChar *data); +static inline NodeName classifier5(const QChar *data); +static inline NodeName classifier6(const QChar *data); +static inline NodeName classifier7(const QChar *data); +static inline NodeName classifier8(const QChar *data); +static inline NodeName classifier9(const QChar *data); +static inline NodeName classifier10(const QChar *data); +static inline NodeName classifier11(const QChar *data); +static inline NodeName classifier12(const QChar *data); +static inline NodeName classifier13(const QChar *data); +static inline NodeName classifier14(const QChar *data); +static inline NodeName classifier15(const QChar *data); +static inline NodeName classifier17(const QChar *data); +static inline NodeName classifier18(const QChar *data); +static inline NodeName classifier20(const QChar *data); +static inline NodeName classifier21(const QChar *data); +static inline NodeName classifier22(const QChar *data); +static inline NodeName classifier32(const QChar *data); + + }; + + inline XsdSchemaToken::NodeName XsdSchemaToken::toToken(const QString &value) + { + return toToken(value.constData(), value.length()); + } + + inline XsdSchemaToken::NodeName XsdSchemaToken::toToken(const QStringRef &value) + { + return toToken(value.constData(), value.length()); + } + + +QT_END_NAMESPACE + +#endif diff --git a/src/xmlpatterns/schema/qxsdschematypesfactory.cpp b/src/xmlpatterns/schema/qxsdschematypesfactory.cpp new file mode 100644 index 0000000..430433f --- /dev/null +++ b/src/xmlpatterns/schema/qxsdschematypesfactory.cpp @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdschematypesfactory_p.h" + +#include "qbasictypesfactory_p.h" +#include "qbuiltintypes_p.h" +#include "qderivedinteger_p.h" +#include "qderivedstring_p.h" +#include "qcommonnamespaces_p.h" +#include "qxsdschematoken_p.h" +#include "qxsdsimpletype_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +XsdSchemaTypesFactory::XsdSchemaTypesFactory(const NamePool::Ptr &namePool) + : m_namePool(namePool) +{ + m_types.reserve(3); + + const XsdFacet::Ptr whiteSpaceFacet(new XsdFacet()); + whiteSpaceFacet->setType(XsdFacet::WhiteSpace); + whiteSpaceFacet->setFixed(true); + whiteSpaceFacet->setValue(DerivedString<TypeString>::fromLexical(m_namePool, XsdSchemaToken::toString(XsdSchemaToken::Collapse))); + + const XsdFacet::Ptr minLengthFacet(new XsdFacet()); + minLengthFacet->setType(XsdFacet::MinimumLength); + minLengthFacet->setValue(DerivedInteger<TypeNonNegativeInteger>::fromLexical(namePool, QLatin1String("1"))); + + XsdFacet::Hash facets; + facets.insert(whiteSpaceFacet->type(), whiteSpaceFacet); + facets.insert(minLengthFacet->type(), minLengthFacet); + + { + const QXmlName typeName = m_namePool->allocateQName(CommonNamespaces::WXS, QLatin1String("NMTOKENS")); + const XsdSimpleType::Ptr type(new XsdSimpleType()); + type->setName(typeName); + type->setWxsSuperType(BuiltinTypes::xsAnySimpleType); + type->setCategory(XsdSimpleType::SimpleTypeList); + type->setItemType(BuiltinTypes::xsNMTOKEN); + type->setDerivationMethod(XsdSimpleType::DerivationRestriction); + type->setFacets(facets); + m_types.insert(typeName, type); + } + { + const QXmlName typeName = m_namePool->allocateQName(CommonNamespaces::WXS, QLatin1String("IDREFS")); + const XsdSimpleType::Ptr type(new XsdSimpleType()); + type->setName(typeName); + type->setWxsSuperType(BuiltinTypes::xsAnySimpleType); + type->setCategory(XsdSimpleType::SimpleTypeList); + type->setItemType(BuiltinTypes::xsIDREF); + type->setDerivationMethod(XsdSimpleType::DerivationRestriction); + type->setFacets(facets); + m_types.insert(typeName, type); + } + { + const QXmlName typeName = m_namePool->allocateQName(CommonNamespaces::WXS, QLatin1String("ENTITIES")); + const XsdSimpleType::Ptr type(new XsdSimpleType()); + type->setName(typeName); + type->setWxsSuperType(BuiltinTypes::xsAnySimpleType); + type->setCategory(XsdSimpleType::SimpleTypeList); + type->setItemType(BuiltinTypes::xsENTITY); + type->setDerivationMethod(XsdSimpleType::DerivationRestriction); + type->setFacets(facets); + m_types.insert(typeName, type); + } +} + +SchemaType::Ptr XsdSchemaTypesFactory::createSchemaType(const QXmlName name) const +{ + if (m_types.contains(name)) { + return m_types.value(name); + } else { + if (!m_basicTypesFactory) + m_basicTypesFactory = BasicTypesFactory::self(m_namePool); + + return m_basicTypesFactory->createSchemaType(name); + } +} + +SchemaType::Hash XsdSchemaTypesFactory::types() const +{ + return m_types; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdschematypesfactory_p.h b/src/xmlpatterns/schema/qxsdschematypesfactory_p.h new file mode 100644 index 0000000..ed082ac --- /dev/null +++ b/src/xmlpatterns/schema/qxsdschematypesfactory_p.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdSchemaTypesFactory_H +#define Patternist_XsdSchemaTypesFactory_H + +#include <QtCore/QHash> +#include "qschematypefactory_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + + /** + * @short Factory for creating schema types for the types defined in XSD. + * + * @ingroup Patternist_types + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdSchemaTypesFactory : public SchemaTypeFactory + { + public: + /** + * Creates a new schema type factory. + * + * @param namePool The name pool all type names belong to. + */ + XsdSchemaTypesFactory(const NamePool::Ptr &namePool); + + /** + * Creates a primitive type for @p name. If @p name is not supported, + * @c null is returned. + * + * @note This does not handle user defined types, only builtin types. + */ + virtual SchemaType::Ptr createSchemaType(const QXmlName) const; + + /** + * Returns a hash of all available types. + */ + virtual SchemaType::Hash types() const; + + private: + /** + * A dictonary of all predefined schema types. + */ + SchemaType::Hash m_types; + + NamePool::Ptr m_namePool; + mutable SchemaTypeFactory::Ptr m_basicTypesFactory; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdsimpletype.cpp b/src/xmlpatterns/schema/qxsdsimpletype.cpp new file mode 100644 index 0000000..8b367ba --- /dev/null +++ b/src/xmlpatterns/schema/qxsdsimpletype.cpp @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#include "qxsdsimpletype_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +QString XsdSimpleType::displayName(const NamePool::Ptr &np) const +{ + return np->displayName(name(np)); +} + +void XsdSimpleType::setWxsSuperType(const SchemaType::Ptr &type) +{ + m_superType = type; +} + +SchemaType::Ptr XsdSimpleType::wxsSuperType() const +{ + return m_superType; +} + +void XsdSimpleType::setContext(const NamedSchemaComponent::Ptr &component) +{ + m_context = component; +} + +NamedSchemaComponent::Ptr XsdSimpleType::context() const +{ + return m_context; +} + +void XsdSimpleType::setPrimitiveType(const AnySimpleType::Ptr &type) +{ + m_primitiveType = type; +} + +AnySimpleType::Ptr XsdSimpleType::primitiveType() const +{ + return m_primitiveType; +} + +void XsdSimpleType::setItemType(const AnySimpleType::Ptr &type) +{ + m_itemType = type; +} + +AnySimpleType::Ptr XsdSimpleType::itemType() const +{ + return m_itemType; +} + +void XsdSimpleType::setMemberTypes(const AnySimpleType::List &types) +{ + m_memberTypes = types; +} + +AnySimpleType::List XsdSimpleType::memberTypes() const +{ + return m_memberTypes; +} + +void XsdSimpleType::setFacets(const XsdFacet::Hash &facets) +{ + m_facets = facets; +} + +XsdFacet::Hash XsdSimpleType::facets() const +{ + return m_facets; +} + +void XsdSimpleType::setCategory(TypeCategory category) +{ + m_typeCategory = category; +} + +XsdSimpleType::TypeCategory XsdSimpleType::category() const +{ + return m_typeCategory; +} + +void XsdSimpleType::setDerivationMethod(DerivationMethod method) +{ + m_derivationMethod = method; +} + +XsdSimpleType::DerivationMethod XsdSimpleType::derivationMethod() const +{ + return m_derivationMethod; +} + +bool XsdSimpleType::isDefinedBySchema() const +{ + return true; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdsimpletype_p.h b/src/xmlpatterns/schema/qxsdsimpletype_p.h new file mode 100644 index 0000000..12053f0 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdsimpletype_p.h @@ -0,0 +1,219 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdSimpleType_H +#define Patternist_XsdSimpleType_H + +#include "qanysimpletype_p.h" +#include "qxsdfacet_p.h" +#include "qxsduserschematype_p.h" + +#include <QtCore/QSet> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short Represents a XSD simpleType object. + * + * This class represents the <em>simpleType</em> object of a XML schema as described + * <a href="http://www.w3.org/TR/xmlschema-2/#rf-defn">here</a>. + * + * It contains information from either a top-level simple type declaration (as child of a <em>schema</em> object) + * or a local simple type declaration (as descendant of an <em>element</em> or <em>complexType</em> object). + * + * @see <a href="http://www.w3.org/Submission/2004/SUBM-xmlschema-api-20040309/xml-schema-api.html#Interface-XSSimpleType">XML Schema API reference</a> + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdSimpleType : public XsdUserSchemaType<AnySimpleType> + { + public: + typedef QExplicitlySharedDataPointer<XsdSimpleType> Ptr; + + /** + * Returns the display name of the simple type. + * + * @param namePool The name pool the type name is stored in. + */ + virtual QString displayName(const NamePool::Ptr &namePool) const; + + /** + * Sets the base @p type of the simple type. + * + * @see <a href="http://www.w3.org/TR/xmlschema-2/#defn-basetype">Base Type Definition</a> + */ + void setWxsSuperType(const SchemaType::Ptr &type); + + /** + * Returns the base type of the simple type or an empty pointer if no base type is + * set. + */ + virtual SchemaType::Ptr wxsSuperType() const; + + /** + * Sets the context @p component of the simple type. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#std-context">Context Definition</a> + */ + void setContext(const NamedSchemaComponent::Ptr &component); + + /** + * Returns the context component of the simple type. + */ + NamedSchemaComponent::Ptr context() const; + + /** + * Sets the primitive @p type of the simple type. + * + * The primitive type is only specified if the category is SimpleTypeAtomic. + * + * @see <a href="http://www.w3.org/TR/xmlschema-2/#defn-primitive">Primitive Type Definition</a> + */ + void setPrimitiveType(const AnySimpleType::Ptr &type); + + /** + * Returns the primitive type of the simple type or an empty pointer if the category is + * not SimpleTypeAtomic. + */ + AnySimpleType::Ptr primitiveType() const; + + /** + * Sets the list item @p type of the simple type. + * + * The list item type is only specified if the category is SimpleTypeList. + * + * @see <a href="http://www.w3.org/TR/xmlschema-2/#defn-itemType">Item Type Definition</a> + */ + void setItemType(const AnySimpleType::Ptr &type); + + /** + * Returns the list item type of the simple type or an empty pointer if the category is + * not SimpleTypeList. + */ + AnySimpleType::Ptr itemType() const; + + /** + * Sets the member @p types of the simple type. + * + * The member types are only specified if the category is SimpleTypeUnion. + * + * @see <a href="http://www.w3.org/TR/xmlschema-2/#defn-memberTypes">Member Types Definition</a> + */ + void setMemberTypes(const AnySimpleType::List &types); + + /** + * Returns the list member types of the simple type or an empty list if the category is + * not SimpleTypeUnion. + */ + AnySimpleType::List memberTypes() const; + + /** + * Sets the @p facets of the simple type. + * + * @see <a href="http://www.w3.org/TR/xmlschema-2/#defn-facets">Facets Definition</a> + */ + void setFacets(const XsdFacet::Hash &facets); + + /** + * Returns the facets of the simple type. + */ + XsdFacet::Hash facets() const; + + /** + * Sets the @p category (variety) of the simple type. + * + * @see <a href="http://www.w3.org/TR/xmlschema-2/#defn-variety">Variety Definition</a> + */ + void setCategory(TypeCategory category); + + /** + * Returns the category (variety) of the simple type. + */ + virtual TypeCategory category() const; + + /** + * Sets the derivation @p method of the simple type. + * + * @see DerivationMethod + */ + void setDerivationMethod(DerivationMethod method); + + /** + * Returns the derivation method of the simple type. + */ + virtual DerivationMethod derivationMethod() const; + + /** + * Always returns @c true. + */ + virtual bool isDefinedBySchema() const; + + private: + SchemaType::Ptr m_superType; + NamedSchemaComponent::Ptr m_context; + AnySimpleType::Ptr m_primitiveType; + AnySimpleType::Ptr m_itemType; + AnySimpleType::List m_memberTypes; + XsdFacet::Hash m_facets; + TypeCategory m_typeCategory; + DerivationMethod m_derivationMethod; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdstatemachine.cpp b/src/xmlpatterns/schema/qxsdstatemachine.cpp new file mode 100644 index 0000000..3a59042 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdstatemachine.cpp @@ -0,0 +1,477 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* + * NOTE: This file is included by qxsdstatemachine_p.h + * if you need some includes, put them in qxsdstatemachine_p.h (outside of the namespace) + */ + +template <typename TransitionType> +XsdStateMachine<TransitionType>::XsdStateMachine() + : m_counter(50) +{ +} + +template <typename TransitionType> +XsdStateMachine<TransitionType>::XsdStateMachine(const NamePool::Ptr &namePool) + : m_namePool(namePool) + , m_counter(50) +{ +} + +template <typename TransitionType> +typename XsdStateMachine<TransitionType>::StateId XsdStateMachine<TransitionType>::addState(StateType type) +{ +#ifndef QT_NO_DEBUG + // make sure we don't have two start states + if (type == StartState) { + QHashIterator<StateId, StateType> it(m_states); + while (it.hasNext()) { + it.next(); + Q_ASSERT(it.value() != StartState && it.value() != StartEndState); + } + } +#endif // QT_NO_DEBUG + + // reserve new state id + const StateId id = ++m_counter; + m_states.insert(id, type); + + // if it is a start state, we make it to our current state + if (type == StartState || type == StartEndState) + m_currentState = id; + + return id; +} + +template <typename TransitionType> +void XsdStateMachine<TransitionType>::addTransition(StateId start, TransitionType transition, StateId end) +{ + QHash<TransitionType, QVector<StateId> > &hash = m_transitions[start]; + QVector<StateId> &states = hash[transition]; + if (!states.contains(end)) + states.append(end); +} + +template <typename TransitionType> +void XsdStateMachine<TransitionType>::addEpsilonTransition(StateId start, StateId end) +{ + QVector<StateId> &states = m_epsilonTransitions[start]; + states.append(end); +} + +template <typename TransitionType> +void XsdStateMachine<TransitionType>::reset() +{ + // reset the machine to the start state + QHashIterator<StateId, StateType> it(m_states); + while (it.hasNext()) { + it.next(); + if (it.value() == StartState || it.value() == StartEndState) { + m_currentState = it.key(); + return; + } + } + + Q_ASSERT(false); +} + +template <typename TransitionType> +void XsdStateMachine<TransitionType>::clear() +{ + m_states.clear(); + m_transitions.clear(); + m_epsilonTransitions.clear(); + m_currentState = -1; + m_counter = 50; +} + +template <typename TransitionType> +bool XsdStateMachine<TransitionType>::proceed(TransitionType transition) +{ + // check that we are not in an invalid state + if (!m_transitions.contains(m_currentState)) { + return false; + } + + // fetch the transition entry for the current state + const QHash<TransitionType, QVector<StateId> > &entry = m_transitions[m_currentState]; + if (entry.contains(transition)) { // is there an transition for the given input? + m_currentState = entry.value(transition).first(); + m_lastTransition = transition; + return true; + } else { + return false; + } +} + +template <typename TransitionType> +QList<TransitionType> XsdStateMachine<TransitionType>::possibleTransitions() const +{ + // check that we are not in an invalid state + if (!m_transitions.contains(m_currentState)) { + return QList<TransitionType>(); + } + + // fetch the transition entry for the current state + const QHash<TransitionType, QVector<StateId> > &entry = m_transitions[m_currentState]; + + return entry.keys(); +} + +template <typename TransitionType> +template <typename InputType> +bool XsdStateMachine<TransitionType>::proceed(InputType input) +{ + // check that we are not in an invalid state + if (!m_transitions.contains(m_currentState)) { + return false; + } + + // fetch the transition entry for the current state + const QHash<TransitionType, QVector<StateId> > &entry = m_transitions[m_currentState]; + QHashIterator<TransitionType, QVector<StateId> > it(entry); + while (it.hasNext()) { + it.next(); + if (inputEqualsTransition(input, it.key())) { + m_currentState = it.value().first(); + m_lastTransition = it.key(); + return true; + } + } + + return false; +} + +template <typename TransitionType> +template <typename InputType> +bool XsdStateMachine<TransitionType>::inputEqualsTransition(InputType input, TransitionType transition) const +{ + return false; +} + +template <typename TransitionType> +bool XsdStateMachine<TransitionType>::inEndState() const +{ + // check if current state is an end state + return (m_states.value(m_currentState) == StartEndState || m_states.value(m_currentState) == EndState); +} + +template <typename TransitionType> +TransitionType XsdStateMachine<TransitionType>::lastTransition() const +{ + return m_lastTransition; +} + +template <typename TransitionType> +typename XsdStateMachine<TransitionType>::StateId XsdStateMachine<TransitionType>::startState() const +{ + QHashIterator<StateId, StateType> it(m_states); + while (it.hasNext()) { + it.next(); + if (it.value() == StartState || it.value() == StartEndState) + return it.key(); + } + + Q_ASSERT(false); // should never be reached + return -1; +} + +template <typename TransitionType> +QString XsdStateMachine<TransitionType>::transitionTypeToString(TransitionType type) const +{ + Q_UNUSED(type) + + return QString(); +} + +template <typename TransitionType> +bool XsdStateMachine<TransitionType>::outputGraph(QIODevice *device, const QString &graphName) const +{ + if (!device->isOpen()) { + qWarning("device must be open for writing"); + return false; + } + + QByteArray graph; + QTextStream s(&graph); + + QHashIterator<StateId, QHash<TransitionType, QVector<StateId> > > it(m_transitions); + QHashIterator<StateId, StateType> it3(m_states); + + s << "digraph " << graphName << " {\n"; + s << " mindist = 2.0\n"; + + // draw edges + while (it.hasNext()) { + it.next(); + + QHashIterator<TransitionType, QVector<StateId> > it2(it.value()); + while (it2.hasNext()) { + it2.next(); + for (int i = 0; i < it2.value().count(); ++i) + s << " " << it.key() << " -> " << it2.value().at(i) << " [label=\"" << transitionTypeToString(it2.key()) << "\"]\n"; + } + } + + QHashIterator<StateId, QVector<StateId> > it4(m_epsilonTransitions); + while (it4.hasNext()) { + it4.next(); + + const QVector<StateId> states = it4.value(); + for (int i = 0; i < states.count(); ++i) + s << " " << it4.key() << " -> " << states.at(i) << " [label=\"ε\"]\n"; + } + + // draw node infos + while (it3.hasNext()) { + it3.next(); + + QString style; + if (it3.value() == StartState) { + style = QLatin1String("shape=circle, style=filled, color=blue"); + } else if (it3.value() == StartEndState) { + style = QLatin1String("shape=doublecircle, style=filled, color=blue"); + } else if (it3.value() == InternalState) { + style = QLatin1String("shape=circle, style=filled, color=red"); + } else if (it3.value() == EndState) { + style = QLatin1String("shape=doublecircle, style=filled, color=green"); + } + + s << " " << it3.key() << " [" << style << "]\n"; + } + + s << "}\n"; + + s.flush(); + + if (device->write(graph) == -1) + return false; + + return true; +} + + +template <typename TransitionType> +typename XsdStateMachine<TransitionType>::StateId XsdStateMachine<TransitionType>::dfaStateForNfaState(QSet<StateId> nfaState, + QList< QPair<QSet<StateId>, StateId> > &stateTable, + XsdStateMachine<TransitionType> &dfa) const +{ + // check whether we have the given state in our lookup table + // already, in that case simply return it + for (int i = 0; i < stateTable.count(); ++i) { + if (stateTable.at(i).first == nfaState) + return stateTable.at(i).second; + } + + // check if the NFA state set contains a Start or End + // state, in that case our new DFA state will be a + // Start or End state as well + StateType type = InternalState; + QSetIterator<StateId> it(nfaState); + bool hasStartState = false; + bool hasEndState = false; + while (it.hasNext()) { + const StateId state = it.next(); + if (m_states.value(state) == EndState) { + hasEndState = true; + } else if (m_states.value(state) == StartState) { + hasStartState = true; + } + } + if (hasStartState) { + if (hasEndState) + type = StartEndState; + else + type = StartState; + } else if (hasEndState) { + type = EndState; + } + + // create the new DFA state + const StateId dfaState = dfa.addState(type); + + // add the new DFA state to the lookup table + stateTable.append(qMakePair<QSet<StateId>, StateId>(nfaState, dfaState)); + + return dfaState; +} + + +template <typename TransitionType> +QSet<typename XsdStateMachine<TransitionType>::StateId> XsdStateMachine<TransitionType>::epsilonClosure(const QSet<StateId> &input) const +{ + // every state can reach itself by epsilon transition, so include the input states + // in the result as well + QSet<StateId> result = input; + + // add the input states to the list of to be processed states + QList<StateId> workStates = input.toList(); + while (!workStates.isEmpty()) { // while there are states to be processed left... + + // dequeue one state from list + const StateId state = workStates.takeFirst(); + + // get the list of states that can be reached by the epsilon transition + // from the current 'state' + const QVector<StateId> targetStates = m_epsilonTransitions.value(state); + for (int i = 0; i < targetStates.count(); ++i) { + // if we have this target state not in our result set yet... + if (!result.contains(targetStates.at(i))) { + // ... add it to the result set + result.insert(targetStates.at(i)); + + // add the target state to the list of to be processed states as well, + // as we want to have the epsilon transitions not only for the first + // level of following states + workStates.append(targetStates.at(i)); + } + } + } + + return result; +} + +template <typename TransitionType> +QSet<typename XsdStateMachine<TransitionType>::StateId> XsdStateMachine<TransitionType>::move(const QSet<StateId> &states, TransitionType input) const +{ + QSet<StateId> result; + + QSetIterator<StateId> it(states); + while (it.hasNext()) { // iterate over all given states + const StateId state = it.next(); + + // get the transition table for the current state + const QHash<TransitionType, QVector<StateId> > transitions = m_transitions.value(state); + + // get the target states for the given input + const QVector<StateId> targetStates = transitions.value(input); + + // add all target states to the result + for (int i = 0; i < targetStates.size(); ++i) + result.insert(targetStates.at(i)); + } + + return result; +} + +template <typename TransitionType> +XsdStateMachine<TransitionType> XsdStateMachine<TransitionType>::toDFA() const +{ + XsdStateMachine<TransitionType> dfa(m_namePool); + dfa.m_counter = 100; + QList< QPair< QSet<StateId>, StateId> > table; + QList< QSet<StateId> > isMarked; + + // search the start state as the algorithm starts with it... + StateId startState = -1; + QHashIterator<StateId, StateType> stateTypeIt(m_states); + while (stateTypeIt.hasNext()) { + stateTypeIt.next(); + if (stateTypeIt.value() == StartState) { + startState = stateTypeIt.key(); + break; + } + } + Q_ASSERT(startState != -1); + + // our list of state set that still have to be processed + QList< QSet<StateId> > workStates; + + // add the start state to the list of to processed state sets + workStates.append(epsilonClosure(QSet<StateId>() << startState)); + + while (!workStates.isEmpty()) { // as long as there are state sets to process left + + // enqueue set of states + const QSet<StateId> states = workStates.takeFirst(); + + if (isMarked.contains(states)) // we processed this state set already + continue; + + // mark as processed + isMarked.append(states); + + // select a list of all inputs that are possible for + // the 'states' set + QList<TransitionType> input; + + { + QSetIterator<StateId> it(states); + while (it.hasNext()) { + input << m_transitions.value(it.next()).keys(); + } + } + + // get the state in DFA that corresponds to the 'states' set in the NFA + const StateId dfaBegin = dfaStateForNfaState(states, table, dfa); + + for (int i = 0; i < input.count(); ++i) { // for each possible input + // retrieve the states that can be reached from the 'states' set by the + // given input or by epsilon transition + const QSet<StateId> followStates = epsilonClosure(move(states, input.at(i))); + + // get the state in DFA that corresponds to the 'followStates' set in the NFA + const StateId dfaEnd = dfaStateForNfaState(followStates, table, dfa); + + // adds a new transition to the DFA that corresponds to the transitions between + // 'states' and 'followStates' in the NFA + dfa.addTransition(dfaBegin, input.at(i), dfaEnd); + + // add the 'followStates' to the list of to be processed state sets + workStates.append(followStates); + } + } + + return dfa; +} + +template <typename TransitionType> +QHash<typename XsdStateMachine<TransitionType>::StateId, typename XsdStateMachine<TransitionType>::StateType> XsdStateMachine<TransitionType>::states() const +{ + return m_states; +} + +template <typename TransitionType> +QHash<typename XsdStateMachine<TransitionType>::StateId, QHash<TransitionType, QVector<typename XsdStateMachine<TransitionType>::StateId> > > XsdStateMachine<TransitionType>::transitions() const +{ + return m_transitions; +} diff --git a/src/xmlpatterns/schema/qxsdstatemachine_p.h b/src/xmlpatterns/schema/qxsdstatemachine_p.h new file mode 100644 index 0000000..68bc801 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdstatemachine_p.h @@ -0,0 +1,245 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdStateMachine_H +#define Patternist_XsdStateMachine_H + +#include "qnamepool_p.h" + +#include <QtCore/QHash> +#include <QtCore/QSet> +#include <QtCore/QTextStream> + +class QIODevice; + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short A state machine used for evaluation. + * + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + template <typename TransitionType> + class XsdStateMachine + { + public: + typedef qint32 StateId; + + /** + * Describes the type of state. + */ + enum StateType + { + StartState, ///< The state the machine will start with. + StartEndState, ///< The state the machine will start with, can be end state as well. + InternalState, ///< Any state that is not start or end state. + EndState ///< Any state where the machine is allowed to stop. + }; + + /** + * Creates a new state machine object. + */ + XsdStateMachine(); + + /** + * Creates a new state machine object. + * + * The name pool to use for accessing object names. + */ + XsdStateMachine(const NamePool::Ptr &namePool); + + /** + * Adds a new state of the given @p type to the state machine. + * + * @return The id of the new state. + */ + StateId addState(StateType type); + + /** + * Adds a new @p transition to the state machine. + * + * @param start The start state. + * @param transition The transition to come from the start to the end state. + * @param end The end state. + */ + void addTransition(StateId start, TransitionType transition, StateId end); + + /** + * Adds a new epsilon @p transition to the state machine. + * + * @param start The start state. + * @param end The end state. + */ + void addEpsilonTransition(StateId start, StateId end); + + /** + * Resets the machine to the start state. + */ + void reset(); + + /** + * Removes all states and transitions from the state machine. + */ + void clear(); + + /** + * Continues execution of the machine with the given input @p transition. + * + * @return @c true if the transition was successfull, @c false otherwise. + */ + bool proceed(TransitionType transition); + + /** + * Returns the list of transitions that are reachable from the current + * state. + */ + QList<TransitionType> possibleTransitions() const; + + /** + * Continues execution of the machine with the given @p input. + * + * @note To use this method, inputEqualsTransition must be implemented + * to find the right transition to use. + * + * @return @c true if the transition was successfull, @c false otherwise. + */ + template <typename InputType> + bool proceed(InputType input); + + /** + * Returns whether the given @p input matches the given @p transition. + */ + template <typename InputType> + bool inputEqualsTransition(InputType input, TransitionType transition) const; + + /** + * Returns whether the machine is in an allowed end state. + */ + bool inEndState() const; + + /** + * Returns the last transition that was taken. + */ + TransitionType lastTransition() const; + + /** + * Returns the start state of the machine. + */ + StateId startState() const; + + /** + * This method should be redefined by template specialization for every + * concret TransitionType. + */ + QString transitionTypeToString(TransitionType type) const; + + /** + * Outputs the state machine in DOT format to the given + * output @p device. + */ + bool outputGraph(QIODevice *device, const QString &graphName) const; + + /** + * Returns a DFA that is equal to the NFA of the state machine. + */ + XsdStateMachine<TransitionType> toDFA() const; + + /** + * Returns the information of all states of the state machine. + */ + QHash<StateId, StateType> states() const; + + /** + * Returns the information of all transitions of the state machine. + */ + QHash<StateId, QHash<TransitionType, QVector<StateId> > > transitions() const; + + private: + /** + * Returns the DFA state for the given @p nfaStat from the given @p stateTable. + * If there is no corresponding DFA state yet, a new one is created. + */ + StateId dfaStateForNfaState(QSet<StateId> nfaState, QList< QPair< QSet<StateId>, StateId> > &stateTable, XsdStateMachine<TransitionType> &dfa) const; + + /** + * Returns the set of all states that can be reached from the set of @p input states + * by the epsilon transition. + */ + QSet<StateId> epsilonClosure(const QSet<StateId> &input) const; + + /** + * Returns the set of all states that can be reached from the set of given @p states + * by the given @p input. + */ + QSet<StateId> move(const QSet<StateId> &states, TransitionType input) const; + + NamePool::Ptr m_namePool; + QHash<StateId, StateType> m_states; + QHash<StateId, QHash<TransitionType, QVector<StateId> > > m_transitions; + QHash<StateId, QVector<StateId> > m_epsilonTransitions; + StateId m_currentState; + qint32 m_counter; + TransitionType m_lastTransition; + }; + + #include "qxsdstatemachine.cpp" +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdstatemachinebuilder.cpp b/src/xmlpatterns/schema/qxsdstatemachinebuilder.cpp new file mode 100644 index 0000000..ae7fefe --- /dev/null +++ b/src/xmlpatterns/schema/qxsdstatemachinebuilder.cpp @@ -0,0 +1,260 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdstatemachinebuilder_p.h" + +#include "qxsdelement_p.h" +#include "qxsdmodelgroup_p.h" +#include "qxsdschemahelper_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +/* + * This methods takes a list of objects and returns a list of list + * of all combinations the objects can be ordered. + * + * e.g. input = [ 1, 2, 3 ] + * output = [ + * [ 1, 2, 3 ], + * [ 1, 3, 2 ], + * [ 2, 1, 3 ], + * [ 2, 3, 1 ], + * [ 3, 1, 2 ], + * [ 3, 2, 1 ] + * ] + * + * The method is used to create all possible combinations for the particles + * in an <all> model group. + */ +template <typename T> +QList< QList<T> > allCombinations(const QList<T> &input) +{ + if (input.count() == 1) + return (QList< QList<T> >() << input); + + QList< QList<T> > result; + for (int i = 0; i < input.count(); ++i) { + QList<T> subList = input; + T value = subList.takeAt(i); + + QList< QList<T> > subLists = allCombinations(subList); + for (int j = 0; j < subLists.count(); ++j) { + subLists[j].prepend(value); + } + result << subLists; + } + + return result; +} + +XsdStateMachineBuilder::XsdStateMachineBuilder(XsdStateMachine<XsdTerm::Ptr> *machine, const NamePool::Ptr &namePool, Mode mode) + : m_stateMachine(machine), m_namePool(namePool), m_mode(mode) +{ +} + +XsdStateMachine<XsdTerm::Ptr>::StateId XsdStateMachineBuilder::reset() +{ + Q_ASSERT(m_stateMachine); + + m_stateMachine->clear(); + + return m_stateMachine->addState(XsdStateMachine<XsdTerm::Ptr>::EndState); +} + +XsdStateMachine<XsdTerm::Ptr>::StateId XsdStateMachineBuilder::addStartState(XsdStateMachine<XsdTerm::Ptr>::StateId state) +{ + const XsdStateMachine<XsdTerm::Ptr>::StateId startState = m_stateMachine->addState(XsdStateMachine<XsdTerm::Ptr>::StartState); + m_stateMachine->addEpsilonTransition(startState, state); + + return startState; +} + +/* + * Create the FSA according to Algorithm Tp(S) from http://www.ltg.ed.ac.uk/~ht/XML_Europe_2003.html + */ +XsdStateMachine<XsdTerm::Ptr>::StateId XsdStateMachineBuilder::buildParticle(const XsdParticle::Ptr &particle, XsdStateMachine<XsdTerm::Ptr>::StateId endState) +{ + XsdStateMachine<XsdTerm::Ptr>::StateId currentStartState = endState; + XsdStateMachine<XsdTerm::Ptr>::StateId currentEndState = endState; + + // 2 + if (particle->maximumOccursUnbounded()) { + const XsdStateMachine<XsdTerm::Ptr>::StateId t = m_stateMachine->addState(XsdStateMachine<XsdTerm::Ptr>::InternalState); + const XsdStateMachine<XsdTerm::Ptr>::StateId n = buildTerm(particle->term(), t); + + m_stateMachine->addEpsilonTransition(t, n); + m_stateMachine->addEpsilonTransition(n, endState); + + currentEndState = t; + currentStartState = t; + } else { // 3 + int count = (particle->maximumOccurs() - particle->minimumOccurs()); + if (count > 100) + count = 100; + + for (int i = 0; i < count; ++i) { + currentStartState = buildTerm(particle->term(), currentEndState); + m_stateMachine->addEpsilonTransition(currentStartState, endState); + currentEndState = currentStartState; + } + } + + int minOccurs = particle->minimumOccurs(); + if (minOccurs > 100) + minOccurs = 100; + + for (int i = 0; i < minOccurs; ++i) { + currentStartState = buildTerm(particle->term(), currentEndState); + currentEndState = currentStartState; + } + + return currentStartState; +} + +/* + * Create the FSA according to Algorithm Tt(S) from http://www.ltg.ed.ac.uk/~ht/XML_Europe_2003.html + */ +XsdStateMachine<XsdTerm::Ptr>::StateId XsdStateMachineBuilder::buildTerm(const XsdTerm::Ptr &term, XsdStateMachine<XsdTerm::Ptr>::StateId endState) +{ + if (term->isWildcard()) { // 1 + const XsdStateMachine<XsdTerm::Ptr>::StateId b = m_stateMachine->addState(XsdStateMachine<XsdTerm::Ptr>::InternalState); + m_stateMachine->addTransition(b, term, endState); + return b; + } else if (term->isElement()) { // 2 + const XsdStateMachine<XsdTerm::Ptr>::StateId b = m_stateMachine->addState(XsdStateMachine<XsdTerm::Ptr>::InternalState); + m_stateMachine->addTransition(b, term, endState); + + const XsdElement::Ptr element(term); + if (m_mode == CheckingMode) { + const XsdElement::List substGroups = element->substitutionGroups(); + for (int i = 0; i < substGroups.count(); ++i) + m_stateMachine->addTransition(b, substGroups.at(i), endState); + } else if (m_mode == ValidatingMode) { + const XsdElement::List substGroups = element->substitutionGroups(); + for (int i = 0; i < substGroups.count(); ++i) { + if (XsdSchemaHelper::substitutionGroupOkTransitive(element, substGroups.at(i), m_namePool)) + m_stateMachine->addTransition(b, substGroups.at(i), endState); + } + } + + return b; + } else if (term->isModelGroup()) { + const XsdModelGroup::Ptr group(term); + + if (group->compositor() == XsdModelGroup::ChoiceCompositor) { // 3 + const XsdStateMachine<XsdTerm::Ptr>::StateId b = m_stateMachine->addState(XsdStateMachine<XsdTerm::Ptr>::InternalState); + + for (int i = 0; i < group->particles().count(); ++i) { + const XsdParticle::Ptr particle(group->particles().at(i)); + if (particle->maximumOccurs() != 0) { + const XsdStateMachine<XsdTerm::Ptr>::StateId state = buildParticle(particle, endState); + m_stateMachine->addEpsilonTransition(b, state); + } + } + + return b; + } else if (group->compositor() == XsdModelGroup::SequenceCompositor) { // 4 + XsdStateMachine<XsdTerm::Ptr>::StateId currentStartState = endState; + XsdStateMachine<XsdTerm::Ptr>::StateId currentEndState = endState; + + for (int i = (group->particles().count() - 1); i >= 0; --i) { // iterate reverse + const XsdParticle::Ptr particle(group->particles().at(i)); + if (particle->maximumOccurs() != 0) { + currentStartState = buildParticle(particle, currentEndState); + currentEndState = currentStartState; + } + } + + return currentStartState; + } else if (group->compositor() == XsdModelGroup::AllCompositor) { + const XsdStateMachine<XsdTerm::Ptr>::StateId newStartState = m_stateMachine->addState(XsdStateMachine<XsdTerm::Ptr>::InternalState); + + const QList<XsdParticle::List> list = allCombinations(group->particles()); + + for (int i = 0; i < list.count(); ++i) { + XsdStateMachine<XsdTerm::Ptr>::StateId currentStartState = endState; + XsdStateMachine<XsdTerm::Ptr>::StateId currentEndState = endState; + + const XsdParticle::List particles = list.at(i); + for (int j = (particles.count() - 1); j >= 0; --j) { // iterate reverse + const XsdParticle::Ptr particle(particles.at(j)); + if (particle->maximumOccurs() != 0) { + currentStartState = buildParticle(particle, currentEndState); + currentEndState = currentStartState; + } + } + m_stateMachine->addEpsilonTransition(newStartState, currentStartState); + } + + if (list.isEmpty()) + return endState; + else + return newStartState; + } + } + + Q_ASSERT(false); + return 0; +} + +static void internalParticleLookupMap(const XsdParticle::Ptr &particle, QHash<XsdTerm::Ptr, XsdParticle::Ptr> &hash) +{ + hash.insert(particle->term(), particle); + + if (particle->term()->isModelGroup()) { + const XsdModelGroup::Ptr group(particle->term()); + const XsdParticle::List particles = group->particles(); + for (int i = 0; i < particles.count(); ++i) + internalParticleLookupMap(particles.at(i), hash); + } +} + +QHash<XsdTerm::Ptr, XsdParticle::Ptr> XsdStateMachineBuilder::particleLookupMap(const XsdParticle::Ptr &particle) +{ + QHash<XsdTerm::Ptr, XsdParticle::Ptr> result; + internalParticleLookupMap(particle, result); + + return result; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdstatemachinebuilder_p.h b/src/xmlpatterns/schema/qxsdstatemachinebuilder_p.h new file mode 100644 index 0000000..08d69de --- /dev/null +++ b/src/xmlpatterns/schema/qxsdstatemachinebuilder_p.h @@ -0,0 +1,141 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdStateMachineBuilder_H +#define Patternist_XsdStateMachineBuilder_H + +#include "qxsdparticle_p.h" +#include "qxsdstatemachine_p.h" +#include "qxsdterm_p.h" + +#include <QtCore/QExplicitlySharedDataPointer> +#include <QtCore/QList> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short A helper class to build up validation state machines. + * + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdStateMachineBuilder : public QSharedData + { + public: + typedef QExplicitlySharedDataPointer<XsdStateMachineBuilder> Ptr; + + enum Mode + { + CheckingMode, + ValidatingMode + }; + + /** + * Creates a new state machine builder. + * + * @param machine The state machine it should work on. + * @param namePool The name pool used by all schema components. + * @param mode The mode the machine shall be build for. + */ + XsdStateMachineBuilder(XsdStateMachine<XsdTerm::Ptr> *machine, const NamePool::Ptr &namePool, Mode mode = CheckingMode); + + /** + * Resets the state machine. + * + * @returns The initial end state. + */ + XsdStateMachine<XsdTerm::Ptr>::StateId reset(); + + /** + * Prepends a start state to the given @p state. + * That is needed to allow the conversion of the state machine from a FSA to a DFA. + */ + XsdStateMachine<XsdTerm::Ptr>::StateId addStartState(XsdStateMachine<XsdTerm::Ptr>::StateId state); + + /** + * Creates the state machine for the given @p particle that should have the + * given @p endState. + * + * @returns The new start state. + */ + XsdStateMachine<XsdTerm::Ptr>::StateId buildParticle(const XsdParticle::Ptr &particle, XsdStateMachine<XsdTerm::Ptr>::StateId endState); + + /** + * Creates the state machine for the given @p term that should have the + * given @p endState. + * + * @returns The new start state. + */ + XsdStateMachine<XsdTerm::Ptr>::StateId buildTerm(const XsdTerm::Ptr &term, XsdStateMachine<XsdTerm::Ptr>::StateId endState); + + /** + * Returns a hash that maps each term that appears inside @p particle, to the particle it belongs. + * + * @note These information are used by XsdParticleChecker to check particle inheritance. + */ + static QHash<XsdTerm::Ptr, XsdParticle::Ptr> particleLookupMap(const XsdParticle::Ptr &particle); + + private: + XsdStateMachine<XsdTerm::Ptr> *m_stateMachine; + NamePool::Ptr m_namePool; + Mode m_mode; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdterm.cpp b/src/xmlpatterns/schema/qxsdterm.cpp new file mode 100644 index 0000000..a1349c9 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdterm.cpp @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdterm_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +bool XsdTerm::isElement() const +{ + return false; +} + +bool XsdTerm::isModelGroup() const +{ + return false; +} + +bool XsdTerm::isWildcard() const +{ + return false; +} + +bool XsdTerm::isReference() const +{ + return false; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdterm_p.h b/src/xmlpatterns/schema/qxsdterm_p.h new file mode 100644 index 0000000..c42bb40 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdterm_p.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdTerm_H +#define Patternist_XsdTerm_H + +#include "qnamedschemacomponent_p.h" +#include "qxsdannotated_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short A base class for all particles of a model group. + * + * This class is the base class for all particles of a model group + * as the <em>element</em>, <em>group</em> or <em>any</em> tag, it is not supposed to + * be instantiated directly. + * + * @see <a href="http://www.w3.org/Submission/2004/SUBM-xmlschema-api-20040309/xml-schema-api.html#Interface-XSTerm">XML Schema API reference</a> + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdTerm : public NamedSchemaComponent, public XsdAnnotated + { + public: + typedef QExplicitlySharedDataPointer<XsdTerm> Ptr; + + /** + * Returns @c true if the term is an element, @c false otherwise. + */ + virtual bool isElement() const; + + /** + * Returns @c true if the term is a model group (group tag), @c false otherwise. + */ + virtual bool isModelGroup() const; + + /** + * Returns @c true if the term is a wildcard (any tag), @c false otherwise. + */ + virtual bool isWildcard() const; + + /** + * Returns @c true if the term is a reference, @c false otherwise. + * + * @note The reference term is only used internally as helper during type resolving. + */ + virtual bool isReference() const; + + protected: + /** + * This constructor only exists to ensure this class is subclassed. + */ + inline XsdTerm() {}; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdtypechecker.cpp b/src/xmlpatterns/schema/qxsdtypechecker.cpp new file mode 100644 index 0000000..acb10ef --- /dev/null +++ b/src/xmlpatterns/schema/qxsdtypechecker.cpp @@ -0,0 +1,1338 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdtypechecker_p.h" + +#include "qabstractdatetime_p.h" +#include "qbase64binary_p.h" +#include "qboolean_p.h" +#include "qdecimal_p.h" +#include "qderivedinteger_p.h" +#include "qduration_p.h" +#include "qgenericstaticcontext_p.h" +#include "qhexbinary_p.h" +#include "qnamespaceresolver_p.h" +#include "qpatternplatform_p.h" +#include "qqnamevalue_p.h" +#include "qvaluefactory_p.h" +#include "qxmlnamepool.h" +#include "qxsdschemahelper_p.h" +#include "qxsdschemamerger_p.h" +#include "qxsdstatemachine_p.h" + +#include "qxsdschemadebugger_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +XsdSchemaSourceLocationReflection::XsdSchemaSourceLocationReflection(const QSourceLocation &location) + : m_sourceLocation(location) +{ +} + +const SourceLocationReflection* XsdSchemaSourceLocationReflection::actualReflection() const +{ + return this; +} + +QSourceLocation XsdSchemaSourceLocationReflection::sourceLocation() const +{ + return m_sourceLocation; +} + + +static AnySimpleType::Ptr comparableType(const AnySimpleType::Ptr &type) +{ + if (!type->isDefinedBySchema()) { + return type; + } else { + const XsdSimpleType::Ptr simpleType(type); + if (type->category() == SchemaType::SimpleTypeAtomic) { + return simpleType->primitiveType(); + } else if (type->category() == SchemaType::SimpleTypeList) { + return simpleType->itemType(); + } else if (type->category() == SchemaType::SimpleTypeUnion) { + return simpleType->memberTypes().first(); + } + } + + Q_ASSERT(false); + return AnySimpleType::Ptr(); +} + +static int totalDigitsForSignedLongLong(long long value) +{ + QString number = QString::number(value); + if (number.startsWith(QLatin1Char('-'))) + number = number.mid(1); + + return number.length(); +} + +static int totalDigitsForUnsignedLongLong(unsigned long long value) +{ + const QString number = QString::number(value); + return number.length(); +} + +static int totalDigitsForDecimal(const QString &lexicalValue) +{ + const QLatin1Char zeroChar('0'); + const int length = lexicalValue.length() - 1; + + // strip leading zeros + int pos = 0; + while (lexicalValue.at(pos) == zeroChar && (pos != length)) + pos++; + + QString value = lexicalValue.mid(pos); + + // if contains '.' strip trailing zeros + if (value.contains(QLatin1Char('.'))) { + pos = value.length() - 1; + while (value.at(pos) == zeroChar) { + pos--; + } + + value = value.left(pos + 1); + } + + // check number of digits of remaining string + int totalDigits = 0; + for (int i = 0; i < value.count(); ++i) + if (value.at(i).isDigit()) + ++totalDigits; + + if (totalDigits == 0) + totalDigits = 1; + + return totalDigits; +} + +static int fractionDigitsForDecimal(const QString &lexicalValue) +{ + // we use the lexical value here, as the conversion to double might strip + // away decimal positions + + QString trimmedValue(lexicalValue.trimmed()); + const int pos = trimmedValue.indexOf(QLatin1Char('.')); + if (pos == -1) // no '.' -> 0 fraction digits + return 0; + else + return (trimmedValue.length() - pos - 1); +} + +XsdTypeChecker::XsdTypeChecker(const XsdSchemaContext::Ptr &context, const QVector<QXmlName> &namespaceBindings, const QSourceLocation &location) + : m_context(context) + , m_namePool(m_context->namePool()) + , m_namespaceBindings(namespaceBindings) + , m_reflection(new XsdSchemaSourceLocationReflection(location)) +{ +} + +XsdTypeChecker::~XsdTypeChecker() +{ +} + +QString XsdTypeChecker::normalizedValue(const QString &value, const XsdFacet::Hash &facets) +{ + if (!facets.contains(XsdFacet::WhiteSpace)) + return value; + + const XsdFacet::Ptr whiteSpaceFacet = facets.value(XsdFacet::WhiteSpace); + + const DerivedString<TypeString>::Ptr facetValue = whiteSpaceFacet->value(); + const QString stringValue = facetValue->stringValue(); + if (stringValue == XsdSchemaToken::toString(XsdSchemaToken::Preserve)) + return value; + else if (stringValue == XsdSchemaToken::toString(XsdSchemaToken::Replace)) { + QString newValue(value); + newValue.replace(QLatin1Char('\t'), QLatin1Char(' ')); + newValue.replace(QLatin1Char('\n'), QLatin1Char(' ')); + newValue.replace(QLatin1Char('\r'), QLatin1Char(' ')); + + return newValue; + } else if (stringValue == XsdSchemaToken::toString(XsdSchemaToken::Collapse)) { + return value.simplified(); + } + + return value; +} + +XsdFacet::Hash XsdTypeChecker::mergedFacetsForType(const SchemaType::Ptr &type, const XsdSchemaContext::Ptr &context) +{ + if (!type) + return XsdFacet::Hash(); + + const XsdFacet::Hash baseFacets = mergedFacetsForType(type->wxsSuperType(), context); + const XsdFacet::Hash facets = context->facetsForType(type); + + XsdFacet::Hash result = baseFacets; + XsdFacet::HashIterator it(facets); + while (it.hasNext()) { + it.next(); + + result.insert(it.key(), it.value()); + } + + return result; +} + +bool XsdTypeChecker::isValidString(const QString &normalizedString, const AnySimpleType::Ptr &type, QString &errorMsg, AnySimpleType::Ptr *boundType) const +{ + if (type->name(m_namePool) == BuiltinTypes::xsAnySimpleType->name(m_namePool)) { + if (boundType) + *boundType = type; + + return true; + } + + if (!type->isDefinedBySchema()) { + // special QName check + if (BuiltinTypes::xsQName->wxsTypeMatches(type)) { + if (!XPathHelper::isQName(normalizedString)) { + errorMsg = QtXmlPatterns::tr("%1 is not valid according to %2").arg(formatData(normalizedString)).arg(formatType(m_namePool, type)); + return false; + } + } + + const AtomicValue::Ptr value = fromLexical(normalizedString, type, m_context, m_reflection); + if (value->hasError()) { + errorMsg = QtXmlPatterns::tr("%1 is not valid according to %2").arg(formatData(normalizedString)).arg(formatType(m_namePool, type)); + return false; + } + + if (!checkConstrainingFacets(value, normalizedString, type, errorMsg)) { + return false; + } + + if (boundType) + *boundType = type; + + } else { + const XsdSimpleType::Ptr simpleType(type); + + if (simpleType->category() == XsdSimpleType::SimpleTypeAtomic) { + AnySimpleType::Ptr targetType = simpleType->primitiveType(); + if (!simpleType->wxsSuperType()->isDefinedBySchema()) + targetType = simpleType->wxsSuperType(); + + const AtomicValue::Ptr value = fromLexical(normalizedString, targetType, m_context, m_reflection); + if (value->hasError()) { + errorMsg = QtXmlPatterns::tr("%1 is not valid according to %2").arg(formatData(normalizedString)).arg(formatType(m_namePool, targetType)); + return false; + } + + if (!checkConstrainingFacets(value, normalizedString, type, errorMsg)) { + return false; + } + + if (boundType) + *boundType = type; + + } else if (simpleType->category() == XsdSimpleType::SimpleTypeList) { + QStringList entries = normalizedString.split(QLatin1Char(' '), QString::SkipEmptyParts); + for (int i = 0; i < entries.count(); ++i) { + entries[i] = normalizedValue(entries.at(i), mergedFacetsForType(simpleType->itemType(), m_context)); + } + + if (!checkConstrainingFacetsList(entries, normalizedString, simpleType->itemType(), mergedFacetsForType(simpleType, m_context), errorMsg)) { + return false; + } + + for (int i = 0; i < entries.count(); ++i) { + if (!isValidString(entries.at(i), simpleType->itemType(), errorMsg)) { + return false; + } + } + + if (boundType) + *boundType = simpleType->itemType(); + + } else if (simpleType->category() == XsdSimpleType::SimpleTypeUnion) { + if (!checkConstrainingFacetsUnion(normalizedString, normalizedString, simpleType, mergedFacetsForType(simpleType, m_context), errorMsg)) { + return false; + } + + const AnySimpleType::List memberTypes = simpleType->memberTypes(); + + bool foundValidType = false; + for (int i = 0; i < memberTypes.count(); ++i) { + const XsdFacet::Hash mergedFacets = mergedFacetsForType(memberTypes.at(i), m_context); + if (isValidString(normalizedValue(normalizedString, mergedFacets), memberTypes.at(i), errorMsg)) { + foundValidType = true; + + if (boundType) + *boundType = memberTypes.at(i); + + break; + } + } + + if (!foundValidType) { + return false; + } + } + } + + return true; +} + +bool XsdTypeChecker::valuesAreEqual(const QString &value, const QString &otherValue, const AnySimpleType::Ptr &type) const +{ + const AnySimpleType::Ptr targetType = comparableType(type); + + // if the type is xs:anySimpleType we just do string comparison... + if (targetType->name(m_namePool) == BuiltinTypes::xsAnySimpleType->name(m_namePool)) + return (value == otherValue); + + if (BuiltinTypes::xsQName->wxsTypeMatches(type)) { + const QXmlName valueName = convertToQName(value); + const QXmlName otherValueName = convertToQName(otherValue); + + if (valueName == otherValueName) + return true; + } + + if (type->category() == SchemaType::SimpleTypeAtomic) { + // ... otherwise we use the casting platform for value comparison + const DerivedString<TypeString>::Ptr valueStr = DerivedString<TypeString>::fromLexical(m_namePool, value); + const DerivedString<TypeString>::Ptr otherValueStr = DerivedString<TypeString>::fromLexical(m_namePool, otherValue); + + return XsdSchemaHelper::constructAndCompare(valueStr, AtomicComparator::OperatorEqual, otherValueStr, targetType, m_context, m_reflection); + } else if (type->category() == SchemaType::SimpleTypeList) { + const QStringList values = value.split(QLatin1Char(' '), QString::SkipEmptyParts); + const QStringList otherValues = otherValue.split(QLatin1Char(' '), QString::SkipEmptyParts); + if (values.count() != otherValues.count()) + return false; + + for (int i = 0; i < values.count(); ++i) { + if (!valuesAreEqual(values.at(i), otherValues.at(i), XsdSimpleType::Ptr(type)->itemType())) + return false; + } + + return true; + } else if (type->category() == SchemaType::SimpleTypeUnion) { + const AnySimpleType::List memberTypes = XsdSimpleType::Ptr(type)->memberTypes(); + for (int i = 0; i < memberTypes.count(); ++i) { + if (valuesAreEqual(value, otherValue, memberTypes.at(i))) { + return true; + } + } + + return false; + } + + return false; +} + +bool XsdTypeChecker::checkConstrainingFacets(const AtomicValue::Ptr &value, const QString &lexicalValue, const AnySimpleType::Ptr &type, QString &errorMsg) const +{ + const XsdFacet::Hash facets = mergedFacetsForType(type, m_context); + + if (BuiltinTypes::xsString->wxsTypeMatches(type) || + BuiltinTypes::xsUntypedAtomic->wxsTypeMatches(type)) { + return checkConstrainingFacetsString(value->stringValue(), facets, BuiltinTypes::xsString, errorMsg); + } else if (BuiltinTypes::xsAnyURI->wxsTypeMatches(type)) { + return checkConstrainingFacetsString(value->stringValue(), facets, BuiltinTypes::xsAnyURI, errorMsg); + } else if (BuiltinTypes::xsNOTATION->wxsTypeMatches(type)) { + return checkConstrainingFacetsNotation(value->as<QNameValue>()->qName(), facets, errorMsg); + } else if (BuiltinTypes::xsUnsignedByte->wxsTypeMatches(type) || + BuiltinTypes::xsUnsignedInt->wxsTypeMatches(type) || + BuiltinTypes::xsUnsignedLong->wxsTypeMatches(type) || + BuiltinTypes::xsUnsignedShort->wxsTypeMatches(type)) { + return checkConstrainingFacetsUnsignedInteger(value->as<Numeric>()->toUnsignedInteger(), lexicalValue, facets, errorMsg); + } else if (BuiltinTypes::xsInteger->wxsTypeMatches(type)) { + return checkConstrainingFacetsSignedInteger(value->as<Numeric>()->toInteger(), lexicalValue, facets, errorMsg); + } else if (BuiltinTypes::xsFloat->wxsTypeMatches(type) || + BuiltinTypes::xsDouble->wxsTypeMatches(type)) { + return checkConstrainingFacetsDouble(value->as<Numeric>()->toDouble(), lexicalValue, facets, errorMsg); + } else if (BuiltinTypes::xsDecimal->wxsTypeMatches(type)) { + return checkConstrainingFacetsDecimal(value, lexicalValue, facets, errorMsg); + } else if (BuiltinTypes::xsDateTime->wxsTypeMatches(type)) { + return checkConstrainingFacetsDateTime(value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, BuiltinTypes::xsDateTime, errorMsg); + } else if (BuiltinTypes::xsDate->wxsTypeMatches(type)) { + return checkConstrainingFacetsDateTime(value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, BuiltinTypes::xsDate, errorMsg); + } else if (BuiltinTypes::xsGYear->wxsTypeMatches(type)) { + return checkConstrainingFacetsDateTime(value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, BuiltinTypes::xsGYear, errorMsg); + } else if (BuiltinTypes::xsGYearMonth->wxsTypeMatches(type)) { + return checkConstrainingFacetsDateTime(value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, BuiltinTypes::xsGYearMonth, errorMsg); + } else if (BuiltinTypes::xsGMonth->wxsTypeMatches(type)) { + return checkConstrainingFacetsDateTime(value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, BuiltinTypes::xsGMonth, errorMsg); + } else if (BuiltinTypes::xsGMonthDay->wxsTypeMatches(type)) { + return checkConstrainingFacetsDateTime(value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, BuiltinTypes::xsGMonthDay, errorMsg); + } else if (BuiltinTypes::xsGDay->wxsTypeMatches(type)) { + return checkConstrainingFacetsDateTime(value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, BuiltinTypes::xsGDay, errorMsg); + } else if (BuiltinTypes::xsTime->wxsTypeMatches(type)) { + return checkConstrainingFacetsDateTime(value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, BuiltinTypes::xsTime, errorMsg); + } else if (BuiltinTypes::xsDuration->wxsTypeMatches(type)) { + return checkConstrainingFacetsDuration(value, lexicalValue, facets, errorMsg); + } else if (BuiltinTypes::xsBoolean->wxsTypeMatches(type)) { + return checkConstrainingFacetsBoolean(value->as<Boolean>()->value(), lexicalValue, facets, errorMsg); + } else if (BuiltinTypes::xsHexBinary->wxsTypeMatches(type)) { + return checkConstrainingFacetsBinary(value->as<Base64Binary>()->asByteArray(), facets, BuiltinTypes::xsHexBinary, errorMsg); + } else if (BuiltinTypes::xsBase64Binary->wxsTypeMatches(type)) { + return checkConstrainingFacetsBinary(value->as<Base64Binary>()->asByteArray(), facets, BuiltinTypes::xsBase64Binary, errorMsg); + } else if (BuiltinTypes::xsQName->wxsTypeMatches(type)) { + return checkConstrainingFacetsQName(value->as<QNameValue>()->qName(), lexicalValue, facets, errorMsg); + } + + return true; +} + +bool XsdTypeChecker::checkConstrainingFacetsString(const QString &value, const XsdFacet::Hash &facets, const AnySimpleType::Ptr &type, QString &errorMsg) const +{ + if (facets.contains(XsdFacet::Length)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::Length); + const DerivedInteger<TypeNonNegativeInteger>::Ptr length = facet->value(); + if (length->toInteger() != value.length()) { + errorMsg = QtXmlPatterns::tr("string content does not match the length facet"); + return false; + } + } + if (facets.contains(XsdFacet::MinimumLength)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumLength); + const DerivedInteger<TypeNonNegativeInteger>::Ptr length = facet->value(); + if (length->toInteger() > value.length()) { + errorMsg = QtXmlPatterns::tr("string content does not match the minLength facet"); + return false; + } + } + if (facets.contains(XsdFacet::MaximumLength)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumLength); + const DerivedInteger<TypeNonNegativeInteger>::Ptr length = facet->value(); + if (length->toInteger() < value.length()) { + errorMsg = QtXmlPatterns::tr("string content does not match the maxLength facet"); + return false; + } + } + if (facets.contains(XsdFacet::Pattern)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::Pattern); + const AtomicValue::List multiValue = facet->multiValue(); + bool found = false; + for (int j = 0; j < multiValue.count(); ++j) { + const QString pattern = multiValue.at(j)->as<DerivedString<TypeString> >()->stringValue(); + const QRegExp exp = PatternPlatform::parsePattern(pattern, m_context, m_reflection); + if (exp.exactMatch(value)) { + found = true; + break; + } + } + + if (!found) { + errorMsg = QtXmlPatterns::tr("string content does not match pattern facet"); + return false; + } + } + if (facets.contains(XsdFacet::Enumeration)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration); + const DerivedString<TypeString>::Ptr valueStr = DerivedString<TypeString>::fromLexical(m_namePool, value); + + const AtomicValue::List multiValue = facet->multiValue(); + bool found = false; + for (int j = 0; j < multiValue.count(); ++j) { + if (XsdSchemaHelper::constructAndCompare(valueStr, AtomicComparator::OperatorEqual, multiValue.at(j), type, m_context, m_reflection)) { + found = true; + break; + } + } + + if (!found) { + errorMsg = QtXmlPatterns::tr("string content is not listed in the enumeration facet"); + return false; + } + } + if (facets.contains(XsdFacet::Assertion)) { + //TODO: implement + } + + return true; +} + +bool XsdTypeChecker::checkConstrainingFacetsSignedInteger(long long value, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const +{ + if (facets.contains(XsdFacet::MaximumInclusive)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumInclusive); + const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsLong, m_context, m_reflection); + if (facetValue->toInteger() < value) { + errorMsg = QtXmlPatterns::tr("signed integer content does not match the maxInclusive facet"); + return false; + } + } + if (facets.contains(XsdFacet::MaximumExclusive)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumExclusive); + const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsLong, m_context, m_reflection); + if (facetValue->toInteger() <= value) { + errorMsg = QtXmlPatterns::tr("signed integer content does not match the maxExclusive facet"); + return false; + } + } + if (facets.contains(XsdFacet::MinimumInclusive)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumInclusive); + const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsLong, m_context, m_reflection); + if (facetValue->toInteger() > value) { + errorMsg = QtXmlPatterns::tr("signed integer content does not match the minInclusive facet"); + return false; + } + } + if (facets.contains(XsdFacet::MinimumExclusive)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumExclusive); + const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsLong, m_context, m_reflection); + if (facetValue->toInteger() >= value) { + errorMsg = QtXmlPatterns::tr("signed integer content does not match the minExclusive facet"); + return false; + } + } + if (facets.contains(XsdFacet::Enumeration)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration); + const DerivedString<TypeString>::Ptr valueStr = DerivedString<TypeString>::fromLexical(m_namePool, QString::number(value)); + + const AtomicValue::List multiValue = facet->multiValue(); + bool found = false; + for (int j = 0; j < multiValue.count(); ++j) { + if (XsdSchemaHelper::constructAndCompare(valueStr, AtomicComparator::OperatorEqual, multiValue.at(j), BuiltinTypes::xsLong, m_context, m_reflection)) { + found = true; + break; + } + } + + if (!found) { + errorMsg = QtXmlPatterns::tr("signed integer content is not listed in the enumeration facet"); + return false; + } + } + if (facets.contains(XsdFacet::Pattern)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::Pattern); + const AtomicValue::List multiValue = facet->multiValue(); + bool found = false; + for (int j = 0; j < multiValue.count(); ++j) { + const QString pattern = multiValue.at(j)->as<DerivedString<TypeString> >()->stringValue(); + const QRegExp exp = PatternPlatform::parsePattern(pattern, m_context, m_reflection); + if (exp.exactMatch(lexicalValue)) { + found = true; + break; + } + } + + if (!found) { + errorMsg = QtXmlPatterns::tr("signed integer content does not match pattern facet"); + return false; + } + } + if (facets.contains(XsdFacet::TotalDigits)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::TotalDigits); + const DerivedInteger<TypePositiveInteger>::Ptr facetValue = facet->value(); + + if (totalDigitsForSignedLongLong(value) > facetValue->toInteger()) { + errorMsg = QtXmlPatterns::tr("signed integer content does not match in the totalDigits facet"); + return false; + } + } + if (facets.contains(XsdFacet::Assertion)) { + //TODO: implement + } + + return true; +} + +bool XsdTypeChecker::checkConstrainingFacetsUnsignedInteger(unsigned long long value, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const +{ + if (facets.contains(XsdFacet::MaximumInclusive)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumInclusive); + const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsUnsignedLong, m_context, m_reflection); + if (facetValue->toUnsignedInteger() < value) { + errorMsg = QtXmlPatterns::tr("unsigned integer content does not match the maxInclusive facet"); + return false; + } + } + if (facets.contains(XsdFacet::MaximumExclusive)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumExclusive); + const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsUnsignedLong, m_context, m_reflection); + if (facetValue->toUnsignedInteger() <= value) { + errorMsg = QtXmlPatterns::tr("unsigned integer content does not match the maxExclusive facet"); + return false; + } + } + if (facets.contains(XsdFacet::MinimumInclusive)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumInclusive); + const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsUnsignedLong, m_context, m_reflection); + if (facetValue->toUnsignedInteger() > value) { + errorMsg = QtXmlPatterns::tr("unsigned integer content does not match the minInclusive facet"); + return false; + } + } + if (facets.contains(XsdFacet::MinimumExclusive)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumExclusive); + const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsUnsignedLong, m_context, m_reflection); + if (facetValue->toUnsignedInteger() >= value) { + errorMsg = QtXmlPatterns::tr("unsigned integer content does not match the minExclusive facet"); + return false; + } + } + if (facets.contains(XsdFacet::Enumeration)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration); + const DerivedString<TypeString>::Ptr valueStr = DerivedString<TypeString>::fromLexical(m_namePool, QString::number(value)); + + const AtomicValue::List multiValue = facet->multiValue(); + bool found = false; + for (int j = 0; j < multiValue.count(); ++j) { + if (XsdSchemaHelper::constructAndCompare(valueStr, AtomicComparator::OperatorEqual, multiValue.at(j), BuiltinTypes::xsUnsignedLong, m_context, m_reflection)) { + found = true; + break; + } + } + + if (!found) { + errorMsg = QtXmlPatterns::tr("unsigned integer content is not listed in the enumeration facet"); + return false; + } + } + if (facets.contains(XsdFacet::Pattern)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::Pattern); + const AtomicValue::List multiValue = facet->multiValue(); + bool found = false; + for (int j = 0; j < multiValue.count(); ++j) { + const QString pattern = multiValue.at(j)->as<DerivedString<TypeString> >()->stringValue(); + const QRegExp exp = PatternPlatform::parsePattern(pattern, m_context, m_reflection); + if (exp.exactMatch(lexicalValue)) { + found = true; + break; + } + } + + if (!found) { + errorMsg = QtXmlPatterns::tr("unsigned integer content does not match pattern facet"); + return false; + } + } + if (facets.contains(XsdFacet::TotalDigits)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::TotalDigits); + const DerivedInteger<TypePositiveInteger>::Ptr facetValue = facet->value(); + + if (totalDigitsForUnsignedLongLong(value) > facetValue->toInteger()) { + errorMsg = QtXmlPatterns::tr("unsigned integer content does not match in the totalDigits facet"); + return false; + } + } + if (facets.contains(XsdFacet::Assertion)) { + //TODO: implement + } + + return true; +} + +bool XsdTypeChecker::checkConstrainingFacetsDouble(double value, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const +{ + if (facets.contains(XsdFacet::MaximumInclusive)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumInclusive); + const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsDouble, m_context, m_reflection); + if (facetValue->toDouble() < value) { + errorMsg = QtXmlPatterns::tr("double content does not match the maxInclusive facet"); + return false; + } + } + if (facets.contains(XsdFacet::MaximumExclusive)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumExclusive); + const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsDouble, m_context, m_reflection); + if (facetValue->toDouble() <= value) { + errorMsg = QtXmlPatterns::tr("double content does not match the maxExclusive facet"); + return false; + } + } + if (facets.contains(XsdFacet::MinimumInclusive)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumInclusive); + const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsDouble, m_context, m_reflection); + if (facetValue->toDouble() > value) { + errorMsg = QtXmlPatterns::tr("double content does not match the minInclusive facet"); + return false; + } + } + if (facets.contains(XsdFacet::MinimumExclusive)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumExclusive); + const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsDouble, m_context, m_reflection); + if (facetValue->toDouble() >= value) { + errorMsg = QtXmlPatterns::tr("double content does not match the minExclusive facet"); + return false; + } + } + if (facets.contains(XsdFacet::Enumeration)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration); + const DerivedString<TypeString>::Ptr valueStr = DerivedString<TypeString>::fromLexical(m_namePool, QString::number(value)); + + const AtomicValue::List multiValue = facet->multiValue(); + bool found = false; + for (int j = 0; j < multiValue.count(); ++j) { + if (XsdSchemaHelper::constructAndCompare(valueStr, AtomicComparator::OperatorEqual, multiValue.at(j), BuiltinTypes::xsDouble, m_context, m_reflection)) { + found = true; + break; + } + } + + if (!found) { + errorMsg = QtXmlPatterns::tr("double content is not listed in the enumeration facet"); + return false; + } + } + if (facets.contains(XsdFacet::Pattern)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::Pattern); + const AtomicValue::List multiValue = facet->multiValue(); + bool found = false; + for (int j = 0; j < multiValue.count(); ++j) { + const QString pattern = multiValue.at(j)->as<DerivedString<TypeString> >()->stringValue(); + const QRegExp exp = PatternPlatform::parsePattern(pattern, m_context, m_reflection); + if (exp.exactMatch(lexicalValue)) { + found = true; + break; + } + } + + if (!found) { + errorMsg = QtXmlPatterns::tr("double content does not match pattern facet"); + return false; + } + } + if (facets.contains(XsdFacet::Assertion)) { + //TODO: implement + } + + return true; +} + +bool XsdTypeChecker::checkConstrainingFacetsDecimal(const AtomicValue::Ptr &value, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const +{ + if (facets.contains(XsdFacet::FractionDigits)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::FractionDigits); + const DerivedInteger<TypePositiveInteger>::Ptr facetValue = facet->value(); + + if (fractionDigitsForDecimal(lexicalValue) > facetValue->toInteger()) { + errorMsg = QtXmlPatterns::tr("decimal content does not match in the fractionDigits facet"); + return false; + } + } + if (facets.contains(XsdFacet::TotalDigits)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::TotalDigits); + const DerivedInteger<TypePositiveInteger>::Ptr facetValue = facet->value(); + + if (totalDigitsForDecimal(lexicalValue) > facetValue->toInteger()) { + errorMsg = QtXmlPatterns::tr("decimal content does not match in the totalDigits facet"); + return false; + } + } + + return checkConstrainingFacetsDouble(value->as<Decimal>()->toDouble(), lexicalValue, facets, errorMsg); +} + +bool XsdTypeChecker::checkConstrainingFacetsDateTime(const QDateTime &value, const QString &lexicalValue, const XsdFacet::Hash &facets, const AnySimpleType::Ptr &type, QString &errorMsg) const +{ + if (facets.contains(XsdFacet::MaximumInclusive)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumInclusive); + const AbstractDateTime::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), type, m_context, m_reflection); + if (facetValue->toDateTime() < value) { + errorMsg = QtXmlPatterns::tr("date time content does not match the maxInclusive facet"); + return false; + } + } + if (facets.contains(XsdFacet::MaximumExclusive)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumExclusive); + const AbstractDateTime::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), type, m_context, m_reflection); + if (facetValue->toDateTime() <= value) { + errorMsg = QtXmlPatterns::tr("date time content does not match the maxExclusive facet"); + return false; + } + } + if (facets.contains(XsdFacet::MinimumInclusive)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumInclusive); + const AbstractDateTime::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), type, m_context, m_reflection); + if (facetValue->toDateTime() > value) { + errorMsg = QtXmlPatterns::tr("date time content does not match the minInclusive facet"); + return false; + } + } + if (facets.contains(XsdFacet::MinimumExclusive)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumExclusive); + const AbstractDateTime::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), type, m_context, m_reflection); + if (facetValue->toDateTime() >= value) { + errorMsg = QtXmlPatterns::tr("date time content does not match the minExclusive facet"); + return false; + } + } + if (facets.contains(XsdFacet::Enumeration)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration); + + const AtomicValue::List multiValue = facet->multiValue(); + bool found = false; + for (int j = 0; j < multiValue.count(); ++j) { + const AbstractDateTime::Ptr facetValue = ValueFactory::fromLexical(multiValue.at(j)->as<DerivedString<TypeString> >()->stringValue(), type, m_context, m_reflection); + if (facetValue->toDateTime() == value) { + found = true; + break; + } + } + + if (!found) { + errorMsg = QtXmlPatterns::tr("date time content is not listed in the enumeration facet"); + return false; + } + } + if (facets.contains(XsdFacet::Pattern)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::Pattern); + const AtomicValue::List multiValue = facet->multiValue(); + bool found = false; + for (int j = 0; j < multiValue.count(); ++j) { + const QString pattern = multiValue.at(j)->as<DerivedString<TypeString> >()->stringValue(); + const QRegExp exp = PatternPlatform::parsePattern(pattern, m_context, m_reflection); + if (exp.exactMatch(lexicalValue)) { + found = true; + break; + } + } + + if (!found) { + errorMsg = QtXmlPatterns::tr("date time content does not match pattern facet"); + return false; + } + } + + return true; +} + +bool XsdTypeChecker::checkConstrainingFacetsDuration(const AtomicValue::Ptr&, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const +{ + if (facets.contains(XsdFacet::MaximumInclusive)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumInclusive); + const DerivedString<TypeString>::Ptr value = DerivedString<TypeString>::fromLexical(m_namePool, lexicalValue); + + if (XsdSchemaHelper::constructAndCompare(facets.value(XsdFacet::MaximumInclusive)->value(), AtomicComparator::OperatorLessThan, value, BuiltinTypes::xsDuration, m_context, m_reflection)) { + errorMsg = QtXmlPatterns::tr("duration content does not match the maxInclusive facet"); + return false; + } + } + if (facets.contains(XsdFacet::MaximumExclusive)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumExclusive); + const DerivedString<TypeString>::Ptr value = DerivedString<TypeString>::fromLexical(m_namePool, lexicalValue); + + if (XsdSchemaHelper::constructAndCompare(facets.value(XsdFacet::MaximumExclusive)->value(), AtomicComparator::OperatorLessOrEqual, value, BuiltinTypes::xsDuration, m_context, m_reflection)) { + errorMsg = QtXmlPatterns::tr("duration content does not match the maxExclusive facet"); + return false; + } + } + if (facets.contains(XsdFacet::MinimumInclusive)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumInclusive); + const DerivedString<TypeString>::Ptr value = DerivedString<TypeString>::fromLexical(m_namePool, lexicalValue); + + if (XsdSchemaHelper::constructAndCompare(facets.value(XsdFacet::MinimumInclusive)->value(), AtomicComparator::OperatorGreaterThan, value, BuiltinTypes::xsDuration, m_context, m_reflection)) { + errorMsg = QtXmlPatterns::tr("duration content does not match the minInclusive facet"); + return false; + } + } + if (facets.contains(XsdFacet::MinimumExclusive)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumExclusive); + const DerivedString<TypeString>::Ptr value = DerivedString<TypeString>::fromLexical(m_namePool, lexicalValue); + + if (XsdSchemaHelper::constructAndCompare(facets.value(XsdFacet::MinimumExclusive)->value(), AtomicComparator::OperatorGreaterOrEqual, value, BuiltinTypes::xsDuration, m_context, m_reflection)) { + errorMsg = QtXmlPatterns::tr("duration content does not match the minExclusive facet"); + return false; + } + } + if (facets.contains(XsdFacet::Enumeration)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration); + const DerivedString<TypeString>::Ptr value = DerivedString<TypeString>::fromLexical(m_namePool, lexicalValue); + + const AtomicValue::List multiValue = facet->multiValue(); + bool found = false; + for (int j = 0; j < multiValue.count(); ++j) { + if (XsdSchemaHelper::constructAndCompare(multiValue.at(j), AtomicComparator::OperatorEqual, value, BuiltinTypes::xsDuration, m_context, m_reflection)) { + found = true; + break; + } + } + + if (!found) { + errorMsg = QtXmlPatterns::tr("duration content is not listed in the enumeration facet"); + return false; + } + } + if (facets.contains(XsdFacet::Pattern)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::Pattern); + const AtomicValue::List multiValue = facet->multiValue(); + bool found = false; + for (int j = 0; j < multiValue.count(); ++j) { + const QString pattern = multiValue.at(j)->as<DerivedString<TypeString> >()->stringValue(); + const QRegExp exp = PatternPlatform::parsePattern(pattern, m_context, m_reflection); + if (exp.exactMatch(lexicalValue)) { + found = true; + break; + } + } + + if (!found) { + errorMsg = QtXmlPatterns::tr("duration content does not match pattern facet"); + return false; + } + } + if (facets.contains(XsdFacet::Assertion)) { + //TODO: implement + } + + return true; +} + +bool XsdTypeChecker::checkConstrainingFacetsBoolean(bool, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const +{ + if (facets.contains(XsdFacet::Pattern)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::Pattern); + const AtomicValue::List multiValue = facet->multiValue(); + bool found = false; + for (int j = 0; j < multiValue.count(); ++j) { + const QString pattern = multiValue.at(j)->as<DerivedString<TypeString> >()->stringValue(); + const QRegExp exp = PatternPlatform::parsePattern(pattern, m_context, m_reflection); + if (exp.exactMatch(lexicalValue)) { + found = true; + break; + } + } + + if (!found) { + errorMsg = QtXmlPatterns::tr("boolean content does not match pattern facet"); + return false; + } + } + if (facets.contains(XsdFacet::Assertion)) { + //TODO: implement + } + + return true; +} + +bool XsdTypeChecker::checkConstrainingFacetsBinary(const QByteArray &value, const XsdFacet::Hash &facets, const AnySimpleType::Ptr &type, QString &errorMsg) const +{ + if (facets.contains(XsdFacet::Length)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::Length); + const DerivedInteger<TypeNonNegativeInteger>::Ptr length = facet->value(); + if (length->toInteger() != value.length()) { + errorMsg = QtXmlPatterns::tr("binary content does not match the length facet"); + return false; + } + } + if (facets.contains(XsdFacet::MinimumLength)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumLength); + const DerivedInteger<TypeNonNegativeInteger>::Ptr length = facet->value(); + if (length->toInteger() > value.length()) { + errorMsg = QtXmlPatterns::tr("binary content does not match the minLength facet"); + return false; + } + } + if (facets.contains(XsdFacet::MaximumLength)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumLength); + const DerivedInteger<TypeNonNegativeInteger>::Ptr length = facet->value(); + if (length->toInteger() < value.length()) { + errorMsg = QtXmlPatterns::tr("binary content does not match the maxLength facet"); + return false; + } + } + if (facets.contains(XsdFacet::Enumeration)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration); + const AtomicValue::List multiValue = facet->multiValue(); + bool found = false; + for (int j = 0; j < multiValue.count(); ++j) { + const Base64Binary::Ptr binary = ValueFactory::fromLexical(multiValue.at(j)->as<DerivedString<TypeString> >()->stringValue(), type, m_context, m_reflection); + const QByteArray facetValue = binary->as<Base64Binary>()->asByteArray(); + if (value == facetValue) { + found = true; + break; + } + } + + if (!found) { + errorMsg = QtXmlPatterns::tr("binary content is not listed in the enumeration facet"); + return false; + } + } + if (facets.contains(XsdFacet::Pattern)) { + //TODO: implement + } + if (facets.contains(XsdFacet::Assertion)) { + //TODO: implement + } + + return true; +} + +bool XsdTypeChecker::checkConstrainingFacetsQName(const QXmlName &value, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const +{ + if (facets.contains(XsdFacet::Length)) { + // always true + } + if (facets.contains(XsdFacet::MinimumLength)) { + // always true + } + if (facets.contains(XsdFacet::MaximumLength)) { + // always true + } + if (facets.contains(XsdFacet::Enumeration)) { + if (!XPathHelper::isQName(lexicalValue)) { + errorMsg = QtXmlPatterns::tr("invalid QName content: %1").arg(formatData(lexicalValue)); + return false; + } + + const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration); + const AtomicValue::List multiValue = facet->multiValue(); + bool found = false; + for (int j = 0; j < multiValue.count(); ++j) { + const QXmlName facetValue = multiValue.at(j)->as<QNameValue>()->qName(); + + if (value == facetValue) { + found = true; + break; + } + } + + if (!found) { + errorMsg = QtXmlPatterns::tr("QName content is not listed in the enumeration facet"); + return false; + } + } + if (facets.contains(XsdFacet::Pattern)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::Pattern); + const AtomicValue::List multiValue = facet->multiValue(); + bool found = false; + for (int j = 0; j < multiValue.count(); ++j) { + const QString pattern = multiValue.at(j)->as<DerivedString<TypeString> >()->stringValue(); + const QRegExp exp = PatternPlatform::parsePattern(pattern, m_context, m_reflection); + if (exp.exactMatch(lexicalValue)) { + found = true; + break; + } + } + + if (!found) { + errorMsg = QtXmlPatterns::tr("QName content does not match pattern facet"); + return false; + } + } + if (facets.contains(XsdFacet::Assertion)) { + //TODO: implement + } + + return true; +} + +bool XsdTypeChecker::checkConstrainingFacetsNotation(const QXmlName &value, const XsdFacet::Hash &facets, QString &errorMsg) const +{ + if (facets.contains(XsdFacet::Length)) { + // deprecated by spec + } + if (facets.contains(XsdFacet::MinimumLength)) { + // deprecated by spec + } + if (facets.contains(XsdFacet::MaximumLength)) { + // deprecated by spec + } + if (facets.contains(XsdFacet::Enumeration)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration); + const AtomicValue::List multiValue = facet->multiValue(); + bool found = false; + for (int j = 0; j < multiValue.count(); ++j) { + const QXmlName facetValue = multiValue.at(j)->as<QNameValue>()->qName(); + + if (value == facetValue) { + found = true; + break; + } + } + + if (!found) { + errorMsg = QtXmlPatterns::tr("notation content is not listed in the enumeration facet"); + return false; + } + } + if (facets.contains(XsdFacet::Pattern)) { + //TODO: implement + } + if (facets.contains(XsdFacet::Assertion)) { + //TODO: implement + } + + return true; +} + +bool XsdTypeChecker::checkConstrainingFacetsList(const QStringList &values, const QString &lexicalValue, const AnySimpleType::Ptr &itemType, const XsdFacet::Hash &facets, QString &errorMsg) const +{ + if (facets.contains(XsdFacet::Length)) { + const DerivedInteger<TypeNonNegativeInteger>::Ptr value = facets.value(XsdFacet::Length)->value(); + if (value->toInteger() != values.count()) { + errorMsg = QtXmlPatterns::tr("list content does not match length facet"); + return false; + } + } + if (facets.contains(XsdFacet::MinimumLength)) { + const DerivedInteger<TypeNonNegativeInteger>::Ptr value = facets.value(XsdFacet::MinimumLength)->value(); + if (value->toInteger() > values.count()) { + errorMsg = QtXmlPatterns::tr("list content does not match minLength facet"); + return false; + } + } + if (facets.contains(XsdFacet::MaximumLength)) { + const DerivedInteger<TypeNonNegativeInteger>::Ptr value = facets.value(XsdFacet::MaximumLength)->value(); + if (value->toInteger() < values.count()) { + errorMsg = QtXmlPatterns::tr("list content does not match maxLength facet"); + return false; + } + } + if (facets.contains(XsdFacet::Enumeration)) { + + bool found = false; + + // we have to handle lists with QName derived items differently + if (BuiltinTypes::xsQName->wxsTypeMatches(itemType) || BuiltinTypes::xsNOTATION->wxsTypeMatches(itemType)) { + // first convert the string values from the instance document to a list of QXmlName + QList<QXmlName> instanceValues; + for (int i = 0; i < values.count(); ++i) { + instanceValues.append(convertToQName(values.at(i))); + } + + // fetch the values from the facet and create a list of QXmlNames for each of them + const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration); + + const AtomicValue::List multiValue = facet->multiValue(); + for (int i = 0; i < multiValue.count(); ++i) { + const QStringList facetValueList = multiValue.at(i)->as<DerivedString<TypeString> >()->stringValue().split(QLatin1Char(' '), QString::SkipEmptyParts); + + // create the list of atomic string values + QList<QXmlName> facetValues; + for (int j = 0; j < facetValueList.count(); ++j) { + facetValues.append(convertToQName(facetValueList.at(j))); + } + + // check if both lists have the same length + if (instanceValues.count() != facetValues.count()) + continue; + + // check if both lists are equal, that means the contain equal items in the same order + bool matchesAll = true; + for (int j = 0; j < instanceValues.count(); ++j) { + if (instanceValues.at(j) != facetValues.at(j)) { + matchesAll = false; + break; + } + } + + if (matchesAll) { + found = true; + break; + } + } + } else { + // first convert the string values from the instance document to atomic values of type string + AtomicValue::List instanceValues; + for (int i = 0; i < values.count(); ++i) { + instanceValues.append(DerivedString<TypeString>::fromLexical(m_namePool, values.at(i))); + } + + // fetch the values from the facet and create a list of atomic string values for each of them + const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration); + + const AnySimpleType::Ptr targetType = comparableType(itemType); + + const AtomicValue::List multiValue = facet->multiValue(); + for (int i = 0; i < multiValue.count(); ++i) { + const QStringList facetValueList = multiValue.at(i)->as<DerivedString<TypeString> >()->stringValue().split(QLatin1Char(' '), QString::SkipEmptyParts); + + // create the list of atomic string values + AtomicValue::List facetValues; + for (int j = 0; j < facetValueList.count(); ++j) { + facetValues.append(DerivedString<TypeString>::fromLexical(m_namePool, facetValueList.at(j))); + } + + // check if both lists have the same length + if (instanceValues.count() != facetValues.count()) + continue; + + // check if both lists are equal, that means the contain equal items in the same order + bool matchesAll = true; + for (int j = 0; j < instanceValues.count(); ++j) { + if (!XsdSchemaHelper::constructAndCompare(instanceValues.at(j), AtomicComparator::OperatorEqual, facetValues.at(j), targetType, m_context, m_reflection)) { + matchesAll = false; + break; + } + } + + if (matchesAll) { + found = true; + break; + } + } + } + + if (!found) { + errorMsg = QtXmlPatterns::tr("list content is not listed in the enumeration facet"); + return false; + } + } + if (facets.contains(XsdFacet::Pattern)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::Pattern); + const AtomicValue::List multiValue = facet->multiValue(); + bool found = false; + for (int j = 0; j < multiValue.count(); ++j) { + const QString pattern = multiValue.at(j)->as<DerivedString<TypeString> >()->stringValue(); + const QRegExp exp = PatternPlatform::parsePattern(pattern, m_context, m_reflection); + if (exp.exactMatch(lexicalValue)) { + found = true; + break; + } + } + + if (!found) { + errorMsg = QtXmlPatterns::tr("list content does not match pattern facet"); + return false; + } + } + if (facets.contains(XsdFacet::Assertion)) { + //TODO: implement + } + + return true; +} + +bool XsdTypeChecker::checkConstrainingFacetsUnion(const QString &value, const QString &lexicalValue, const XsdSimpleType::Ptr &simpleType, const XsdFacet::Hash &facets, QString &errorMsg) const +{ + if (facets.contains(XsdFacet::Enumeration)) { + const AnySimpleType::List memberTypes = simpleType->memberTypes(); + + const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration); + + // convert the instance value into an atomic string value + const DerivedString<TypeString>::Ptr valueString = DerivedString<TypeString>::fromLexical(m_namePool, value); + + // collect the facet values into a list of atomic string values + const AtomicValue::List facetValues = facet->multiValue(); + + // compare the instance value against the facetValues for each member type and + // search for a match + + bool found = false; + for (int i = 0; i < memberTypes.count(); ++i) { + const AnySimpleType::Ptr targetType = comparableType(memberTypes.at(i)); + for (int j = 0; j < facetValues.count(); ++j) { + if (XsdSchemaHelper::constructAndCompare(valueString, AtomicComparator::OperatorEqual, facetValues.at(j), targetType, m_context, m_reflection)) { + found = true; + break; + } + } + } + + if (!found) { + errorMsg = QtXmlPatterns::tr("union content is not listed in the enumeration facet"); + return false; + } + } + if (facets.contains(XsdFacet::Pattern)) { + const XsdFacet::Ptr facet = facets.value(XsdFacet::Pattern); + const AtomicValue::List multiValue = facet->multiValue(); + bool found = false; + for (int j = 0; j < multiValue.count(); ++j) { + const QString pattern = multiValue.at(j)->as<DerivedString<TypeString> >()->stringValue(); + const QRegExp exp = PatternPlatform::parsePattern(pattern, m_context, m_reflection); + if (exp.exactMatch(lexicalValue)) { + found = true; + break; + } + } + + if (!found) { + errorMsg = QtXmlPatterns::tr("union content does not match pattern facet"); + return false; + } + } + if (facets.contains(XsdFacet::Assertion)) { + //TODO: implement + } + + return true; +} + +AtomicValue::Ptr XsdTypeChecker::fromLexical(const QString &value, const SchemaType::Ptr &type, const ReportContext::Ptr &context, const SourceLocationReflection *const reflection) const +{ + if (type->name(m_namePool) == BuiltinTypes::xsNOTATION->name(m_namePool) || type->name(m_namePool) == BuiltinTypes::xsQName->name(m_namePool)) { + if (value.simplified().isEmpty()) + return ValidationError::createError(QtXmlPatterns::tr("data of type %1 are not allowed to be empty").arg(formatType(m_namePool, BuiltinTypes::xsNOTATION))); + + const QXmlName valueName = convertToQName(value); + return QNameValue::fromValue(m_namePool, valueName); + } else { + return ValueFactory::fromLexical(value, type, context, reflection); + } +} + +QXmlName XsdTypeChecker::convertToQName(const QString &name) const +{ + const int pos = name.indexOf(QLatin1Char(':')); + + QXmlName::PrefixCode prefixCode = 0; + QXmlName::NamespaceCode namespaceCode; + QXmlName::LocalNameCode localNameCode; + if (pos != -1) { + prefixCode = m_context->namePool()->allocatePrefix(name.left(pos)); + namespaceCode = StandardNamespaces::empty; + for (int i = 0; i < m_namespaceBindings.count(); ++i) { + if (m_namespaceBindings.at(i).prefix() == prefixCode) { + namespaceCode = m_namespaceBindings.at(i).namespaceURI(); + break; + } + } + localNameCode = m_context->namePool()->allocateLocalName(name.mid(pos + 1)); + } else { + prefixCode = StandardPrefixes::empty; + namespaceCode = StandardNamespaces::empty; + for (int i = 0; i < m_namespaceBindings.count(); ++i) { + if (m_namespaceBindings.at(i).prefix() == prefixCode) { + namespaceCode = m_namespaceBindings.at(i).namespaceURI(); + break; + } + } + localNameCode = m_context->namePool()->allocateLocalName(name); + } + + return QXmlName(namespaceCode, localNameCode, prefixCode); +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdtypechecker_p.h b/src/xmlpatterns/schema/qxsdtypechecker_p.h new file mode 100644 index 0000000..88a0c63 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdtypechecker_p.h @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdTypeChecker_H +#define Patternist_XsdTypeChecker_H + +#include <QtXmlPatterns/QSourceLocation> + +#include "qschematype_p.h" +#include "qsourcelocationreflection_p.h" +#include "qxsdschemacontext_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QXmlQuery; + +namespace QPatternist +{ + /** + * @short An implementation of SourceLocationReflection that takes a QSourceLocation. + * + * This is a convenience class which provides a QSourceLocation with a SourceLocationReflection + * interface. + */ + class XsdSchemaSourceLocationReflection : public SourceLocationReflection + { + public: + XsdSchemaSourceLocationReflection(const QSourceLocation &location); + + virtual const SourceLocationReflection *actualReflection() const; + virtual QSourceLocation sourceLocation() const; + + private: + const QSourceLocation m_sourceLocation; + }; + + /** + * @short The class that provides methods for checking a string against a type. + * + * The class provides functionality for type-aware string handling. + */ + class XsdTypeChecker + { + public: + /** + * Creates a new type checker. + * + * @param context The schema context that is used for error reporting. + * @param namespaceBindings The namespace bindings that shall be used to check against xs:QName based types. + * @param location The source location that is used for error reporting. + */ + XsdTypeChecker(const XsdSchemaContext::Ptr &context, const QVector<QXmlName> &namespaceBindings, const QSourceLocation &location); + + /** + * Destroys the type checker. + */ + ~XsdTypeChecker(); + + /** + * Returns all facets for the given @p type. + * + * The list of facets is created by following the type hierarchy from xs:anyType down to the given type + * and merging the facets in each step. + */ + static XsdFacet::Hash mergedFacetsForType(const SchemaType::Ptr &type, const XsdSchemaContext::Ptr &context); + + /** + * Returns the normalized value for the given @p value. + * + * The normalized value is the original value with all the white space facets + * applied on it. + * + * @param value The original value. + * @param facets The hash of all facets of the values type. + */ + static QString normalizedValue(const QString &value, const XsdFacet::Hash &facets); + + /** + * Checks whether the @p normalizedString is valid according the given @p type. + * + * @param normalizedString The string in normalized form (whitespace facets applied). + * @param type The type the string shall be tested against. + * @param errorMsg Contains the error message if the normalizedString does not match the type. + * @param boundType The type the data was bound to during validation. + * + * @note The @p boundType only differs from @p type if the type is derived from an based union value. + */ + bool isValidString(const QString &normalizedString, const AnySimpleType::Ptr &type, QString &errorMsg, AnySimpleType::Ptr *boundType = 0) const; + + /** + * Returns whether the given @p value and @p otherValue are of @p type and are equal. + */ + bool valuesAreEqual(const QString &value, const QString &otherValue, const AnySimpleType::Ptr &type) const; + + private: + Q_DISABLE_COPY(XsdTypeChecker) + + /** + * Checks the given value against the facets of @p type. + */ + bool checkConstrainingFacets(const AtomicValue::Ptr &value, const QString &lexicalValue, const AnySimpleType::Ptr &type, QString &errorMsg) const; + bool checkConstrainingFacetsString(const QString &value, const XsdFacet::Hash &facets, const AnySimpleType::Ptr &type, QString &errorMsg) const; + bool checkConstrainingFacetsSignedInteger(long long value, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const; + bool checkConstrainingFacetsUnsignedInteger(unsigned long long value, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const; + bool checkConstrainingFacetsDouble(double value, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const; + bool checkConstrainingFacetsDecimal(const AtomicValue::Ptr &value, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const; + bool checkConstrainingFacetsDateTime(const QDateTime &value, const QString &lexicalValue, const XsdFacet::Hash &facets, const AnySimpleType::Ptr &type, QString &errorMsg) const; + bool checkConstrainingFacetsDuration(const AtomicValue::Ptr &value, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const; + bool checkConstrainingFacetsBoolean(bool value, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const; + bool checkConstrainingFacetsBinary(const QByteArray &value, const XsdFacet::Hash &facets, const AnySimpleType::Ptr &type, QString &errorMsg) const; + bool checkConstrainingFacetsQName(const QXmlName&, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const; + bool checkConstrainingFacetsNotation(const QXmlName &value, const XsdFacet::Hash &facets, QString &errorMsg) const; + bool checkConstrainingFacetsList(const QStringList &values, const QString &lexicalValue, const AnySimpleType::Ptr &itemType, const XsdFacet::Hash &facets, QString &errorMsg) const; + bool checkConstrainingFacetsUnion(const QString &value, const QString &lexicalValue, const XsdSimpleType::Ptr &simpleType, const XsdFacet::Hash &facets, QString &errorMsg) const; + + /** + * Creates an atomic value of @p type from the given string @p value. + */ + AtomicValue::Ptr fromLexical(const QString &value, const SchemaType::Ptr &type, const ReportContext::Ptr &context, const SourceLocationReflection *const reflection) const; + + /** + * Converts a qualified name into a QXmlName according to the namespace + * mappings of the current node. + */ + QXmlName convertToQName(const QString &name) const; + + XsdSchemaContext::Ptr m_context; + XsdSchema::Ptr m_schema; + const NamePool::Ptr m_namePool; + QVector<QXmlName> m_namespaceBindings; + SourceLocationReflection* m_reflection; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsduserschematype.cpp b/src/xmlpatterns/schema/qxsduserschematype.cpp new file mode 100644 index 0000000..bb545b4 --- /dev/null +++ b/src/xmlpatterns/schema/qxsduserschematype.cpp @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* + * NOTE: This file is included by qxsduserschematype_p.h + * if you need some includes, put them in qxsduserschematype_p.h (outside of the namespace) + */ + +template<typename TSuperClass> +void XsdUserSchemaType<TSuperClass>::setName(const QXmlName &name) +{ + m_name = name; +} + +template<typename TSuperClass> +QXmlName XsdUserSchemaType<TSuperClass>::name(const NamePool::Ptr&) const +{ + return m_name; +} + +template<typename TSuperClass> +QString XsdUserSchemaType<TSuperClass>::displayName(const NamePool::Ptr &np) const +{ + return np->displayName(m_name); +} + +template<typename TSuperClass> +void XsdUserSchemaType<TSuperClass>::setDerivationConstraints(const SchemaType::DerivationConstraints &constraints) +{ + m_derivationConstraints = constraints; +} + +template<typename TSuperClass> +SchemaType::DerivationConstraints XsdUserSchemaType<TSuperClass>::derivationConstraints() const +{ + return m_derivationConstraints; +} diff --git a/src/xmlpatterns/schema/qxsduserschematype_p.h b/src/xmlpatterns/schema/qxsduserschematype_p.h new file mode 100644 index 0000000..9138d09 --- /dev/null +++ b/src/xmlpatterns/schema/qxsduserschematype_p.h @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdUserSchemaType_H +#define Patternist_XsdUserSchemaType_H + +#include "qnamedschemacomponent_p.h" +#include "qschematype_p.h" +#include "qxsdannotated_p.h" + +template<typename N, typename M> class QHash; +template<typename N> class QList; + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short A base class for all user defined simple and complex types. + * + * This class was introduced to combine the SchemaType class and the + * NamedSchemaComponent class without explicit inheritance. + * + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + template<typename TSuperClass> + class XsdUserSchemaType : public TSuperClass, public NamedSchemaComponent, public XsdAnnotated + { + public: + typedef QExplicitlySharedDataPointer<XsdUserSchemaType> Ptr; + + /** + * Sets the @p name of the type. + */ + void setName(const QXmlName &name); + + /** + * Returns the name of the type. + * + * @param namePool The pool the name belongs to. + */ + virtual QXmlName name(const NamePool::Ptr &namePool) const; + + /** + * Returns the display name of the type. + * + * @param namePool The pool the name belongs to. + */ + virtual QString displayName(const NamePool::Ptr &namePool) const; + + /** + * Sets the derivation @p constraints of the type. + */ + void setDerivationConstraints(const SchemaType::DerivationConstraints &constraints); + + /** + * Returns the derivation constraints of the type. + */ + SchemaType::DerivationConstraints derivationConstraints() const; + + private: + QXmlName m_name; + SchemaType::DerivationConstraints m_derivationConstraints; + }; + + #include "qxsduserschematype.cpp" +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdvalidatedxmlnodemodel.cpp b/src/xmlpatterns/schema/qxsdvalidatedxmlnodemodel.cpp new file mode 100644 index 0000000..944ae79 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdvalidatedxmlnodemodel.cpp @@ -0,0 +1,215 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdvalidatedxmlnodemodel_p.h" + +#include <QtCore/QUrl> +#include <QtCore/QVariant> +#include <QtCore/QVector> + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +XsdValidatedXmlNodeModel::XsdValidatedXmlNodeModel(const QAbstractXmlNodeModel *model) + : m_internalModel(model) +{ +} + +XsdValidatedXmlNodeModel::~XsdValidatedXmlNodeModel() +{ +} + +QUrl XsdValidatedXmlNodeModel::baseUri(const QXmlNodeModelIndex &index) const +{ + return m_internalModel->baseUri(index); +} + +QUrl XsdValidatedXmlNodeModel::documentUri(const QXmlNodeModelIndex &index) const +{ + return m_internalModel->documentUri(index); +} + +QXmlNodeModelIndex::NodeKind XsdValidatedXmlNodeModel::kind(const QXmlNodeModelIndex &index) const +{ + return m_internalModel->kind(index); +} + +QXmlNodeModelIndex::DocumentOrder XsdValidatedXmlNodeModel::compareOrder(const QXmlNodeModelIndex &index, const QXmlNodeModelIndex &otherIndex) const +{ + return m_internalModel->compareOrder(index, otherIndex); +} + +QXmlNodeModelIndex XsdValidatedXmlNodeModel::root(const QXmlNodeModelIndex &index) const +{ + return m_internalModel->root(index); +} + +QXmlName XsdValidatedXmlNodeModel::name(const QXmlNodeModelIndex &index) const +{ + return m_internalModel->name(index); +} + +QString XsdValidatedXmlNodeModel::stringValue(const QXmlNodeModelIndex &index) const +{ + return m_internalModel->stringValue(index); +} + +QVariant XsdValidatedXmlNodeModel::typedValue(const QXmlNodeModelIndex &index) const +{ + return m_internalModel->typedValue(index); +} + +QExplicitlySharedDataPointer<QAbstractXmlForwardIterator<QXmlNodeModelIndex> > XsdValidatedXmlNodeModel::iterate(const QXmlNodeModelIndex &index, QXmlNodeModelIndex::Axis axis) const +{ + return m_internalModel->iterate(index, axis); +} + +QPatternist::ItemIteratorPtr XsdValidatedXmlNodeModel::sequencedTypedValue(const QXmlNodeModelIndex &index) const +{ + return m_internalModel->sequencedTypedValue(index); +} + +QPatternist::ItemTypePtr XsdValidatedXmlNodeModel::type(const QXmlNodeModelIndex &index) const +{ + return m_internalModel->type(index); +} + +QXmlName::NamespaceCode XsdValidatedXmlNodeModel::namespaceForPrefix(const QXmlNodeModelIndex &index, const QXmlName::PrefixCode prefix) const +{ + return m_internalModel->namespaceForPrefix(index, prefix); +} + +bool XsdValidatedXmlNodeModel::isDeepEqual(const QXmlNodeModelIndex &index, const QXmlNodeModelIndex &otherIndex) const +{ + return m_internalModel->isDeepEqual(index, otherIndex); +} + +void XsdValidatedXmlNodeModel::sendNamespaces(const QXmlNodeModelIndex &index, QAbstractXmlReceiver *const receiver) const +{ + m_internalModel->sendNamespaces(index, receiver); +} + +QVector<QXmlName> XsdValidatedXmlNodeModel::namespaceBindings(const QXmlNodeModelIndex &index) const +{ + return m_internalModel->namespaceBindings(index); +} + +QXmlNodeModelIndex XsdValidatedXmlNodeModel::elementById(const QXmlName &name) const +{ + return m_internalModel->elementById(name); +} + +QVector<QXmlNodeModelIndex> XsdValidatedXmlNodeModel::nodesByIdref(const QXmlName &name) const +{ + return m_internalModel->nodesByIdref(name); +} + +void XsdValidatedXmlNodeModel::copyNodeTo(const QXmlNodeModelIndex &index, QAbstractXmlReceiver *const receiver, const NodeCopySettings &settings) const +{ + return m_internalModel->copyNodeTo(index, receiver, settings); +} + +QXmlNodeModelIndex XsdValidatedXmlNodeModel::nextFromSimpleAxis(SimpleAxis axis, const QXmlNodeModelIndex &origin) const +{ + return m_internalModel->nextFromSimpleAxis(axis, origin); +} + +QVector<QXmlNodeModelIndex> XsdValidatedXmlNodeModel::attributes(const QXmlNodeModelIndex &index) const +{ + return m_internalModel->attributes(index); +} + +void XsdValidatedXmlNodeModel::setAssignedElement(const QXmlNodeModelIndex &index, const XsdElement::Ptr &element) +{ + m_assignedElements.insert(index, element); +} + +XsdElement::Ptr XsdValidatedXmlNodeModel::assignedElement(const QXmlNodeModelIndex &index) const +{ + if (m_assignedElements.contains(index)) + return m_assignedElements.value(index); + else + return XsdElement::Ptr(); +} + +void XsdValidatedXmlNodeModel::setAssignedAttribute(const QXmlNodeModelIndex &index, const XsdAttribute::Ptr &attribute) +{ + m_assignedAttributes.insert(index, attribute); +} + +XsdAttribute::Ptr XsdValidatedXmlNodeModel::assignedAttribute(const QXmlNodeModelIndex &index) const +{ + if (m_assignedAttributes.contains(index)) + return m_assignedAttributes.value(index); + else + return XsdAttribute::Ptr(); +} + +void XsdValidatedXmlNodeModel::setAssignedType(const QXmlNodeModelIndex &index, const SchemaType::Ptr &type) +{ + m_assignedTypes.insert(index, type); +} + +SchemaType::Ptr XsdValidatedXmlNodeModel::assignedType(const QXmlNodeModelIndex &index) const +{ + if (m_assignedTypes.contains(index)) + return m_assignedTypes.value(index); + else + return SchemaType::Ptr(); +} + +void XsdValidatedXmlNodeModel::addIdIdRefBinding(const QString &id, const NamedSchemaComponent::Ptr &binding) +{ + m_idIdRefBindings[id].insert(binding); +} + +QStringList XsdValidatedXmlNodeModel::idIdRefBindingIds() const +{ + return m_idIdRefBindings.keys(); +} + +QSet<NamedSchemaComponent::Ptr> XsdValidatedXmlNodeModel::idIdRefBindings(const QString &id) const +{ + return m_idIdRefBindings.value(id); +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdvalidatedxmlnodemodel_p.h b/src/xmlpatterns/schema/qxsdvalidatedxmlnodemodel_p.h new file mode 100644 index 0000000..6b6c03d --- /dev/null +++ b/src/xmlpatterns/schema/qxsdvalidatedxmlnodemodel_p.h @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdValidatedXmlNodeModel_H +#define Patternist_XsdValidatedXmlNodeModel_H + +#include "qabstractxmlnodemodel.h" + +#include "qabstractxmlforwarditerator_p.h" +#include "qitem_p.h" +#include "qschematype_p.h" +#include "qxsdelement_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short A delegate class that wraps around a QAbstractXmlNodeModel and provides + * additional validation specific information. + * + * This class represents the input XML document enriched with additional type + * information that has been assigned during validation. + * + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdValidatedXmlNodeModel : public QAbstractXmlNodeModel + { + public: + typedef QExplicitlySharedDataPointer<XsdValidatedXmlNodeModel> Ptr; + typedef QList<Ptr> List; + + /** + * Creates a new validated xml node model. + */ + XsdValidatedXmlNodeModel(const QAbstractXmlNodeModel *model); + + /** + * Destroys the validated xml node model. + */ + virtual ~XsdValidatedXmlNodeModel(); + + virtual QUrl baseUri(const QXmlNodeModelIndex &ni) const; + virtual QUrl documentUri(const QXmlNodeModelIndex &ni) const; + virtual QXmlNodeModelIndex::NodeKind kind(const QXmlNodeModelIndex &ni) const; + virtual QXmlNodeModelIndex::DocumentOrder compareOrder(const QXmlNodeModelIndex &ni1, const QXmlNodeModelIndex &ni2) const; + virtual QXmlNodeModelIndex root(const QXmlNodeModelIndex &n) const; + virtual QXmlName name(const QXmlNodeModelIndex &ni) const; + virtual QString stringValue(const QXmlNodeModelIndex &n) const; + virtual QVariant typedValue(const QXmlNodeModelIndex &n) const; + virtual QExplicitlySharedDataPointer<QAbstractXmlForwardIterator<QXmlNodeModelIndex> > iterate(const QXmlNodeModelIndex &ni, QXmlNodeModelIndex::Axis axis) const; + virtual QPatternist::ItemIteratorPtr sequencedTypedValue(const QXmlNodeModelIndex &ni) const; + virtual QPatternist::ItemTypePtr type(const QXmlNodeModelIndex &ni) const; + virtual QXmlName::NamespaceCode namespaceForPrefix(const QXmlNodeModelIndex &ni, const QXmlName::PrefixCode prefix) const; + virtual bool isDeepEqual(const QXmlNodeModelIndex &ni1, const QXmlNodeModelIndex &ni2) const; + virtual void sendNamespaces(const QXmlNodeModelIndex &n, QAbstractXmlReceiver *const receiver) const; + virtual QVector<QXmlName> namespaceBindings(const QXmlNodeModelIndex &n) const; + virtual QXmlNodeModelIndex elementById(const QXmlName &NCName) const; + virtual QVector<QXmlNodeModelIndex> nodesByIdref(const QXmlName &NCName) const; + virtual void copyNodeTo(const QXmlNodeModelIndex &node, QAbstractXmlReceiver *const receiver, const NodeCopySettings &) const; + + /** + * Sets the @p element that is assigned to the xml node at @p index. + */ + void setAssignedElement(const QXmlNodeModelIndex &index, const XsdElement::Ptr &element); + + /** + * Returns the element that is assigned to the xml node at @p index. + */ + XsdElement::Ptr assignedElement(const QXmlNodeModelIndex &index) const; + + /** + * Sets the @p attribute that is assigned to the xml node at @p index. + */ + void setAssignedAttribute(const QXmlNodeModelIndex &index, const XsdAttribute::Ptr &attribute); + + /** + * Returns the attribute that is assigned to the xml node at @p index. + */ + XsdAttribute::Ptr assignedAttribute(const QXmlNodeModelIndex &index) const; + + /** + * Sets the @p type that is assigned to the xml node at @p index. + * + * @note The type can be a different than the type of the element or + * attribute that is assigned to the index, since the instance + * document can overwrite it by xsi:type. + */ + void setAssignedType(const QXmlNodeModelIndex &index, const SchemaType::Ptr &type); + + /** + * Returns the type that is assigned to the xml node at @p index. + */ + SchemaType::Ptr assignedType(const QXmlNodeModelIndex &index) const; + + /** + * Adds the attribute or element @p binding with the given @p id. + */ + void addIdIdRefBinding(const QString &id, const NamedSchemaComponent::Ptr &binding); + + /** + * Returns a list of all binding ids. + */ + QStringList idIdRefBindingIds() const; + + /** + * Returns the set of bindings with the given @p id. + */ + QSet<NamedSchemaComponent::Ptr> idIdRefBindings(const QString &id) const; + + protected: + virtual QXmlNodeModelIndex nextFromSimpleAxis(SimpleAxis axis, const QXmlNodeModelIndex &origin) const; + virtual QVector<QXmlNodeModelIndex> attributes(const QXmlNodeModelIndex &element) const; + + private: + QExplicitlySharedDataPointer<const QAbstractXmlNodeModel> m_internalModel; + QHash<QXmlNodeModelIndex, XsdElement::Ptr> m_assignedElements; + QHash<QXmlNodeModelIndex, XsdAttribute::Ptr> m_assignedAttributes; + QHash<QXmlNodeModelIndex, SchemaType::Ptr> m_assignedTypes; + QHash<QString, QSet<NamedSchemaComponent::Ptr> > m_idIdRefBindings; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdvalidatinginstancereader.cpp b/src/xmlpatterns/schema/qxsdvalidatinginstancereader.cpp new file mode 100644 index 0000000..8af70f6 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdvalidatinginstancereader.cpp @@ -0,0 +1,1276 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdvalidatinginstancereader_p.h" + +#include "qabstractdatetime_p.h" +#include "qacceltreeresourceloader_p.h" +#include "qbase64binary_p.h" +#include "qboolean_p.h" +#include "qcommonnamespaces_p.h" +#include "qderivedinteger_p.h" +#include "qduration_p.h" +#include "qgenericstaticcontext_p.h" +#include "qhexbinary_p.h" +#include "qnamespaceresolver_p.h" +#include "qpatternplatform_p.h" +#include "qqnamevalue_p.h" +#include "qsourcelocationreflection_p.h" +#include "qvaluefactory_p.h" +#include "qxmlnamepool.h" +#include "qxmlquery_p.h" +#include "qxmlschema_p.h" +#include "qxsdschemahelper_p.h" +#include "qxsdschemamerger_p.h" +#include "qxsdstatemachine_p.h" +#include "qxsdstatemachinebuilder_p.h" +#include "qxsdtypechecker_p.h" + +#include "qxsdschemadebugger_p.h" + +#include <QtCore/QFile> +#include <QtXmlPatterns/QXmlQuery> +#include <QtXmlPatterns/QXmlResultItems> + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +namespace QPatternist +{ + template <> + template <> + bool XsdStateMachine<XsdTerm::Ptr>::inputEqualsTransition<QXmlName>(QXmlName name, XsdTerm::Ptr term) const + { + if (term->isElement()) { + return (XsdElement::Ptr(term)->name(m_namePool) == name); + } else if (term->isWildcard()) { + // wildcards using XsdWildcard::absentNamespace, so we have to fix that here + if (name.namespaceURI() == StandardNamespaces::empty) { + name.setNamespaceURI(m_namePool->allocateNamespace(XsdWildcard::absentNamespace())); + } + + return XsdSchemaHelper::wildcardAllowsExpandedName(name, XsdWildcard::Ptr(term), m_namePool); + } + + return false; + } +} + +XsdValidatingInstanceReader::XsdValidatingInstanceReader(XsdValidatedXmlNodeModel *model, const QUrl &documentUri, const XsdSchemaContext::Ptr &context) + : XsdInstanceReader(model, context) + , m_model(model) + , m_namePool(m_context->namePool()) + , m_xsiNilName(m_namePool->allocateQName(CommonNamespaces::XSI, QLatin1String("nil"))) + , m_xsiTypeName(m_namePool->allocateQName(CommonNamespaces::XSI, QLatin1String("type"))) + , m_xsiSchemaLocationName(m_namePool->allocateQName(CommonNamespaces::XSI, QLatin1String("schemaLocation"))) + , m_xsiNoNamespaceSchemaLocationName(m_namePool->allocateQName(CommonNamespaces::XSI, QLatin1String("noNamespaceSchemaLocation"))) + , m_documentUri(documentUri) +{ + m_idRefsType = m_context->schemaTypeFactory()->createSchemaType(m_namePool->allocateQName(CommonNamespaces::WXS, QLatin1String("IDREFS"))); +} + +void XsdValidatingInstanceReader::addSchema(const XsdSchema::Ptr &schema, const QUrl &locationUrl) +{ + if (!m_mergedSchemas.contains(locationUrl)) { + m_mergedSchemas.insert(locationUrl, QStringList() << schema->targetNamespace()); + } else { + QStringList &targetNamespaces = m_mergedSchemas[locationUrl]; + if (targetNamespaces.contains(schema->targetNamespace())) + return; + + targetNamespaces.append(schema->targetNamespace()); + } + + const XsdSchemaMerger merger(m_schema, schema); + m_schema = merger.mergedSchema(); +/* + XsdSchemaDebugger dbg(m_namePool); + dbg.dumpSchema(m_schema); +*/ +} + +bool XsdValidatingInstanceReader::read() +{ + while (!atEnd()) { + readNext(); + + if (isEndElement()) + return true; + + if (isStartElement()) { + const QXmlName elementName = name(); + const QXmlItem currentItem = item(); + bool hasStateMachine = false; + XsdElement::Ptr processedElement; + + if (!validate(hasStateMachine, processedElement)) + return false; + + read(); + + if (processedElement) { // for wildcard with 'skip' we have no element + m_model->setAssignedElement(currentItem.toNodeModelIndex(), processedElement); + + // check identity constraints after all child nodes have been + // validated, so that we know there assigned types + validateIdentityConstraint(processedElement, currentItem); + } + + if (!m_stateMachines.isEmpty() && hasStateMachine) { + if (!m_stateMachines.top().inEndState()) { + error(QtXmlPatterns::tr("element %1 is missing child element").arg(formatKeyword(m_namePool->displayName(elementName)))); + return false; + } + m_stateMachines.pop(); + } + } + } + + // final validations + + // check IDREF occurrences + const QStringList ids = m_model->idIdRefBindingIds(); + QSetIterator<QString> it(m_idRefs); + while (it.hasNext()) { + const QString id = it.next(); + if (!ids.contains(id)) { + error(QtXmlPatterns::tr("there is one IDREF value with no corresponding ID: %1").arg(formatKeyword(id))); + return false; + } + } + + return true; +} + +void XsdValidatingInstanceReader::error(const QString &msg) const +{ + m_context.data()->error(msg, XsdSchemaContext::XSDError, sourceLocation()); +} + +bool XsdValidatingInstanceReader::loadSchema(const QString &targetNamespace, const QUrl &location) +{ + const AutoPtr<QNetworkReply> reply(AccelTreeResourceLoader::load(location, m_context->networkAccessManager(), + m_context, AccelTreeResourceLoader::ContinueOnError)); + if (!reply) + return true; + + // we have to create a separated schema context here, that however shares the type factory + XsdSchemaContext::Ptr context(new XsdSchemaContext(m_namePool)); + context->m_schemaTypeFactory = m_context->m_schemaTypeFactory; + + QXmlSchemaPrivate schema(context); + schema.load(reply.data(), location, targetNamespace); + if (!schema.isValid()) { + error(QtXmlPatterns::tr("loaded schema file is invalid")); + return false; + } + + addSchema(schema.m_schemaParserContext->schema(), location); + + return true; +} + +bool XsdValidatingInstanceReader::validate(bool &hasStateMachine, XsdElement::Ptr &processedElement) +{ + // first check if a custom schema is defined + if (hasAttribute(m_xsiSchemaLocationName)) { + const QString schemaLocation = attribute(m_xsiSchemaLocationName); + const QStringList parts = schemaLocation.split(QLatin1Char(' '), QString::SkipEmptyParts); + if ((parts.count()%2) == 1) { + error(QtXmlPatterns::tr("%1 contains invalid data").arg(formatKeyword(m_namePool, m_xsiSchemaLocationName))); + return false; + } + + for (int i = 0; i < parts.count(); i += 2) { + const QString identifier = QString::fromLatin1("%1 %2").arg(parts.at(i)).arg(parts.at(i + 1)); + if (m_processedSchemaLocations.contains(identifier)) + continue; + else + m_processedSchemaLocations.insert(identifier); + + // check constraint 4) from http://www.w3.org/TR/xmlschema-1/#schema-loc (only valid for XML Schema 1.0?) + if (m_processedNamespaces.contains(parts.at(i))) { + error(QtXmlPatterns::tr("xsi:schemaLocation namespace %1 has already appeared earlier in the instance document").arg(formatKeyword(parts.at(i)))); + return false; + } + + QUrl url(parts.at(i + 1)); + if (url.isRelative()) { + Q_ASSERT(m_documentUri.isValid()); + + url = m_documentUri.resolved(url); + } + + loadSchema(parts.at(i), url); + } + } + + if (hasAttribute(m_xsiNoNamespaceSchemaLocationName)) { + const QString schemaLocation = attribute(m_xsiNoNamespaceSchemaLocationName); + + if (!m_processedSchemaLocations.contains(schemaLocation)) { + m_processedSchemaLocations.insert(schemaLocation); + + if (m_processedNamespaces.contains(QString())) { + error(QtXmlPatterns::tr("xsi:noNamespaceSchemaLocation cannot appear after the first no-namespace element or attribute")); + return false; + } + + QUrl url(schemaLocation); + if (url.isRelative()) { + Q_ASSERT(m_documentUri.isValid()); + + url = m_documentUri.resolved(url); + } + + loadSchema(QString(), url); + } + } + + m_processedNamespaces.insert(m_namePool->stringForNamespace(name().namespaceURI())); + + if (!m_schema) { + error(QtXmlPatterns::tr("no schema defined for validation")); + return false; + } + + // check if we are 'inside' a type definition + if (m_stateMachines.isEmpty()) { + // find out the type of the top-level element + XsdElement::Ptr element = elementByName(name()); + if (!element) { + if (!hasAttribute(m_xsiTypeName)) { + error(QtXmlPatterns::tr("no definition for element %1 available").arg(formatKeyword(m_namePool, name()))); + return false; + } + + // This instance document has an element with no definition in the schema + // but an explicitly given type, that is fine according to the spec. + // We will create an element definition manually here and continue the + // normal validation process + element = XsdElement::Ptr(new XsdElement()); + element->setName(name()); + element->setIsAbstract(false); + element->setIsNillable(hasAttribute(m_xsiNilName)); + + const QString type = qNameAttribute(m_xsiTypeName); + const QXmlName typeName = convertToQName(type); + + const SchemaType::Ptr elementType = typeByName(typeName); + if (!elementType) { + error(QtXmlPatterns::tr("specified type %1 is not known to the schema").arg(formatType(m_namePool, typeName))); + return false; + } + element->setType(elementType); + } + + // rememeber the element we process + processedElement = element; + + if (!validateElement(element, hasStateMachine)) { + return false; + } + + } else { + if (!m_stateMachines.top().proceed<QXmlName>(name())) { + error(QtXmlPatterns::tr("element %1 is not defined in this scope").arg(formatKeyword(m_namePool, name()))); + return false; + } + + const XsdTerm::Ptr term = m_stateMachines.top().lastTransition(); + if (term->isElement()) { + const XsdElement::Ptr element(term); + + // rememeber the element we process + processedElement = element; + + if (!validateElement(element, hasStateMachine)) + return false; + + } else { + const XsdWildcard::Ptr wildcard(term); + if (wildcard->processContents() != XsdWildcard::Skip) { + XsdElement::Ptr elementDeclaration = elementByName(name()); + if (!elementDeclaration) { + if (hasAttribute(m_xsiTypeName)) { + // This instance document has an element with no definition in the schema + // but an explicitly given type, that is fine according to the spec. + // We will create an element definition manually here and continue the + // normal validation process + elementDeclaration = XsdElement::Ptr(new XsdElement()); + elementDeclaration->setName(name()); + elementDeclaration->setIsAbstract(false); + elementDeclaration->setIsNillable(hasAttribute(m_xsiNilName)); + + const QString type = qNameAttribute(m_xsiTypeName); + const QXmlName typeName = convertToQName(type); + + const SchemaType::Ptr elementType = typeByName(typeName); + if (!elementType) { + error(QtXmlPatterns::tr("specified type %1 is not known to the schema").arg(formatType(m_namePool, typeName))); + return false; + } + elementDeclaration->setType(elementType); + } + } + + if (!elementDeclaration) { + if (wildcard->processContents() == XsdWildcard::Strict) { + error(QtXmlPatterns::tr("declaration for element %1 does not exist").arg(formatKeyword(m_namePool->displayName(name())))); + return false; + } else { + // in this case we put a state machine for the xs:anyType on the statemachine stack, + // so we accept every content of this element + + createAndPushStateMachine(anyType()->contentType()->particle()); + hasStateMachine = true; + } + } else { + if (!validateElement(elementDeclaration, hasStateMachine)) { + if (wildcard->processContents() == XsdWildcard::Strict) { + error(QtXmlPatterns::tr("element %1 contains invalid content").arg(formatKeyword(m_namePool->displayName(name())))); + return false; + } + } + + // rememeber the type of that element node + m_model->setAssignedType(item().toNodeModelIndex(), elementDeclaration->type()); + } + } else { // wildcard process contents type is Skip + // in this case we put a state machine for the xs:anyType on the statemachine stack, + // so we accept every content of this element + + const XsdWildcard::Ptr wildcard(new XsdWildcard()); + wildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Any); + wildcard->setProcessContents(XsdWildcard::Skip); + + const XsdParticle::Ptr outerParticle(new XsdParticle()); + outerParticle->setMinimumOccurs(1); + outerParticle->setMaximumOccurs(1); + + const XsdParticle::Ptr innerParticle(new XsdParticle()); + innerParticle->setMinimumOccurs(0); + innerParticle->setMaximumOccursUnbounded(true); + innerParticle->setTerm(wildcard); + + const XsdModelGroup::Ptr outerModelGroup(new XsdModelGroup()); + outerModelGroup->setCompositor(XsdModelGroup::SequenceCompositor); + outerModelGroup->setParticles(XsdParticle::List() << innerParticle); + outerParticle->setTerm(outerModelGroup); + + createAndPushStateMachine(outerParticle); + hasStateMachine = true; + } + } + } + + return true; +} + +void XsdValidatingInstanceReader::createAndPushStateMachine(const XsdParticle::Ptr &particle) +{ + XsdStateMachine<XsdTerm::Ptr> stateMachine(m_namePool); + + XsdStateMachineBuilder builder(&stateMachine, m_namePool, XsdStateMachineBuilder::ValidatingMode); + const XsdStateMachine<XsdTerm::Ptr>::StateId endState = builder.reset(); + const XsdStateMachine<XsdTerm::Ptr>::StateId startState = builder.buildParticle(particle, endState); + builder.addStartState(startState); + +/* + QString fileName = QString("/tmp/foo_%1.dot").arg(m_namePool->displayName(complexType->name(m_namePool))); + QString pngFileName = QString("/tmp/foo_%1.png").arg(m_namePool->displayName(complexType->name(m_namePool))); + QFile file(fileName); + file.open(QIODevice::WriteOnly); + stateMachine.outputGraph(&file, "Hello"); + file.close(); + ::system(QString("dot -Tpng %1 -o%2").arg(fileName).arg(pngFileName).toLatin1().data()); +*/ + + stateMachine = stateMachine.toDFA(); + + m_stateMachines.push(stateMachine); +} + +bool XsdValidatingInstanceReader::validateElement(const XsdElement::Ptr &declaration, bool &hasStateMachine) +{ + // http://www.w3.org/TR/xmlschema11-1/#d0e10998 + + bool isNilled = false; + + // 1 tested already, 'declaration' corresponds D + + // 2 + if (declaration->isAbstract()) { + error(QtXmlPatterns::tr("element %1 is declared as abstract").arg(formatKeyword(declaration->displayName(m_namePool)))); + return false; + } + + // 3 + if (!declaration->isNillable()) { + if (hasAttribute(m_xsiNilName)) { + error(QtXmlPatterns::tr("element %1 is not nillable").arg(formatKeyword(declaration->displayName(m_namePool)))); + return false; // 3.1 + } + } else { + if (hasAttribute(m_xsiNilName)) { + const QString value = attribute(m_xsiNilName); + const Boolean::Ptr nil = Boolean::fromLexical(value); + if (nil->hasError()) { + error(QtXmlPatterns::tr("attribute %1 contains invalid data: %1").arg(formatKeyword(QLatin1String("nil"))).arg(formatData(value))); + return false; + } + + // 3.2.3 + if (nil->as<Boolean>()->value() == true) { + // 3.2.3.1 + if (hasChildElement() || hasChildText()) { + error(QtXmlPatterns::tr("element contains content although it is nillable")); + return false; + } + + // 3.2.3.2 + if (declaration->valueConstraint() && declaration->valueConstraint()->variety() == XsdElement::ValueConstraint::Fixed) { + error(QtXmlPatterns::tr("fixed value constrained not allowed if element is nillable")); + return false; + } + } + + isNilled = nil->as<Boolean>()->value(); + } + } + + SchemaType::Ptr finalElementType = declaration->type(); + + // 4 + if (hasAttribute(m_xsiTypeName)) { + const QString type = qNameAttribute(m_xsiTypeName); + const QXmlName typeName = convertToQName(type); + + const SchemaType::Ptr elementType = typeByName(typeName); + // 4.1 + if (!elementType) { + error(QtXmlPatterns::tr("specified type %1 is not known to the schema").arg(formatType(m_namePool, typeName))); + return false; + } + + // 4.2 + SchemaType::DerivationConstraints constraints = 0; + if (declaration->disallowedSubstitutions() & NamedSchemaComponent::ExtensionConstraint) + constraints |= SchemaType::ExtensionConstraint; + if (declaration->disallowedSubstitutions() & NamedSchemaComponent::RestrictionConstraint) + constraints |= SchemaType::RestrictionConstraint; + + if (!XsdSchemaHelper::isValidlySubstitutable(elementType, declaration->type(), constraints)) { + if (declaration->type()->name(m_namePool) != BuiltinTypes::xsAnyType->name(m_namePool)) { // xs:anyType is a valid substitutable type here + error(QtXmlPatterns::tr("specified type %1 is not validly substitutable with element type %2").arg(formatType(m_namePool, elementType)).arg(formatType(m_namePool, declaration->type()))); + return false; + } + } + + finalElementType = elementType; + } + + if (!validateElementType(declaration, finalElementType, isNilled, hasStateMachine)) + return false; + + return true; +} + +bool XsdValidatingInstanceReader::validateElementType(const XsdElement::Ptr &declaration, const SchemaType::Ptr &type, bool isNilled, bool &hasStateMachine) +{ + // @see http://www.w3.org/TR/xmlschema11-1/#d0e11749 + + // 1 checked already + + // 2 + if (type->isComplexType() && type->isDefinedBySchema()) { + if (XsdComplexType::Ptr(type)->isAbstract()) { + error(QtXmlPatterns::tr("complex type %1 is not allowed to be abstract").arg(formatType(m_namePool, type))); + return false; + } + } + + // 3 + if (type->isSimpleType()) + return validateElementSimpleType(declaration, type, isNilled); // 3.1 + else + return validateElementComplexType(declaration, type, isNilled, hasStateMachine); // 3.2 +} + +bool XsdValidatingInstanceReader::validateElementSimpleType(const XsdElement::Ptr &declaration, const SchemaType::Ptr &type, bool isNilled) +{ + // @see http://www.w3.org/TR/xmlschema11-1/#d0e11749 + + // 3.1.1 + const QSet<QXmlName> allowedAttributes(QSet<QXmlName>() << m_xsiNilName << m_xsiTypeName << m_xsiSchemaLocationName << m_xsiNoNamespaceSchemaLocationName); + QSet<QXmlName> elementAttributes = attributeNames(); + elementAttributes.subtract(allowedAttributes); + if (!elementAttributes.isEmpty()) { + error(QtXmlPatterns::tr("element %1 contains not allowed attributes").arg(formatKeyword(declaration->displayName(m_namePool)))); + return false; + } + + // 3.1.2 + if (hasChildElement()) { + error(QtXmlPatterns::tr("element %1 contains not allowed child element").arg(formatKeyword(declaration->displayName(m_namePool)))); + return false; + } + + // 3.1.3 + if (!isNilled) { + const XsdFacet::Hash facets = XsdTypeChecker::mergedFacetsForType(type, m_context); + + QString actualValue; + if (hasChildText()) { + actualValue = XsdTypeChecker::normalizedValue(text(), facets); + } else { + if (declaration->valueConstraint()) + actualValue = XsdTypeChecker::normalizedValue(declaration->valueConstraint()->value(), facets); + } + + QString errorMsg; + AnySimpleType::Ptr boundType; + + const XsdTypeChecker checker(m_context, namespaceBindings(item().toNodeModelIndex()), sourceLocation()); + if (!checker.isValidString(actualValue, type, errorMsg, &boundType)) { + error(QtXmlPatterns::tr("content of element %1 does not match its type definition: %2").arg(formatKeyword(declaration->displayName(m_namePool))).arg(errorMsg)); + return false; + } + + // additional check + if (declaration->valueConstraint() && declaration->valueConstraint()->variety() == XsdElement::ValueConstraint::Fixed) { + const QString actualConstraintValue = XsdTypeChecker::normalizedValue(declaration->valueConstraint()->value(), facets); + if (!text().isEmpty() && !checker.valuesAreEqual(actualValue, actualConstraintValue, type)) { + error(QtXmlPatterns::tr("content of element %1 does not match defined value constraint").arg(formatKeyword(declaration->displayName(m_namePool)))); + return false; + } + } + } + + // 4 checked in validateElement already + + // rememeber the type of that element node + m_model->setAssignedType(item().toNodeModelIndex(), type); + + const XsdFacet::Hash facets = XsdTypeChecker::mergedFacetsForType(type, m_context); + const QString actualValue = XsdTypeChecker::normalizedValue(text(), facets); + + if (BuiltinTypes::xsID->wxsTypeMatches(type)) { + addIdIdRefBinding(actualValue, declaration); + } + + if (m_idRefsType->wxsTypeMatches(type)) { + const QStringList idRefs = actualValue.split(QLatin1Char(' '), QString::SkipEmptyParts); + for (int i = 0; i < idRefs.count(); ++i) { + m_idRefs.insert(idRefs.at(i)); + } + } else if (BuiltinTypes::xsIDREF->wxsTypeMatches(type)) { + m_idRefs.insert(actualValue); + } + + return true; +} + +static bool hasIDAttributeUse(const XsdAttributeUse::List &uses) +{ + const int count = uses.count(); + for (int i = 0; i < count; ++i) { + if (BuiltinTypes::xsID->wxsTypeMatches(uses.at(i)->attribute()->type())) + return true; + } + + return false; +} + +bool XsdValidatingInstanceReader::validateElementComplexType(const XsdElement::Ptr &declaration, const SchemaType::Ptr &type, bool isNilled, bool &hasStateMachine) +{ + // @see http://www.w3.org/TR/xmlschema11-1/#cvc-complex-type + + // 1 + if (!isNilled) { + XsdComplexType::Ptr complexType; + + if (type->isDefinedBySchema()) { + complexType = XsdComplexType::Ptr(type); + } else { + if (type->name(m_namePool) == BuiltinTypes::xsAnyType->name(m_namePool)) + complexType = anyType(); + } + + if (complexType) { + // 1.1 + if (complexType->contentType()->variety() == XsdComplexType::ContentType::Empty) { + if (hasChildText() || hasChildElement()) { + error(QtXmlPatterns::tr("element %1 contains not allowed child content").arg(formatKeyword(declaration->displayName(m_namePool)))); + return false; + } + } + + // 1.2 + if (complexType->contentType()->variety() == XsdComplexType::ContentType::Simple) { + if (hasChildElement()) { + error(QtXmlPatterns::tr("element %1 contains not allowed child element").arg(formatKeyword(declaration->displayName(m_namePool)))); + return false; + } + + const XsdFacet::Hash facets = XsdTypeChecker::mergedFacetsForType(complexType->contentType()->simpleType(), m_context); + QString actualValue; + if (hasChildText()) { + actualValue = XsdTypeChecker::normalizedValue(text(), facets); + } else { + if (declaration->valueConstraint()) + actualValue = XsdTypeChecker::normalizedValue(declaration->valueConstraint()->value(), facets); + } + + QString errorMsg; + AnySimpleType::Ptr boundType; + const XsdTypeChecker checker(m_context, namespaceBindings(item().toNodeModelIndex()), sourceLocation()); + if (!checker.isValidString(actualValue, complexType->contentType()->simpleType(), errorMsg, &boundType)) { + error(QtXmlPatterns::tr("content of element %1 does not match its type definition: %2").arg(formatKeyword(declaration->displayName(m_namePool))).arg(errorMsg)); + return false; + } + + // additional check + if (declaration->valueConstraint() && declaration->valueConstraint()->variety() == XsdElement::ValueConstraint::Fixed) { + if (!checker.valuesAreEqual(actualValue, declaration->valueConstraint()->value(), boundType)) { + error(QtXmlPatterns::tr("content of element %1 does not match defined value constraint").arg(formatKeyword(declaration->displayName(m_namePool)))); + return false; + } + } + } + + // 1.3 + if (complexType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly) { + if (!text().simplified().isEmpty()) { + error(QtXmlPatterns::tr("element %1 contains not allowed text content").arg(formatKeyword(declaration->displayName(m_namePool)))); + return false; + } + } + + // 1.4 + if (complexType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly || + complexType->contentType()->variety() == XsdComplexType::ContentType::Mixed) { + + if (complexType->contentType()->particle()) { + createAndPushStateMachine(complexType->contentType()->particle()); + hasStateMachine = true; + } + + // additional check + if (complexType->contentType()->variety() == XsdComplexType::ContentType::Mixed) { + if (declaration->valueConstraint() && declaration->valueConstraint()->variety() == XsdElement::ValueConstraint::Fixed) { + if (hasChildElement()) { + error(QtXmlPatterns::tr("element %1 can not contain other elements, as it has a fixed content").arg(formatKeyword(declaration->displayName(m_namePool)))); + return false; + } + + const XsdFacet::Hash facets = XsdTypeChecker::mergedFacetsForType(complexType->contentType()->simpleType(), m_context); + QString actualValue; + if (hasChildText()) { + actualValue = XsdTypeChecker::normalizedValue(text(), facets); + } else { + if (declaration->valueConstraint()) + actualValue = XsdTypeChecker::normalizedValue(declaration->valueConstraint()->value(), facets); + } + + if (actualValue != declaration->valueConstraint()->value()) { + error(QtXmlPatterns::tr("content of element %1 does not match defined value constraint").arg(formatKeyword(declaration->displayName(m_namePool)))); + return false; + } + } + } + } + } + } + + if (type->isDefinedBySchema()) { + const XsdComplexType::Ptr complexType(type); + + // create a lookup hash for faster access + QHash<QXmlName, XsdAttributeUse::Ptr> attributeUseHash; + { + const XsdAttributeUse::List attributeUses = complexType->attributeUses(); + for (int i = 0; i < attributeUses.count(); ++i) + attributeUseHash.insert(attributeUses.at(i)->attribute()->name(m_namePool), attributeUses.at(i)); + } + + const QSet<QXmlName> attributes(attributeNames()); + + // 3 + QHashIterator<QXmlName, XsdAttributeUse::Ptr> usesIt(attributeUseHash); + while (usesIt.hasNext()) { + usesIt.next(); + + if (usesIt.value()->isRequired()) { + if (!attributes.contains(usesIt.key())) { + error(QtXmlPatterns::tr("element %1 is missing required attribute %2").arg(formatKeyword(declaration->displayName(m_namePool))) + .arg(formatKeyword(m_namePool->displayName(usesIt.key())))); + return false; + } + } + } + + bool hasIDAttribute = hasIDAttributeUse(complexType->attributeUses()); + + // 2 + QSetIterator<QXmlName> it(attributes); + while (it.hasNext()) { + const QXmlName attributeName = it.next(); + + // skip builtin attributes + if (attributeName == m_xsiNilName || + attributeName == m_xsiTypeName || + attributeName == m_xsiSchemaLocationName || + attributeName == m_xsiNoNamespaceSchemaLocationName) + continue; + + // 2.1 + if (attributeUseHash.contains(attributeName) && (attributeUseHash.value(attributeName)->useType() != XsdAttributeUse::ProhibitedUse)) { + if (!validateAttribute(attributeUseHash.value(attributeName), attribute(attributeName))) + return false; + } else { // 2.2 + if (complexType->attributeWildcard()) { + const XsdWildcard::Ptr wildcard(complexType->attributeWildcard()); + if (!validateAttributeWildcard(attributeName, wildcard)) { + error(QtXmlPatterns::tr("attribute %1 does not match the attribute wildcard").arg(formatKeyword(m_namePool->displayName(attributeName)))); + return false; + } + + if (wildcard->processContents() != XsdWildcard::Skip) { + const XsdAttribute::Ptr attributeDeclaration = attributeByName(attributeName); + + if (!attributeDeclaration) { + if (wildcard->processContents() == XsdWildcard::Strict) { + error(QtXmlPatterns::tr("declaration for attribute %1 does not exist").arg(formatKeyword(m_namePool->displayName(attributeName)))); + return false; + } + } else { + if (BuiltinTypes::xsID->wxsTypeMatches(attributeDeclaration->type())) { + if (hasIDAttribute) { + error(QtXmlPatterns::tr("element %1 contains two attributes of type %2") + .arg(formatKeyword(declaration->displayName(m_namePool))) + .arg(formatKeyword("ID"))); + return false; + } + + hasIDAttribute = true; + } + + if (!validateAttribute(attributeDeclaration, attribute(attributeName))) { + if (wildcard->processContents() == XsdWildcard::Strict) { + error(QtXmlPatterns::tr("attribute %1 contains invalid content").arg(formatKeyword(m_namePool->displayName(attributeName)))); + return false; + } + } + } + } + } else { + error(QtXmlPatterns::tr("element %1 contains unknown attribute %2").arg(formatKeyword(declaration->displayName(m_namePool))) + .arg(formatKeyword(m_namePool->displayName(attributeName)))); + return false; + } + } + } + } + + // 4 + // so what?... + + // 5 + // hmm... + + // 6 + // TODO: check assertions + + // 7 + // TODO: check type table restrictions + + // rememeber the type of that element node + m_model->setAssignedType(item().toNodeModelIndex(), type); + + return true; +} + +bool XsdValidatingInstanceReader::validateAttribute(const XsdAttributeUse::Ptr &declaration, const QString &value) +{ + const AnySimpleType::Ptr attributeType = declaration->attribute()->type(); + const XsdFacet::Hash facets = XsdTypeChecker::mergedFacetsForType(attributeType, m_context); + + const QString actualValue = XsdTypeChecker::normalizedValue(value, facets); + + QString errorMsg; + AnySimpleType::Ptr boundType; + + const QXmlNodeModelIndex index = attributeItem(declaration->attribute()->name(m_namePool)).toNodeModelIndex(); + + const XsdTypeChecker checker(m_context, namespaceBindings(index), sourceLocation()); + if (!checker.isValidString(actualValue, attributeType, errorMsg, &boundType)) { + error(QtXmlPatterns::tr("content of attribute %1 does not match its type definition: %2").arg(formatKeyword(declaration->attribute()->displayName(m_namePool))).arg(errorMsg)); + return false; + } + + // @see http://www.w3.org/TR/xmlschema11-1/#cvc-au + if (declaration->valueConstraint() && declaration->valueConstraint()->variety() == XsdAttributeUse::ValueConstraint::Fixed) { + const QString actualConstraintValue = XsdTypeChecker::normalizedValue(declaration->valueConstraint()->value(), facets); + if (!checker.valuesAreEqual(actualValue, actualConstraintValue, attributeType)) { + error(QtXmlPatterns::tr("content of attribute %1 does not match defined value constraint").arg(formatKeyword(declaration->attribute()->displayName(m_namePool)))); + return false; + } + } + + if (BuiltinTypes::xsID->wxsTypeMatches(declaration->attribute()->type())) { + addIdIdRefBinding(actualValue, declaration->attribute()); + } + + if (m_idRefsType->wxsTypeMatches(declaration->attribute()->type())) { + const QStringList idRefs = actualValue.split(QLatin1Char(' '), QString::SkipEmptyParts); + for (int i = 0; i < idRefs.count(); ++i) + m_idRefs.insert(idRefs.at(i)); + } else if (BuiltinTypes::xsIDREF->wxsTypeMatches(declaration->attribute()->type())) { + m_idRefs.insert(actualValue); + } + + m_model->setAssignedType(index, declaration->attribute()->type()); + m_model->setAssignedAttribute(index, declaration->attribute()); + + return true; +} + +//TODO: merge that with the method above +bool XsdValidatingInstanceReader::validateAttribute(const XsdAttribute::Ptr &declaration, const QString &value) +{ + const AnySimpleType::Ptr attributeType = declaration->type(); + const XsdFacet::Hash facets = XsdTypeChecker::mergedFacetsForType(attributeType, m_context); + + const QString actualValue = XsdTypeChecker::normalizedValue(value, facets); + + QString errorMsg; + AnySimpleType::Ptr boundType; + + const QXmlNodeModelIndex index = attributeItem(declaration->name(m_namePool)).toNodeModelIndex(); + + const XsdTypeChecker checker(m_context, namespaceBindings(index), sourceLocation()); + if (!checker.isValidString(actualValue, attributeType, errorMsg, &boundType)) { + error(QtXmlPatterns::tr("content of attribute %1 does not match its type definition: %2").arg(formatKeyword(declaration->displayName(m_namePool))).arg(errorMsg)); + return false; + } + + // @see http://www.w3.org/TR/xmlschema11-1/#cvc-au + if (declaration->valueConstraint() && declaration->valueConstraint()->variety() == XsdAttribute::ValueConstraint::Fixed) { + const QString actualConstraintValue = XsdTypeChecker::normalizedValue(declaration->valueConstraint()->value(), facets); + if (!checker.valuesAreEqual(actualValue, actualConstraintValue, attributeType)) { + error(QtXmlPatterns::tr("content of attribute %1 does not match defined value constraint").arg(formatKeyword(declaration->displayName(m_namePool)))); + return false; + } + } + + if (BuiltinTypes::xsID->wxsTypeMatches(declaration->type())) { + addIdIdRefBinding(actualValue, declaration); + } + + if (m_idRefsType->wxsTypeMatches(declaration->type())) { + const QStringList idRefs = actualValue.split(QLatin1Char(' '), QString::SkipEmptyParts); + for (int i = 0; i < idRefs.count(); ++i) + m_idRefs.insert(idRefs.at(i)); + } else if (BuiltinTypes::xsIDREF->wxsTypeMatches(declaration->type())) { + m_idRefs.insert(actualValue); + } + + m_model->setAssignedType(index, declaration->type()); + m_model->setAssignedAttribute(index, declaration); + + return true; +} + +bool XsdValidatingInstanceReader::validateAttributeWildcard(const QXmlName &attributeName, const XsdWildcard::Ptr &wildcard) +{ + // @see http://www.w3.org/TR/xmlschema11-1/#cvc-wildcard + + // wildcards using XsdWildcard::absentNamespace, so we have to fix that here + QXmlName name(attributeName); + if (name.namespaceURI() == StandardNamespaces::empty) { + name.setNamespaceURI(m_namePool->allocateNamespace(XsdWildcard::absentNamespace())); + } + + return XsdSchemaHelper::wildcardAllowsExpandedName(name, wildcard, m_namePool); +} + +bool XsdValidatingInstanceReader::validateIdentityConstraint(const XsdElement::Ptr &element, const QXmlItem ¤tItem) +{ + const XsdIdentityConstraint::List constraints = element->identityConstraints(); + + for (int i = 0; i < constraints.count(); ++i) { + const XsdIdentityConstraint::Ptr constraint = constraints.at(i); + + TargetNode::Set targetNodeSet, qualifiedNodeSet; + selectNodeSets(element, currentItem, constraint, targetNodeSet, qualifiedNodeSet); + + if (constraint->category() == XsdIdentityConstraint::Unique) { + if (!validateUniqueIdentityConstraint(element, constraint, qualifiedNodeSet)) + return false; + } else if (constraint->category() == XsdIdentityConstraint::Key) { + if (!validateKeyIdentityConstraint(element, constraint, targetNodeSet, qualifiedNodeSet)) + return false; + } + } + + // we do the keyref check in a separated run to make sure that all keys are available + for (int i = 0; i < constraints.count(); ++i) { + const XsdIdentityConstraint::Ptr constraint = constraints.at(i); + if (constraint->category() == XsdIdentityConstraint::KeyReference) { + TargetNode::Set targetNodeSet, qualifiedNodeSet; + selectNodeSets(element, currentItem, constraint, targetNodeSet, qualifiedNodeSet); + + if (!validateKeyRefIdentityConstraint(element, constraint, qualifiedNodeSet)) + return false; + } + } + + return true; +} + +bool XsdValidatingInstanceReader::validateUniqueIdentityConstraint(const XsdElement::Ptr&, const XsdIdentityConstraint::Ptr &constraint, const TargetNode::Set &qualifiedNodeSet) +{ + // @see http://www.w3.org/TR/xmlschema11-1/#d0e32243 + + // 4.1 + const XsdSchemaSourceLocationReflection reflection(sourceLocation()); + + QSetIterator<TargetNode> it(qualifiedNodeSet); + while (it.hasNext()) { + const TargetNode node = it.next(); + QSetIterator<TargetNode> innerIt(qualifiedNodeSet); + while (innerIt.hasNext()) { + const TargetNode innerNode = innerIt.next(); + + if (node == innerNode) // do not compare with ourself + continue; + + if (node.fieldsAreEqual(innerNode, m_namePool, m_context, &reflection)) { + error(QtXmlPatterns::tr("non-unique value found for constraint %1").arg(formatKeyword(constraint->displayName(m_namePool)))); + return false; + } + } + } + + m_idcKeys.insert(constraint->name(m_namePool), qualifiedNodeSet); + + return true; +} + +bool XsdValidatingInstanceReader::validateKeyIdentityConstraint(const XsdElement::Ptr &element, const XsdIdentityConstraint::Ptr &constraint, const TargetNode::Set &targetNodeSet, const TargetNode::Set &qualifiedNodeSet) +{ + // @see http://www.w3.org/TR/xmlschema11-1/#d0e32243 + + // 4.2 + const XsdSchemaSourceLocationReflection reflection(sourceLocation()); + + // 4.2.1 + if (targetNodeSet.count() != qualifiedNodeSet.count()) { + error(QtXmlPatterns::tr("key constraint %1 contains absent fields").arg(formatKeyword(constraint->displayName(m_namePool)))); + return false; + } + + // 4.2.2 + if (!validateUniqueIdentityConstraint(element, constraint, qualifiedNodeSet)) + return false; + + // 4.2.3 + QSetIterator<TargetNode> it(qualifiedNodeSet); + while (it.hasNext()) { + const TargetNode node = it.next(); + const QVector<QXmlItem> fieldItems = node.fieldItems(); + for (int i = 0; i < fieldItems.count(); ++i) { + const QXmlNodeModelIndex index = fieldItems.at(i).toNodeModelIndex(); + if (m_model->kind(index) == QXmlNodeModelIndex::Element) { + const XsdElement::Ptr declaration = m_model->assignedElement(index); + if (declaration && declaration->isNillable()) { + error(QtXmlPatterns::tr("key constraint %1 contains references nillable element %2") + .arg(formatKeyword(constraint->displayName(m_namePool))) + .arg(formatKeyword(declaration->displayName(m_namePool)))); + return false; + } + } + } + } + + m_idcKeys.insert(constraint->name(m_namePool), qualifiedNodeSet); + + return true; +} + +bool XsdValidatingInstanceReader::validateKeyRefIdentityConstraint(const XsdElement::Ptr&, const XsdIdentityConstraint::Ptr &constraint, const TargetNode::Set &qualifiedNodeSet) +{ + // @see http://www.w3.org/TR/xmlschema11-1/#d0e32243 + + // 4.3 + const XsdSchemaSourceLocationReflection reflection(sourceLocation()); + + const TargetNode::Set keySet = m_idcKeys.value(constraint->referencedKey()->name(m_namePool)); + + QSetIterator<TargetNode> it(qualifiedNodeSet); + while (it.hasNext()) { + const TargetNode node = it.next(); + + bool foundMatching = false; + + QSetIterator<TargetNode> keyIt(keySet); + while (keyIt.hasNext()) { + const TargetNode keyNode = keyIt.next(); + + if (node.fieldsAreEqual(keyNode, m_namePool, m_context, &reflection)) { + foundMatching = true; + break; + } + } + + if (!foundMatching) { + error(QtXmlPatterns::tr("no referenced value found for key reference %1").arg(formatKeyword(constraint->displayName(m_namePool)))); + return false; + } + } + + return true; +} + +QXmlQuery XsdValidatingInstanceReader::createXQuery(const QList<QXmlName> &namespaceBindings, const QXmlItem &contextNode, const QString &queryString) const +{ + // create a public name pool from our name pool + QXmlNamePool namePool(m_namePool.data()); + + // the QXmlQuery shall work with the same name pool as we do + QXmlQuery query(namePool); + + // add additional namespace bindings + QXmlQueryPrivate *queryPrivate = query.d; + + for (int i = 0; i < namespaceBindings.count(); ++i) { + if (!namespaceBindings.at(i).prefix() == StandardPrefixes::empty) + queryPrivate->addAdditionalNamespaceBinding(namespaceBindings.at(i)); + } + + // set the context node for that query and the query string + query.setFocus(contextNode); + query.setQuery(queryString, m_documentUri); + + return query; +} + +bool XsdValidatingInstanceReader::selectNodeSets(const XsdElement::Ptr&, const QXmlItem ¤tItem, const XsdIdentityConstraint::Ptr &constraint, TargetNode::Set &targetNodeSet, TargetNode::Set &qualifiedNodeSet) +{ + // at first select all target nodes + const XsdXPathExpression::Ptr selector = constraint->selector(); + const XsdXPathExpression::List fields = constraint->fields(); + + QXmlQuery query = createXQuery(selector->namespaceBindings(), currentItem, selector->expression()); + + QXmlResultItems resultItems; + query.evaluateTo(&resultItems); + + // now we iterate over all target nodes and select the fields for each node + QXmlItem item(resultItems.next()); + while (!item.isNull()) { + + TargetNode targetNode(item); + + for (int i = 0; i < fields.count(); ++i) { + const XsdXPathExpression::Ptr field = fields.at(i); + QXmlQuery fieldQuery = createXQuery(field->namespaceBindings(), item, field->expression()); + + QXmlResultItems fieldResultItems; + fieldQuery.evaluateTo(&fieldResultItems); + + // copy result into vetor for better testing... + QVector<QXmlItem> fieldVector; + QXmlItem fieldItem(fieldResultItems.next()); + while (!fieldItem.isNull()) { + fieldVector.append(fieldItem); + fieldItem = fieldResultItems.next(); + } + + if (fieldVector.count() > 1) { + error(QtXmlPatterns::tr("more than one value found for field %1").arg(formatData(field->expression()))); + return false; + } + + if (fieldVector.count() == 1) { + fieldItem = fieldVector.first(); + + const QXmlNodeModelIndex index = fieldItem.toNodeModelIndex(); + const SchemaType::Ptr type = m_model->assignedType(index); + + bool typeOk = true; + if (type->isComplexType()) { + if (type->isDefinedBySchema()) { + if (XsdComplexType::Ptr(type)->contentType()->variety() != XsdComplexType::ContentType::Simple) + typeOk = false; + } else { + typeOk = false; + } + } + if (!typeOk) { + error(QtXmlPatterns::tr("field %1 has no simple type").arg(formatData(field->expression()))); + return false; + } + + SchemaType::Ptr targetType = type; + QString value = m_model->stringValue(fieldItem.toNodeModelIndex()); + + if (type->isDefinedBySchema()) { + if (type->isSimpleType()) + targetType = XsdSimpleType::Ptr(type)->primitiveType(); + else + targetType = XsdComplexType::Ptr(type)->contentType()->simpleType(); + } else { + if (BuiltinTypes::xsAnySimpleType->name(m_namePool) == type->name(m_namePool)) { + targetType = BuiltinTypes::xsString; + value = QLatin1String("___anySimpleType_value"); + } + } + + // if it is xs:QName derived type, we normalize the name content + // and do a string comparison + if (BuiltinTypes::xsQName->wxsTypeMatches(type)) { + targetType = BuiltinTypes::xsString; + + const QXmlName qName = convertToQName(value.trimmed()); + value = QString::fromLatin1("%1:%2").arg(m_namePool->stringForNamespace(qName.namespaceURI())).arg(m_namePool->stringForLocalName(qName.localName())); + } + + targetNode.addField(fieldItem, value, targetType); + } else { + // we add an empty entry here, that makes comparison easier later on + targetNode.addField(QXmlItem(), QString(), SchemaType::Ptr()); + } + } + + targetNodeSet.insert(targetNode); + + item = resultItems.next(); + } + + // copy all items from target node set to qualified node set, that have no empty fields + QSetIterator<TargetNode> it(targetNodeSet); + while (it.hasNext()) { + const TargetNode node = it.next(); + if (node.emptyFieldsCount() == 0) + qualifiedNodeSet.insert(node); + } + + return true; +} + +XsdElement::Ptr XsdValidatingInstanceReader::elementByName(const QXmlName &name) const +{ + return m_schema->element(name); +} + +XsdAttribute::Ptr XsdValidatingInstanceReader::attributeByName(const QXmlName &name) const +{ + return m_schema->attribute(name); +} + +SchemaType::Ptr XsdValidatingInstanceReader::typeByName(const QXmlName &name) const +{ + const SchemaType::Ptr type = m_schema->type(name); + if (type) + return type; + + return m_context->schemaTypeFactory()->createSchemaType(name); +} + +void XsdValidatingInstanceReader::addIdIdRefBinding(const QString &id, const NamedSchemaComponent::Ptr &binding) +{ + if (!m_model->idIdRefBindings(id).isEmpty()) { + error(QtXmlPatterns::tr("ID value '%1' is not unique").arg(formatKeyword(id))); + return; + } + + m_model->addIdIdRefBinding(id, binding); +} + +QString XsdValidatingInstanceReader::qNameAttribute(const QXmlName &attributeName) +{ + const QString value = attribute(attributeName).simplified(); + if (!XPathHelper::isQName(value)) { + error(QtXmlPatterns::tr("'%1' attribute contains invalid QName content: %2").arg(m_namePool->displayName(attributeName)).arg(formatData(value))); + return QString(); + } else { + return value; + } +} + +XsdComplexType::Ptr XsdValidatingInstanceReader::anyType() +{ + if (m_anyType) + return m_anyType; + + const XsdWildcard::Ptr wildcard(new XsdWildcard()); + wildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Any); + wildcard->setProcessContents(XsdWildcard::Lax); + + const XsdParticle::Ptr outerParticle(new XsdParticle()); + outerParticle->setMinimumOccurs(1); + outerParticle->setMaximumOccurs(1); + + const XsdParticle::Ptr innerParticle(new XsdParticle()); + innerParticle->setMinimumOccurs(0); + innerParticle->setMaximumOccursUnbounded(true); + innerParticle->setTerm(wildcard); + + const XsdModelGroup::Ptr outerModelGroup(new XsdModelGroup()); + outerModelGroup->setCompositor(XsdModelGroup::SequenceCompositor); + outerModelGroup->setParticles(XsdParticle::List() << innerParticle); + outerParticle->setTerm(outerModelGroup); + + m_anyType = XsdComplexType::Ptr(new XsdComplexType()); + m_anyType->setName(BuiltinTypes::xsAnyType->name(m_namePool)); + m_anyType->setDerivationMethod(XsdComplexType::DerivationRestriction); + m_anyType->contentType()->setVariety(XsdComplexType::ContentType::Mixed); + m_anyType->contentType()->setParticle(outerParticle); + m_anyType->setAttributeWildcard(wildcard); + m_anyType->setIsAbstract(false); + + return m_anyType; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdvalidatinginstancereader_p.h b/src/xmlpatterns/schema/qxsdvalidatinginstancereader_p.h new file mode 100644 index 0000000..8ea4d28 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdvalidatinginstancereader_p.h @@ -0,0 +1,296 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdValidatingInstanceReader_H +#define Patternist_XsdValidatingInstanceReader_H + +#include "qxsdidchelper_p.h" +#include "qxsdinstancereader_p.h" +#include "qxsdstatemachine_p.h" +#include "qxsdvalidatedxmlnodemodel_p.h" + +#include <QtCore/QStack> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QXmlQuery; + +namespace QPatternist +{ + /** + * @short The validating schema instance reader. + * + * This class reads in a xml instance document from a QAbstractXmlNodeModel and + * validates it against a given xml schema. + * + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdValidatingInstanceReader : public XsdInstanceReader + { + public: + typedef QExplicitlySharedDataPointer<XsdValidatingInstanceReader> Ptr; + + /** + * Creates a new validating instance reader that reads the data from + * the given @p model. + * + * @param model The model the data shall be read from. + * @param documentUri The uri of the document the model is from. + * @param context The context that is used to report errors etc. + */ + XsdValidatingInstanceReader(XsdValidatedXmlNodeModel *model, const QUrl &documentUri, const XsdSchemaContext::Ptr &context); + + /** + * Adds a new @p schema to the pool of schemas that shall be used + * for validation. + * The schema is located at the given @p url. + */ + void addSchema(const XsdSchema::Ptr &schema, const QUrl &url); + + /** + * Reads and validates the instance document. + */ + bool read(); + + private: + /** + * Loads a schema with the given @p targetNamespace from the given @p location + * and adds it to the pool of schemas that are used for validation. + * + * This method is used to load schemas defined in the xsi:schemaLocation or + * xsi:noNamespaceSchemaLocation attributes in the instance document. + */ + bool loadSchema(const QString &targetNamespace, const QUrl &location); + + /** + * Reports an error via the report context. + */ + void error(const QString &msg) const; + + /** + * Validates the current element tag of the instance document. + * + * @param hasStateMachine Used to remember whether this element represents the start tag + * of a complex type and therefor pushes a new state machine on the stack. + * @param element Used to remember which element has been validated in this step. + */ + bool validate(bool &hasStateMachine, XsdElement::Ptr &element); + + /** + * Validates the current tag of the instance document against the given element @p declaration. + * + * @param declaration The element declaration to validate against. + * @param hasStateMachine Used to remember whether this element represents the start tag + * of a complex type and therefor pushes a new state machine on the stack. + */ + bool validateElement(const XsdElement::Ptr &declaration, bool &hasStateMachine); + + /** + * Validates the current tag of the instance document against the given @p type of the element @p declaration. + * + * @param declaration The element declaration to validate against. + * @param type The type to validate against. + * @param isNilled Defines whether the element is nilled by the instance document. + * @param hasStateMachine Used to remember whether this element represents the start tag + * of a complex type and therefor pushes a new state machine on the stack. + * + * @note The @p type can differ from the element @p declaration type if the instance document has defined + * it via xsi:type attribute. + */ + bool validateElementType(const XsdElement::Ptr &declaration, const SchemaType::Ptr &type, bool isNilled, bool &hasStateMachine); + + /** + * Validates the current tag of the instance document against the given simple @p type of the element @p declaration. + * + * @param declaration The element declaration to validate against. + * @param type The type to validate against. + * @param isNilled Defines whether the element is nilled by the instance document. + * + * @note The @p type can differ from the element @p declaration type if the instance document has defined + * it via xsi:type attribute. + */ + bool validateElementSimpleType(const XsdElement::Ptr &declaration, const SchemaType::Ptr &type, bool isNilled); + + /** + * Validates the current tag of the instance document against the given complex @p type of the element @p declaration. + * + * @param declaration The element declaration to validate against. + * @param type The type to validate against. + * @param isNilled Defines whether the element is nilled by the instance document. + * @param hasStateMachine Used to remember whether this element represents the start tag + * of a complex type and therefor pushes a new state machine on the stack. + * + * @note The @p type can differ from the element @p declaration type if the instance document has defined + * it via xsi:type attribute. + */ + bool validateElementComplexType(const XsdElement::Ptr &declaration, const SchemaType::Ptr &type, bool isNilled, bool &hasStateMachine); + + /** + * Validates the given @p value against the attribute use @p declaration. + */ + bool validateAttribute(const XsdAttributeUse::Ptr &declaration, const QString &value); + + /** + * Validates the given @p value against the attribute @p declaration. + */ + bool validateAttribute(const XsdAttribute::Ptr &declaration, const QString &value); + + /** + * Validates the given @p attributeName against the @p wildcard. + */ + bool validateAttributeWildcard(const QXmlName &attributeName, const XsdWildcard::Ptr &wildcard); + + /** + * Validates the identity constraints of an @p element. + */ + bool validateIdentityConstraint(const XsdElement::Ptr &element, const QXmlItem ¤tItem); + + /** + * Validates the <em>unique</em> identity @p constraint of the @p element. + */ + bool validateUniqueIdentityConstraint(const XsdElement::Ptr &element, const XsdIdentityConstraint::Ptr &constraint, const TargetNode::Set &qualifiedNodeSet); + + /** + * Validates the <em>key</em> identity @p constraint of the @p element. + */ + bool validateKeyIdentityConstraint(const XsdElement::Ptr &element, const XsdIdentityConstraint::Ptr &constraint, const TargetNode::Set &targetNodeSet, const TargetNode::Set &qualifiedNodeSet); + + /** + * Validates the <em>keyref</em> identity @p constraint of the @p element. + */ + bool validateKeyRefIdentityConstraint(const XsdElement::Ptr &element, const XsdIdentityConstraint::Ptr &constraint, const TargetNode::Set &qualifiedNodeSet); + + /** + * Selects two sets of nodes that match the given identity @p constraint. + * + * @param element The element the identity constraint belongs to. + * @param currentItem The current element that will be used as focus for the XQuery. + * @param constraint The constraint (selector and fields) that describe the two sets. + * @param targetNodeSet The target node set as defined by the schema specification. + * @param qualifiedNodeSet The qualified node set as defined by the schema specification. + */ + bool selectNodeSets(const XsdElement::Ptr &element, const QXmlItem ¤tItem, const XsdIdentityConstraint::Ptr &constraint, TargetNode::Set &targetNodeSet, TargetNode::Set &qualifiedNodeSet); + + /** + * Creates an QXmlQuery object with the defined @p namespaceBindings that has the @p contextNode as focus + * and will execute @p query. + */ + QXmlQuery createXQuery(const QList<QXmlName> &namespaceBindings, const QXmlItem &contextNode, const QString &query) const; + + /** + * Returns the element declaration with the given @p name from the pool of all schemas. + */ + XsdElement::Ptr elementByName(const QXmlName &name) const; + + /** + * Returns the attribute declaration with the given @p name from the pool of all schemas. + */ + XsdAttribute::Ptr attributeByName(const QXmlName &name) const; + + /** + * Returns the type declaration with the given @p name from the pool of all schemas. + */ + SchemaType::Ptr typeByName(const QXmlName &name) const; + + /** + * Adds the ID/IDREF binding to the validated model and checks for duplicates. + */ + void addIdIdRefBinding(const QString &id, const NamedSchemaComponent::Ptr &binding); + + /** + * Helper method that reads an attribute of type xs:QName and does + * syntax checking. + */ + QString qNameAttribute(const QXmlName &attributeName); + + /** + * Returns the xs:anyType that is used to build up the state machine. + * We need that as the BuiltinTypes::xsAnyType is not a XsdComplexType. + */ + XsdComplexType::Ptr anyType(); + + /** + * Helper method that creates a state machine for the given @p particle + * and pushes it on the state machine stack. + */ + void createAndPushStateMachine(const XsdParticle::Ptr &particle); + + typedef QHash<QUrl, QStringList> MergedSchemas; + typedef QHashIterator<QUrl, QStringList> MergedSchemasIterator; + + XsdValidatedXmlNodeModel::Ptr m_model; + MergedSchemas m_mergedSchemas; + XsdSchema::Ptr m_schema; + const NamePool::Ptr m_namePool; + const QXmlName m_xsiNilName; + const QXmlName m_xsiTypeName; + const QXmlName m_xsiSchemaLocationName; + const QXmlName m_xsiNoNamespaceSchemaLocationName; + + QStack<XsdStateMachine<XsdTerm::Ptr> > m_stateMachines; + QUrl m_documentUri; + XsdComplexType::Ptr m_anyType; + QSet<QString> m_processedNamespaces; + QSet<QString> m_processedSchemaLocations; + QSet<QString> m_idRefs; + QHash<QXmlName, TargetNode::Set> m_idcKeys; + SchemaType::Ptr m_idRefsType; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdwildcard.cpp b/src/xmlpatterns/schema/qxsdwildcard.cpp new file mode 100644 index 0000000..561a169 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdwildcard.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdwildcard_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +QString XsdWildcard::absentNamespace() +{ + return QLatin1String("__ns_absent"); +} + +void XsdWildcard::NamespaceConstraint::setVariety(Variety variety) +{ + m_variety = variety; +} + +XsdWildcard::NamespaceConstraint::Variety XsdWildcard::NamespaceConstraint::variety() const +{ + return m_variety; +} + +void XsdWildcard::NamespaceConstraint::setNamespaces(const QSet<QString> &namespaces) +{ + m_namespaces = namespaces; +} + +QSet<QString> XsdWildcard::NamespaceConstraint::namespaces() const +{ + return m_namespaces; +} + +void XsdWildcard::NamespaceConstraint::setDisallowedNames(const QSet<QString> &names) +{ + m_disallowedNames = names; +} + +QSet<QString> XsdWildcard::NamespaceConstraint::disallowedNames() const +{ + return m_disallowedNames; +} + +XsdWildcard::XsdWildcard() + : m_namespaceConstraint(new NamespaceConstraint()) + , m_processContents(Strict) +{ + m_namespaceConstraint->setVariety(NamespaceConstraint::Any); +} + +bool XsdWildcard::isWildcard() const +{ + return true; +} + +void XsdWildcard::setNamespaceConstraint(const NamespaceConstraint::Ptr &namespaceConstraint) +{ + m_namespaceConstraint = namespaceConstraint; +} + +XsdWildcard::NamespaceConstraint::Ptr XsdWildcard::namespaceConstraint() const +{ + return m_namespaceConstraint; +} + +void XsdWildcard::setProcessContents(ProcessContents contents) +{ + m_processContents = contents; +} + +XsdWildcard::ProcessContents XsdWildcard::processContents() const +{ + return m_processContents; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdwildcard_p.h b/src/xmlpatterns/schema/qxsdwildcard_p.h new file mode 100644 index 0000000..a925ab4 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdwildcard_p.h @@ -0,0 +1,199 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdWildcard_H +#define Patternist_XsdWildcard_H + +#include "qxsdterm_p.h" + +#include <QtCore/QSet> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short Represents a XSD wildcard object. + * + * This class represents the <em>wildcard</em> object of a XML schema as described + * <a href="http://www.w3.org/TR/xmlschema11-1/#Wildcards">here</a>. + * + * It contains information from either an <em>any</em> object or an <em>anyAttribute</em> object. + * + * @see <a href="http://www.w3.org/Submission/2004/SUBM-xmlschema-api-20040309/xml-schema-api.html#Interface-XSWildcard">XML Schema API reference</a> + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class XsdWildcard : public XsdTerm + { + public: + typedef QExplicitlySharedDataPointer<XsdWildcard> Ptr; + + /** + * Defines the absent namespace that is used in wildcards. + */ + static QString absentNamespace(); + + /** + * Describes the <a href="http://www.w3.org/TR/xmlschema11-1/#w-namespace_constraint">namespace constraint</a> of the wildcard. + */ + class NamespaceConstraint : public QSharedData + { + public: + typedef QExplicitlySharedDataPointer<NamespaceConstraint> Ptr; + + /** + * Describes the variety of the namespace constraint. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#nc-variety">Variety Definition</a> + */ + enum Variety + { + Any, ///< Any namespace is allowed. + Enumeration, ///< Namespaces in the namespaces set are allowed. + Not ///< Namespaces in the namespaces set are not allowed. + }; + + /** + * Sets the @p variety of the namespace constraint. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#nc-variety">Variety Definition</a> + */ + void setVariety(Variety variety); + + /** + * Returns the variety of the namespace constraint. + */ + Variety variety() const; + + /** + * Sets the set of @p namespaces of the namespace constraint. + */ + void setNamespaces(const QSet<QString> &namespaces); + + /** + * Returns the set of namespaces of the namespace constraint. + */ + QSet<QString> namespaces() const; + + /** + * Sets the set of disallowed @p names of the namespace constraint. + */ + void setDisallowedNames(const QSet<QString> &names); + + /** + * Returns the set of disallowed names of the namespace constraint. + */ + QSet<QString> disallowedNames() const; + + private: + Variety m_variety; + QSet<QString> m_namespaces; + QSet<QString> m_disallowedNames; + }; + + /** + * Describes the <a href="http://www.w3.org/TR/xmlschema11-1/#w-process_contents">type of content processing</a> of the wildcard. + */ + enum ProcessContents + { + Strict, ///< There must be a top-level declaration for the item available, or the item must have an xsi:type, and the item must be valid as appropriate. + Lax, ///< If the item has a uniquely determined declaration available, it must be valid with respect to that definition. + Skip ///< No constraints at all: the item must simply be well-formed XML. + }; + + /** + * Creates a new wildcard object. + */ + XsdWildcard(); + + /** + * Returns always @c true, used to avoid dynamic casts. + */ + virtual bool isWildcard() const; + + /** + * Sets the namespace @p constraint of the wildcard. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#w-namespace_constraint">Namespace Constraint Definition</a> + */ + void setNamespaceConstraint(const NamespaceConstraint::Ptr &constraint); + + /** + * Returns the namespace constraint of the wildcard. + */ + NamespaceConstraint::Ptr namespaceConstraint() const; + + /** + * Sets the process @p contents of the wildcard. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#w-process_contents">Process Contents Definition</a> + */ + void setProcessContents(ProcessContents contents); + + /** + * Returns the process contents of the wildcard. + */ + ProcessContents processContents() const; + + private: + NamespaceConstraint::Ptr m_namespaceConstraint; + ProcessContents m_processContents; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/qxsdxpathexpression.cpp b/src/xmlpatterns/schema/qxsdxpathexpression.cpp new file mode 100644 index 0000000..aa08cbc --- /dev/null +++ b/src/xmlpatterns/schema/qxsdxpathexpression.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxsdxpathexpression_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +void XsdXPathExpression::setNamespaceBindings(const QList<QXmlName> &set) +{ + m_namespaceBindings = set; +} + +QList<QXmlName> XsdXPathExpression::namespaceBindings() const +{ + return m_namespaceBindings; +} + +void XsdXPathExpression::setDefaultNamespace(const AnyURI::Ptr &defaultNs) +{ + m_defaultNamespace = defaultNs; +} + +AnyURI::Ptr XsdXPathExpression::defaultNamespace() const +{ + return m_defaultNamespace; +} + +void XsdXPathExpression::setBaseURI(const AnyURI::Ptr &uri) +{ + m_baseURI = uri; +} + +AnyURI::Ptr XsdXPathExpression::baseURI() const +{ + return m_baseURI; +} + +void XsdXPathExpression::setExpression(const QString &expression) +{ + m_expression = expression; +} + +QString XsdXPathExpression::expression() const +{ + return m_expression; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/schema/qxsdxpathexpression_p.h b/src/xmlpatterns/schema/qxsdxpathexpression_p.h new file mode 100644 index 0000000..6f149d7 --- /dev/null +++ b/src/xmlpatterns/schema/qxsdxpathexpression_p.h @@ -0,0 +1,143 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_XsdXPathExpression_H +#define Patternist_XsdXPathExpression_H + +#include "qanyuri_p.h" +#include "qnamedschemacomponent_p.h" +#include "qxsdannotated_p.h" + +#include <QtCore/QList> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short Represents a XSD assertion object. + * + * @ingroup Patternist_schema + * @author Tobias Koenig <tobias.koenig@trolltech.com> + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#x">XPathExpression Definition</a> + */ + class XsdXPathExpression : public NamedSchemaComponent, public XsdAnnotated + { + public: + typedef QExplicitlySharedDataPointer<XsdXPathExpression> Ptr; + typedef QList<XsdXPathExpression::Ptr> List; + + /** + * Sets the list of namespace @p bindings of the XPath expression. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#x-namespace_bindings">Namespace Bindings Definition</a> + * + * @note We can't use a QSet<QXmlName> here, as the hash method does not take the prefix + * in account, so we loose entries. + */ + void setNamespaceBindings(const QList<QXmlName> &bindings); + + /** + * Returns the list of namespace bindings of the XPath expression. + */ + QList<QXmlName> namespaceBindings() const; + + /** + * Sets the default namespace of the XPath expression. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#x-default_namespace">Default Namespace Definition</a> + */ + void setDefaultNamespace(const AnyURI::Ptr &defaultNamespace); + + /** + * Returns the default namespace of the XPath expression. + */ + AnyURI::Ptr defaultNamespace() const; + + /** + * Sets the base @p uri of the XPath expression. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#x-base_URI">Base URI Definition</a> + */ + void setBaseURI(const AnyURI::Ptr &uri); + + /** + * Returns the base uri of the XPath expression. + */ + AnyURI::Ptr baseURI() const; + + /** + * Sets the @p expression string of the XPath expression. + * + * @see <a href="http://www.w3.org/TR/xmlschema11-1/#x-expression">Expression Definition</a> + */ + void setExpression(const QString &expression); + + /** + * Returns the expression string of the XPath expression. + */ + QString expression() const; + + private: + QList<QXmlName> m_namespaceBindings; + AnyURI::Ptr m_defaultNamespace; + AnyURI::Ptr m_baseURI; + QString m_expression; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/schema/schema.pri b/src/xmlpatterns/schema/schema.pri new file mode 100644 index 0000000..b00d64b --- /dev/null +++ b/src/xmlpatterns/schema/schema.pri @@ -0,0 +1,93 @@ +HEADERS += $$PWD/qnamespacesupport_p.h \ + $$PWD/qxsdalternative_p.h \ + $$PWD/qxsdannotated_p.h \ + $$PWD/qxsdannotation_p.h \ + $$PWD/qxsdapplicationinformation_p.h \ + $$PWD/qxsdassertion_p.h \ + $$PWD/qxsdattribute_p.h \ + $$PWD/qxsdattributereference_p.h \ + $$PWD/qxsdattributeterm_p.h \ + $$PWD/qxsdattributeuse_p.h \ + $$PWD/qxsdattributegroup_p.h \ + $$PWD/qxsdcomplextype_p.h \ + $$PWD/qxsddocumentation_p.h \ + $$PWD/qxsdelement_p.h \ + $$PWD/qxsdfacet_p.h \ + $$PWD/qxsdidcache_p.h \ + $$PWD/qxsdidchelper_p.h \ + $$PWD/qxsdidentityconstraint_p.h \ + $$PWD/qxsdinstancereader_p.h \ + $$PWD/qxsdmodelgroup_p.h \ + $$PWD/qxsdnotation_p.h \ + $$PWD/qxsdparticle_p.h \ + $$PWD/qxsdparticlechecker_p.h \ + $$PWD/qxsdreference_p.h \ + $$PWD/qxsdsimpletype_p.h \ + $$PWD/qxsdschema_p.h \ + $$PWD/qxsdschemachecker_p.h \ + $$PWD/qxsdschemacontext_p.h \ + $$PWD/qxsdschemadebugger_p.h \ + $$PWD/qxsdschemahelper_p.h \ + $$PWD/qxsdschemamerger_p.h \ + $$PWD/qxsdschemaparser_p.h \ + $$PWD/qxsdschemaparsercontext_p.h \ + $$PWD/qxsdschemaresolver_p.h \ + $$PWD/qxsdschematoken_p.h \ + $$PWD/qxsdschematypesfactory_p.h \ + $$PWD/qxsdstatemachine_p.h \ + $$PWD/qxsdstatemachinebuilder_p.h \ + $$PWD/qxsdterm_p.h \ + $$PWD/qxsdtypechecker_p.h \ + $$PWD/qxsduserschematype_p.h \ + $$PWD/qxsdvalidatedxmlnodemodel_p.h \ + $$PWD/qxsdvalidatinginstancereader_p.h \ + $$PWD/qxsdwildcard_p.h \ + $$PWD/qxsdxpathexpression_p.h + +SOURCES += $$PWD/qnamespacesupport.cpp \ + $$PWD/qxsdalternative.cpp \ + $$PWD/qxsdannotated.cpp \ + $$PWD/qxsdannotation.cpp \ + $$PWD/qxsdapplicationinformation.cpp \ + $$PWD/qxsdassertion.cpp \ + $$PWD/qxsdattribute.cpp \ + $$PWD/qxsdattributereference.cpp \ + $$PWD/qxsdattributeterm.cpp \ + $$PWD/qxsdattributeuse.cpp \ + $$PWD/qxsdattributegroup.cpp \ + $$PWD/qxsdcomplextype.cpp \ + $$PWD/qxsddocumentation.cpp \ + $$PWD/qxsdelement.cpp \ + $$PWD/qxsdfacet.cpp \ + $$PWD/qxsdidcache.cpp \ + $$PWD/qxsdidchelper.cpp \ + $$PWD/qxsdidentityconstraint.cpp \ + $$PWD/qxsdinstancereader.cpp \ + $$PWD/qxsdmodelgroup.cpp \ + $$PWD/qxsdnotation.cpp \ + $$PWD/qxsdparticle.cpp \ + $$PWD/qxsdparticlechecker.cpp \ + $$PWD/qxsdreference.cpp \ + $$PWD/qxsdsimpletype.cpp \ + $$PWD/qxsdschema.cpp \ + $$PWD/qxsdschemachecker.cpp \ + $$PWD/qxsdschemachecker_setup.cpp \ + $$PWD/qxsdschemacontext.cpp \ + $$PWD/qxsdschemadebugger.cpp \ + $$PWD/qxsdschemahelper.cpp \ + $$PWD/qxsdschemamerger.cpp \ + $$PWD/qxsdschemaparser.cpp \ + $$PWD/qxsdschemaparser_setup.cpp \ + $$PWD/qxsdschemaparsercontext.cpp \ + $$PWD/qxsdschemaresolver.cpp \ + $$PWD/qxsdschematoken.cpp \ + $$PWD/qxsdschematypesfactory.cpp \ + $$PWD/qxsdstatemachinebuilder.cpp \ + $$PWD/qxsdterm.cpp \ + $$PWD/qxsdtypechecker.cpp \ + $$PWD/qxsdwildcard.cpp \ + $$PWD/qxsdvalidatedxmlnodemodel.cpp \ + $$PWD/qxsdvalidatinginstancereader.cpp \ + $$PWD/qxsdxpathexpression.cpp + +RESOURCES += $$PWD/builtinschemas.qrc diff --git a/src/xmlpatterns/schema/schemas/xml.xsd b/src/xmlpatterns/schema/schemas/xml.xsd new file mode 100644 index 0000000..eeb9db5 --- /dev/null +++ b/src/xmlpatterns/schema/schemas/xml.xsd @@ -0,0 +1,145 @@ +<?xml version='1.0'?> +<xs:schema targetNamespace="http://www.w3.org/XML/1998/namespace" xmlns:xs="http://www.w3.org/2001/XMLSchema" xml:lang="en"> + + <xs:annotation> + <xs:documentation> + See http://www.w3.org/XML/1998/namespace.html and + http://www.w3.org/TR/REC-xml for information about this namespace. + + This schema document describes the XML namespace, in a form + suitable for import by other schema documents. + + Note that local names in this namespace are intended to be defined + only by the World Wide Web Consortium or its subgroups. The + following names are currently defined in this namespace and should + not be used with conflicting semantics by any Working Group, + specification, or document instance: + + base (as an attribute name): denotes an attribute whose value + provides a URI to be used as the base for interpreting any + relative URIs in the scope of the element on which it + appears; its value is inherited. This name is reserved + by virtue of its definition in the XML Base specification. + + id (as an attribute name): denotes an attribute whose value + should be interpreted as if declared to be of type ID. + This name is reserved by virtue of its definition in the + xml:id specification. + + lang (as an attribute name): denotes an attribute whose value + is a language code for the natural language of the content of + any element; its value is inherited. This name is reserved + by virtue of its definition in the XML specification. + + space (as an attribute name): denotes an attribute whose + value is a keyword indicating what whitespace processing + discipline is intended for the content of the element; its + value is inherited. This name is reserved by virtue of its + definition in the XML specification. + + Father (in any context at all): denotes Jon Bosak, the chair of + the original XML Working Group. This name is reserved by + the following decision of the W3C XML Plenary and + XML Coordination groups: + + In appreciation for his vision, leadership and dedication + the W3C XML Plenary on this 10th day of February, 2000 + reserves for Jon Bosak in perpetuity the XML name + xml:Father + </xs:documentation> + </xs:annotation> + + <xs:annotation> + <xs:documentation>This schema defines attributes and an attribute group + suitable for use by + schemas wishing to allow xml:base, xml:lang, xml:space or xml:id + attributes on elements they define. + + To enable this, such a schema must import this schema + for the XML namespace, e.g. as follows: + <schema . . .> + . . . + <import namespace="http://www.w3.org/XML/1998/namespace" + schemaLocation="http://www.w3.org/2001/xml.xsd"/> + + Subsequently, qualified reference to any of the attributes + or the group defined below will have the desired effect, e.g. + + <type . . .> + . . . + <attributeGroup ref="xml:specialAttrs"/> + + will define a type which will schema-validate an instance + element with any of those attributes</xs:documentation> + </xs:annotation> + + <xs:annotation> + <xs:documentation>In keeping with the XML Schema WG's standard versioning + policy, this schema document will persist at + http://www.w3.org/2007/08/xml.xsd. + At the date of issue it can also be found at + http://www.w3.org/2001/xml.xsd. + The schema document at that URI may however change in the future, + in order to remain compatible with the latest version of XML Schema + itself, or with the XML namespace itself. In other words, if the XML + Schema or XML namespaces change, the version of this document at + http://www.w3.org/2001/xml.xsd will change + accordingly; the version at + http://www.w3.org/2007/08/xml.xsd will not change. + </xs:documentation> + </xs:annotation> + + <xs:attribute name="lang"> + <xs:annotation> + <xs:documentation>Attempting to install the relevant ISO 2- and 3-letter + codes as the enumerated possible values is probably never + going to be a realistic possibility. See + RFC 3066 at http://www.ietf.org/rfc/rfc3066.txt and the IANA registry + at http://www.iana.org/assignments/lang-tag-apps.htm for + further information. + + The union allows for the 'un-declaration' of xml:lang with + the empty string.</xs:documentation> + </xs:annotation> + <xs:simpleType> + <xs:union memberTypes="xs:language"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value=""/> + </xs:restriction> + </xs:simpleType> + </xs:union> + </xs:simpleType> + </xs:attribute> + + <xs:attribute name="space"> + <xs:simpleType> + <xs:restriction base="xs:NCName"> + <xs:enumeration value="default"/> + <xs:enumeration value="preserve"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + + <xs:attribute name="base" type="xs:anyURI"> + <xs:annotation> + <xs:documentation>See http://www.w3.org/TR/xmlbase/ for + information about this attribute.</xs:documentation> + </xs:annotation> + </xs:attribute> + + <xs:attribute name="id" type="xs:ID"> + <xs:annotation> + <xs:documentation>See http://www.w3.org/TR/xml-id/ for + information about this attribute.</xs:documentation> + </xs:annotation> + </xs:attribute> + + <xs:attributeGroup name="specialAttrs"> + <xs:attribute ref="xml:base"/> + <xs:attribute ref="xml:lang"/> + <xs:attribute ref="xml:space"/> + <xs:attribute ref="xml:id"/> + </xs:attributeGroup> + +</xs:schema> diff --git a/src/xmlpatterns/schema/schemas/xml.xsd-LICENSE b/src/xmlpatterns/schema/schemas/xml.xsd-LICENSE new file mode 100644 index 0000000..2c687d8 --- /dev/null +++ b/src/xmlpatterns/schema/schemas/xml.xsd-LICENSE @@ -0,0 +1,40 @@ +W3CŪ SOFTWARE NOTICE AND LICENSE + +This license came from: http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 + +This work (and included software, documentation such as READMEs, or other +related items) is being provided by the copyright holders under the following +license. By obtaining, using and/or copying this work, you (the licensee) +agree that you have read, understood, and will comply with the following +terms and conditions. + +Permission to copy, modify, and distribute this software and its +documentation, with or without modification, for any purpose and without +fee or royalty is hereby granted, provided that you include the following on +ALL copies of the software and documentation or portions thereof, including +modifications: + + 1. The full text of this NOTICE in a location viewable to users of the + redistributed or derivative work. + 2. Any pre-existing intellectual property disclaimers, notices, or terms + and conditions. If none exist, the W3C Software Short Notice should be + included (hypertext is preferred, text is permitted) + within the body of any redistributed or derivative code. + 3. Notice of any changes or modifications to the files, including the date + changes were made. (We recommend you provide URIs to the location from + which the code is derived.) + +THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS +MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR +PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE +ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. + +COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR +DOCUMENTATION. + +The name and trademarks of copyright holders may NOT be used in +advertising or publicity pertaining to the software without specific, written +prior permission. Title to copyright in this software and any associated +documentation will at all times remain with copyright holders. diff --git a/src/xmlpatterns/schema/tokens.xml b/src/xmlpatterns/schema/tokens.xml new file mode 100644 index 0000000..5420695 --- /dev/null +++ b/src/xmlpatterns/schema/tokens.xml @@ -0,0 +1,155 @@ +<?xml version="1.0" encoding="UTF-8"?> +<tokenAutomaton scope="public" + className="XsdSchemaToken" + headerFile="qxsdschematoken_p.h" + sourceFile="qxsdschematoken.cpp" + defaultToken="NoKeyword" + tokenEnum="NodeName" + hasToString="true" + includeGuardName="QPatternist_XsdSchemaToken_h"> + <tokens> + <token>abstract</token> + <token>all</token> + <token>alternative</token> + <token>annotation</token> + <token>any</token> + <token>anyAttribute</token> + <token>appinfo</token> + <token>appliesToEmpty</token> + <token>assert</token> + <token>assertion</token> + <token>attribute</token> + <token>attributeFormDefault</token> + <token>attributeGroup</token> + <token>base</token> + <token>block</token> + <token>blockDefault</token> + <token>choice</token> + <token>collapse</token> + <token>complexContent</token> + <token>complexType</token> + <token>default</token> + <token>defaultAttributes</token> + <token>defaultAttributesApply</token> + <token>defaultOpenContent</token> + <token>documentation</token> + <token>element</token> + <token>elementFormDefault</token> + <token>enumeration</token> + <token>extension</token> + <token>field</token> + <token>final</token> + <token>finalDefault</token> + <token>fixed</token> + <token>form</token> + <token>fractionDigits</token> + <token>group</token> + <token>id</token> + <token>import</token> + <token>include</token> + <token>itemType</token> + <token>key</token> + <token>keyref</token> + <token>length</token> + <token>list</token> + <token>maxExclusive</token> + <token>maxInclusive</token> + <token>maxLength</token> + <token>maxOccurs</token> + <token>memberTypes</token> + <token>minExclusive</token> + <token>minInclusive</token> + <token>minLength</token> + <token>minOccurs</token> + <token>mixed</token> + <token>mode</token> + <token>name</token> + <token>namespace</token> + <token>nillable</token> + <token>notation</token> + <token>notNamespace</token> + <token>notQName</token> + <token>openContent</token> + <token>override</token> + <token>preserve</token> + <token>pattern</token> + <token>processContents</token> + <token>public</token> + <token>redefine</token> + <token>ref</token> + <token>refer</token> + <token>replace</token> + <token>restriction</token> + <token>schema</token> + <token>schemaLocation</token> + <token>selector</token> + <token>sequence</token> + <token>simpleContent</token> + <token>simpleType</token> + <token>source</token> + <token>substitutionGroup</token> + <token>system</token> + <token>targetNamespace</token> + <token>test</token> + <token>totalDigits</token> + <token>type</token> + <token>union</token> + <token>unique</token> + <token>use</token> + <token>value</token> + <token>version</token> + <token>whiteSpace</token> + <token>xpath</token> + <token name="XPathDefaultNamespace">xpathDefaultNamespace</token> + <token name="XmlLanguage">xml:lang</token> + <token name="XML_NS_SCHEMA_URI">http://www.w3.org/2001/XMLSchema</token> + </tokens> + + <boilerplate> + + <prolog>/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +</prolog> + + </boilerplate> + +</tokenAutomaton> diff --git a/src/xmlpatterns/type/qanysimpletype.cpp b/src/xmlpatterns/type/qanysimpletype.cpp index 9e5c876..659f4499 100644 --- a/src/xmlpatterns/type/qanysimpletype.cpp +++ b/src/xmlpatterns/type/qanysimpletype.cpp @@ -80,4 +80,14 @@ SchemaType::DerivationMethod AnySimpleType::derivationMethod() const return DerivationRestriction; } +bool AnySimpleType::isSimpleType() const +{ + return true; +} + +bool AnySimpleType::isComplexType() const +{ + return false; +} + QT_END_NAMESPACE diff --git a/src/xmlpatterns/type/qanysimpletype_p.h b/src/xmlpatterns/type/qanysimpletype_p.h index 8009c3b..a633052 100644 --- a/src/xmlpatterns/type/qanysimpletype_p.h +++ b/src/xmlpatterns/type/qanysimpletype_p.h @@ -73,6 +73,8 @@ namespace QPatternist class AnySimpleType : public AnyType { public: + typedef QExplicitlySharedDataPointer<AnySimpleType> Ptr; + typedef QList<AnySimpleType::Ptr> List; friend class BuiltinTypes; virtual ~AnySimpleType(); @@ -105,6 +107,16 @@ namespace QPatternist */ virtual SchemaType::DerivationMethod derivationMethod() const; + /** + * Always returns @c true. + */ + virtual bool isSimpleType() const; + + /** + * Always returns @c false. + */ + virtual bool isComplexType() const; + protected: AnySimpleType(); diff --git a/src/xmlpatterns/type/qanytype.cpp b/src/xmlpatterns/type/qanytype.cpp index 3d8714e..cabe56f 100644 --- a/src/xmlpatterns/type/qanytype.cpp +++ b/src/xmlpatterns/type/qanytype.cpp @@ -69,7 +69,7 @@ QXmlName AnyType::name(const NamePool::Ptr &np) const return np->allocateQName(StandardNamespaces::xs, QLatin1String("anyType")); } -QString AnyType::displayName(const NamePool::Ptr &) const +QString AnyType::displayName(const NamePool::Ptr &np) const { /* A bit faster than calling name()->displayName() */ return QLatin1String("xs:anyType"); @@ -85,9 +85,19 @@ SchemaType::TypeCategory AnyType::category() const return None; } +bool AnyType::isComplexType() const +{ + return true; +} + SchemaType::DerivationMethod AnyType::derivationMethod() const { return NoDerivation; } +SchemaType::DerivationConstraints AnyType::derivationConstraints() const +{ + return SchemaType::DerivationConstraints(); +} + QT_END_NAMESPACE diff --git a/src/xmlpatterns/type/qanytype_p.h b/src/xmlpatterns/type/qanytype_p.h index ae5cac8..7bc5554 100644 --- a/src/xmlpatterns/type/qanytype_p.h +++ b/src/xmlpatterns/type/qanytype_p.h @@ -114,6 +114,16 @@ namespace QPatternist */ virtual DerivationMethod derivationMethod() const; + /** + * @returns an empty set of derivation constraint flags. + */ + virtual DerivationConstraints derivationConstraints() const; + + /** + * Always returns @c true. + */ + virtual bool isComplexType() const; + protected: /** * @short This constructor is protected, because this diff --git a/src/xmlpatterns/type/qnamedschemacomponent.cpp b/src/xmlpatterns/type/qnamedschemacomponent.cpp new file mode 100644 index 0000000..c7bdc30 --- /dev/null +++ b/src/xmlpatterns/type/qnamedschemacomponent.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnamedschemacomponent_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +NamedSchemaComponent::NamedSchemaComponent() +{ +} + +NamedSchemaComponent::~NamedSchemaComponent() +{ +} + +void NamedSchemaComponent::setName(const QXmlName &name) +{ + m_name = name; +} + +QXmlName NamedSchemaComponent::name(const NamePool::Ptr&) const +{ + return m_name; +} + +QString NamedSchemaComponent::displayName(const NamePool::Ptr &np) const +{ + return np->displayName(m_name); +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/type/qnamedschemacomponent_p.h b/src/xmlpatterns/type/qnamedschemacomponent_p.h new file mode 100644 index 0000000..ab8a916 --- /dev/null +++ b/src/xmlpatterns/type/qnamedschemacomponent_p.h @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_NamedSchemaComponent_H +#define Patternist_NamedSchemaComponent_H + +#include "qnamepool_p.h" +#include "qschemacomponent_p.h" +#include "qxmlname.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short Base class for all named components that can appear in a W3C XML Schema. + * + * @ingroup Patternist_types + * @author Tobias Koenig <tobias.koenig@trolltech.com> + */ + class NamedSchemaComponent : public SchemaComponent + { + public: + typedef QExplicitlySharedDataPointer<NamedSchemaComponent> Ptr; + + /** + * Describes the blocking constraints that are given by the 'block' attributes. + */ + enum BlockingConstraint + { + RestrictionConstraint = 1, + ExtensionConstraint = 2, + SubstitutionConstraint = 4 + }; + Q_DECLARE_FLAGS(BlockingConstraints, BlockingConstraint) + + /** + * Creates a new named schema component. + */ + NamedSchemaComponent(); + + /** + * Destroys the named schema component. + */ + virtual ~NamedSchemaComponent(); + + /** + * Sets the @p name of the schema component. + */ + void setName(const QXmlName &name); + + /** + * Returns the name of the schema component. + * + * @param namePool The name pool the name belongs to. + */ + virtual QXmlName name(const NamePool::Ptr &namePool) const; + + /** + * Returns the display name of the schema component. + * + * @param namePool The name pool the name belongs to. + */ + virtual QString displayName(const NamePool::Ptr &namePool) const; + + private: + QXmlName m_name; + }; + + Q_DECLARE_OPERATORS_FOR_FLAGS(NamedSchemaComponent::BlockingConstraints) +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/type/qprimitives_p.h b/src/xmlpatterns/type/qprimitives_p.h index 818cb22..b77698a 100644 --- a/src/xmlpatterns/type/qprimitives_p.h +++ b/src/xmlpatterns/type/qprimitives_p.h @@ -53,6 +53,8 @@ #define Patternist_Primitives_H #include <QtGlobal> +#include <QtCore/QHash> +#include <QtCore/QUrl> /** * @file @@ -79,6 +81,17 @@ namespace QPatternist { /** + * @internal + * + * A method to allow a QHash or QSet with QUrl + * as key type. + */ + inline uint qHash(const QUrl &uri) + { + return qHash(uri.toString()); + } + + /** * @defgroup Patternist_cppWXSTypes C++ Primitives for W3C XML Schema Number Types * * The implementations of W3C XML Schema's(WXS) number types, more specifically @@ -195,6 +208,8 @@ namespace QPatternist QString Q_AUTOTEST_EXPORT escape(const QString &input); } +using QPatternist::qHash; + QT_END_NAMESPACE QT_END_HEADER diff --git a/src/xmlpatterns/type/qschematype.cpp b/src/xmlpatterns/type/qschematype.cpp index e7b8738..51ac41d 100644 --- a/src/xmlpatterns/type/qschematype.cpp +++ b/src/xmlpatterns/type/qschematype.cpp @@ -72,4 +72,9 @@ bool SchemaType::isComplexType() const return category() == ComplexType; } +bool SchemaType::isDefinedBySchema() const +{ + return false; +} + QT_END_NAMESPACE diff --git a/src/xmlpatterns/type/qschematype_p.h b/src/xmlpatterns/type/qschematype_p.h index 38ed9b6..eaac28a 100644 --- a/src/xmlpatterns/type/qschematype_p.h +++ b/src/xmlpatterns/type/qschematype_p.h @@ -57,6 +57,7 @@ #include "qxmlname.h" template<typename N, typename M> class QHash; +template<typename N> class QList; QT_BEGIN_HEADER @@ -80,6 +81,7 @@ namespace QPatternist typedef QExplicitlySharedDataPointer<SchemaType> Ptr; typedef QHash<QXmlName, SchemaType::Ptr> Hash; + typedef QList<SchemaType::Ptr> List; /** * Schema types are divided into different categories such as @@ -117,6 +119,18 @@ namespace QPatternist NoDerivation = 16 }; + /** + * Describes the derivation constraints that are given by the 'final' or 'block' attributes. + */ + enum DerivationConstraint + { + RestrictionConstraint = 1, + ExtensionConstraint = 2, + ListConstraint = 4, + UnionConstraint = 8 + }; + Q_DECLARE_FLAGS(DerivationConstraints, DerivationConstraint) + SchemaType(); virtual ~SchemaType(); @@ -137,6 +151,11 @@ namespace QPatternist virtual DerivationMethod derivationMethod() const = 0; /** + * Determines what derivation constraints exists for the type. + */ + virtual DerivationConstraints derivationConstraints() const = 0; + + /** * Determines whether the type is an abstract type. * * @note It is important a correct value is returned, since @@ -202,7 +221,7 @@ namespace QPatternist * @note Do not re-implement this function, but instead override category() * and let it return an appropriate value. */ - bool isSimpleType() const; + virtual bool isSimpleType() const; /** * Determines whether the type is a complex type, by introspecting @@ -211,8 +230,15 @@ namespace QPatternist * @note Do not re-implement this function, but instead override category() * and let it return an appropriate value. */ - bool isComplexType() const; + virtual bool isComplexType() const; + + /** + * Returns whether the value has been defined by a schema (is not a built in type). + */ + virtual bool isDefinedBySchema() const; }; + + Q_DECLARE_OPERATORS_FOR_FLAGS(SchemaType::DerivationConstraints) } QT_END_NAMESPACE diff --git a/src/xmlpatterns/type/type.pri b/src/xmlpatterns/type/type.pri index ef5976a..5425298 100644 --- a/src/xmlpatterns/type/type.pri +++ b/src/xmlpatterns/type/type.pri @@ -24,6 +24,7 @@ HEADERS += $$PWD/qabstractnodetest_p.h \ $$PWD/qitemtype_p.h \ $$PWD/qlocalnametest_p.h \ $$PWD/qmultiitemtype_p.h \ + $$PWD/qnamedschemacomponent_p.h \ $$PWD/qnamespacenametest_p.h \ $$PWD/qnonetype_p.h \ $$PWD/qnumerictype_p.h \ @@ -57,6 +58,7 @@ SOURCES += $$PWD/qabstractnodetest.cpp \ $$PWD/qitemtype.cpp \ $$PWD/qlocalnametest.cpp \ $$PWD/qmultiitemtype.cpp \ + $$PWD/qnamedschemacomponent.cpp \ $$PWD/qnamespacenametest.cpp \ $$PWD/qnonetype.cpp \ $$PWD/qnumerictype.cpp \ diff --git a/src/xmlpatterns/utils/qpatternistlocale_p.h b/src/xmlpatterns/utils/qpatternistlocale_p.h index 5dcd917..d8288c7 100644 --- a/src/xmlpatterns/utils/qpatternistlocale_p.h +++ b/src/xmlpatterns/utils/qpatternistlocale_p.h @@ -93,7 +93,8 @@ namespace QPatternist Q_DISABLE_COPY(QtXmlPatterns) }; - static inline QString formatKeyword(const QString &keyword) + // don't make this function static, otherwise xlC 7 cannot find it + inline QString formatKeyword(const QString &keyword) { return QLatin1String("<span class='XQuery-keyword'>") + escape(keyword) + @@ -168,6 +169,16 @@ namespace QPatternist } /** + * @short Formats name of any type. + */ + static inline QString formatType(const NamePool::Ptr &np, const QXmlName &name) + { + return QLatin1String("<span class='XQuery-type'>") + + escape(np->displayName(name)) + + QLatin1String("</span>"); + } + + /** * @short Formats Cardinality. */ static inline QString formatType(const Cardinality &type) diff --git a/src/xmlpatterns/utils/qxpathhelper.cpp b/src/xmlpatterns/utils/qxpathhelper.cpp index 377d097..69f5494 100644 --- a/src/xmlpatterns/utils/qxpathhelper.cpp +++ b/src/xmlpatterns/utils/qxpathhelper.cpp @@ -125,4 +125,16 @@ ItemType::Ptr XPathHelper::typeFromKind(const QXmlNodeModelIndex::NodeKind nodeK } } +QUrl XPathHelper::normalizeQueryURI(const QUrl &uri) +{ + Q_ASSERT_X(uri.isEmpty() || uri.isValid(), Q_FUNC_INFO, + "The URI passed to QXmlQuery::setQuery() must be valid or empty."); + if(uri.isEmpty()) + return QUrl::fromLocalFile(QCoreApplication::applicationFilePath()); + else if(uri.isRelative()) + return QUrl::fromLocalFile(QCoreApplication::applicationFilePath()).resolved(uri); + else + return uri; +} + QT_END_NAMESPACE diff --git a/src/xmlpatterns/utils/qxpathhelper_p.h b/src/xmlpatterns/utils/qxpathhelper_p.h index 8b7dc6e..4a37bb6 100644 --- a/src/xmlpatterns/utils/qxpathhelper_p.h +++ b/src/xmlpatterns/utils/qxpathhelper_p.h @@ -128,6 +128,11 @@ namespace QPatternist static QPatternist::ItemTypePtr typeFromKind(const QXmlNodeModelIndex::NodeKind nodeKind); /** + * Normalizes an @p uri by resolving it to the application directory if empty. + */ + static QUrl normalizeQueryURI(const QUrl &uri); + + /** * @short Determines whether @p consists only of whitespace. Characters * considered whitespace are the ones for which QChar::isSpace() returns @c true for. * diff --git a/src/xmlpatterns/xmlpatterns.pro b/src/xmlpatterns/xmlpatterns.pro index e9d8af9..fb6aa1a 100644 --- a/src/xmlpatterns/xmlpatterns.pro +++ b/src/xmlpatterns/xmlpatterns.pro @@ -21,6 +21,8 @@ include($$PWD/iterators/iterators.pri) include($$PWD/janitors/janitors.pri) include($$PWD/parser/parser.pri) include($$PWD/projection/projection.pri) +include($$PWD/schema/schema.pri) +include($$PWD/schematron/schematron.pri) include($$PWD/type/type.pri) include($$PWD/utils/utils.pri) include($$PWD/qobjectmodel/qobjectmodel.pri) |