1 /*
2  * This file is part of the XSL implementation.
3  *
4  * Copyright (C) 2009 Jakub Wieczorek <faw217@gmail.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 
22 #include "config.h"
23 
24 #if ENABLE(XSLT)
25 
26 #include "XSLTProcessor.h"
27 
28 #include "Console.h"
29 #include "DOMWindow.h"
30 #include "Frame.h"
31 #include "SecurityOrigin.h"
32 #include "TransformSource.h"
33 #include "markup.h"
34 #include <wtf/Assertions.h>
35 #include <wtf/Vector.h>
36 
37 #include <qabstractmessagehandler.h>
38 #include <qabstracturiresolver.h>
39 #include <qbuffer.h>
40 #include <qsourcelocation.h>
41 #include <qxmlquery.h>
42 
43 namespace WebCore {
44 
45 class XSLTMessageHandler : public QAbstractMessageHandler {
46 
47 public:
48     XSLTMessageHandler(Document* document = 0);
49     virtual void handleMessage(QtMsgType type, const QString& description,
50                                const QUrl& identifier, const QSourceLocation& sourceLocation);
51 
52 private:
53     Document* m_document;
54 };
55 
XSLTMessageHandler(Document * document)56 XSLTMessageHandler::XSLTMessageHandler(Document* document)
57     : QAbstractMessageHandler()
58     , m_document(document)
59 {
60 }
61 
handleMessage(QtMsgType type,const QString & description,const QUrl &,const QSourceLocation & sourceLocation)62 void XSLTMessageHandler::handleMessage(QtMsgType type, const QString& description,
63                                        const QUrl&, const QSourceLocation& sourceLocation)
64 {
65     if (!m_document->frame())
66         return;
67 
68     MessageLevel level;
69     switch (type) {
70     case QtDebugMsg:
71         level = TipMessageLevel;
72         break;
73     case QtWarningMsg:
74         level = WarningMessageLevel;
75         break;
76     case QtCriticalMsg:
77     case QtFatalMsg:
78         level = ErrorMessageLevel;
79         break;
80     default:
81         level = LogMessageLevel;
82         break;
83     }
84 
85     Console* console = m_document->frame()->domWindow()->console();
86     console->addMessage(XMLMessageSource, LogMessageType, level, description,
87                         sourceLocation.line(), sourceLocation.uri().toString());
88 }
89 
90 class XSLTUriResolver : public QAbstractUriResolver {
91 
92 public:
93     XSLTUriResolver(Document* document);
94     virtual QUrl resolve(const QUrl& relative, const QUrl& baseURI) const;
95 
96 private:
97     Document* m_document;
98 };
99 
XSLTUriResolver(Document * document)100 XSLTUriResolver::XSLTUriResolver(Document* document)
101     : QAbstractUriResolver()
102     , m_document(document)
103 {
104 }
105 
resolve(const QUrl & relative,const QUrl & baseURI) const106 QUrl XSLTUriResolver::resolve(const QUrl& relative, const QUrl& baseURI) const
107 {
108     QUrl url = baseURI.resolved(relative);
109 
110     if (!m_document->frame() || !m_document->securityOrigin()->canRequest(url))
111         return QUrl();
112     return url;
113 }
114 
transformToString(Node * sourceNode,String &,String & resultString,String &)115 bool XSLTProcessor::transformToString(Node* sourceNode, String&, String& resultString, String&)
116 {
117     bool success = false;
118 
119     RefPtr<XSLStyleSheet> stylesheet = m_stylesheet;
120     if (!stylesheet && m_stylesheetRootNode) {
121         Node* node = m_stylesheetRootNode.get();
122         stylesheet = XSLStyleSheet::createForXSLTProcessor(node->parentNode() ? node->parentNode() : node,
123             node->document()->url().string(),
124             node->document()->url()); // FIXME: Should we use baseURL here?
125 
126         // According to Mozilla documentation, the node must be a Document node, an xsl:stylesheet or xsl:transform element.
127         // But we just use text content regardless of node type.
128         stylesheet->parseString(createMarkup(node));
129     }
130 
131     if (!stylesheet || stylesheet->sheetString().isEmpty())
132         return success;
133 
134     RefPtr<Document> ownerDocument = sourceNode->document();
135     bool sourceIsDocument = (sourceNode == ownerDocument.get());
136 
137     QXmlQuery query(QXmlQuery::XSLT20);
138 
139     XSLTMessageHandler messageHandler(ownerDocument.get());
140     XSLTUriResolver uriResolver(ownerDocument.get());
141     query.setMessageHandler(&messageHandler);
142 
143     XSLTProcessor::ParameterMap::iterator end = m_parameters.end();
144     for (XSLTProcessor::ParameterMap::iterator it = m_parameters.begin(); it != end; ++it)
145         query.bindVariable(QString(it->first), QXmlItem(QVariant(QString(it->second))));
146 
147     QString source;
148     if (sourceIsDocument && ownerDocument->transformSource())
149         source = ownerDocument->transformSource()->platformSource();
150     if (!sourceIsDocument || source.isEmpty())
151         source = createMarkup(sourceNode);
152 
153     QBuffer inputBuffer;
154     QBuffer styleSheetBuffer;
155     QBuffer outputBuffer;
156 
157     inputBuffer.setData(source.toUtf8());
158     styleSheetBuffer.setData(QString(stylesheet->sheetString()).toUtf8());
159 
160     inputBuffer.open(QIODevice::ReadOnly);
161     styleSheetBuffer.open(QIODevice::ReadOnly);
162     outputBuffer.open(QIODevice::ReadWrite);
163 
164     query.setFocus(&inputBuffer);
165     query.setQuery(&styleSheetBuffer, QUrl(stylesheet->href()));
166 
167     query.setUriResolver(&uriResolver);
168 
169     success = query.evaluateTo(&outputBuffer);
170     outputBuffer.reset();
171     resultString = QString::fromUtf8(outputBuffer.readAll()).trimmed();
172 
173     if (m_stylesheet) {
174         m_stylesheet->clearDocuments();
175         m_stylesheet = 0;
176     }
177 
178     return success;
179 }
180 
181 } // namespace WebCore
182 
183 #endif // ENABLE(XSLT)
184