1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). |
4 | ** Contact: http://www.qt-project.org/legal |
5 | ** |
6 | ** This file is part of the QtDeclarative module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and Digia. For licensing terms and |
14 | ** conditions see http://qt.digia.com/licensing. For further information |
15 | ** use the contact form at http://qt.digia.com/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 2.1 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 2.1 requirements |
23 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
24 | ** |
25 | ** In addition, as a special exception, Digia gives you certain additional |
26 | ** rights. These rights are described in the Digia Qt LGPL Exception |
27 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
28 | ** |
29 | ** GNU General Public License Usage |
30 | ** Alternatively, this file may be used under the terms of the GNU |
31 | ** General Public License version 3.0 as published by the Free Software |
32 | ** Foundation and appearing in the file LICENSE.GPL included in the |
33 | ** packaging of this file. Please review the following information to |
34 | ** ensure the GNU General Public License version 3.0 requirements will be |
35 | ** met: http://www.gnu.org/copyleft/gpl.html. |
36 | ** |
37 | ** |
38 | ** $QT_END_LICENSE$ |
39 | ** |
40 | ****************************************************************************/ |
41 | |
42 | #include "private/qdeclarativedirparser_p.h" |
43 | #include "qdeclarativeerror.h" |
44 | #include <private/qdeclarativeglobal_p.h> |
45 | |
46 | #include <QtCore/QTextStream> |
47 | #include <QtCore/QFile> |
48 | #include <QtCore/QtDebug> |
49 | |
50 | QT_BEGIN_NAMESPACE |
51 | |
52 | QDeclarativeDirParser::QDeclarativeDirParser() |
53 | : _isParsed(false) |
54 | { |
55 | } |
56 | |
57 | QDeclarativeDirParser::~QDeclarativeDirParser() |
58 | { |
59 | } |
60 | |
61 | QUrl QDeclarativeDirParser::url() const |
62 | { |
63 | return _url; |
64 | } |
65 | |
66 | void QDeclarativeDirParser::setUrl(const QUrl &url) |
67 | { |
68 | _url = url; |
69 | } |
70 | |
71 | QString QDeclarativeDirParser::fileSource() const |
72 | { |
73 | return _filePathSouce; |
74 | } |
75 | |
76 | void QDeclarativeDirParser::setFileSource(const QString &filePath) |
77 | { |
78 | _filePathSouce = filePath; |
79 | } |
80 | |
81 | QString QDeclarativeDirParser::source() const |
82 | { |
83 | return _source; |
84 | } |
85 | |
86 | void QDeclarativeDirParser::setSource(const QString &source) |
87 | { |
88 | _isParsed = false; |
89 | _source = source; |
90 | } |
91 | |
92 | bool QDeclarativeDirParser::isParsed() const |
93 | { |
94 | return _isParsed; |
95 | } |
96 | |
97 | bool QDeclarativeDirParser::parse() |
98 | { |
99 | if (_isParsed) |
100 | return true; |
101 | |
102 | _isParsed = true; |
103 | _errors.clear(); |
104 | _plugins.clear(); |
105 | _components.clear(); |
106 | |
107 | if (_source.isEmpty() && !_filePathSouce.isEmpty()) { |
108 | QFile file(_filePathSouce); |
109 | if (!QDeclarative_isFileCaseCorrect(_filePathSouce)) { |
110 | QDeclarativeError error; |
111 | error.setDescription(QString::fromUtf8("cannot load module \"$$URI$$\": File name case mismatch for \"%1\"" ).arg(_filePathSouce)); |
112 | _errors.prepend(error); |
113 | return false; |
114 | } else if (file.open(QFile::ReadOnly)) { |
115 | _source = QString::fromUtf8(file.readAll()); |
116 | } else { |
117 | QDeclarativeError error; |
118 | error.setDescription(QString::fromUtf8("module \"$$URI$$\" definition \"%1\" not readable" ).arg(_filePathSouce)); |
119 | _errors.prepend(error); |
120 | return false; |
121 | } |
122 | } |
123 | |
124 | QTextStream stream(&_source); |
125 | int lineNumber = 0; |
126 | |
127 | forever { |
128 | ++lineNumber; |
129 | |
130 | const QString line = stream.readLine(); |
131 | if (line.isNull()) |
132 | break; |
133 | |
134 | QString sections[3]; |
135 | int sectionCount = 0; |
136 | |
137 | int index = 0; |
138 | const int length = line.length(); |
139 | |
140 | while (index != length) { |
141 | const QChar ch = line.at(index); |
142 | |
143 | if (ch.isSpace()) { |
144 | do { ++index; } |
145 | while (index != length && line.at(index).isSpace()); |
146 | |
147 | } else if (ch == QLatin1Char('#')) { |
148 | // recognized a comment |
149 | break; |
150 | |
151 | } else { |
152 | const int start = index; |
153 | |
154 | do { ++index; } |
155 | while (index != length && !line.at(index).isSpace()); |
156 | |
157 | const QString lexeme = line.mid(start, index - start); |
158 | |
159 | if (sectionCount >= 3) { |
160 | reportError(lineNumber, start, QLatin1String("unexpected token" )); |
161 | |
162 | } else { |
163 | sections[sectionCount++] = lexeme; |
164 | } |
165 | } |
166 | } |
167 | |
168 | if (sectionCount == 0) { |
169 | continue; // no sections, no party. |
170 | |
171 | } else if (sections[0] == QLatin1String("plugin" )) { |
172 | if (sectionCount < 2) { |
173 | reportError(lineNumber, -1, |
174 | QString::fromUtf8("plugin directive requires 2 arguments, but %1 were provided" ).arg(sectionCount + 1)); |
175 | |
176 | continue; |
177 | } |
178 | |
179 | const Plugin entry(sections[1], sections[2]); |
180 | |
181 | _plugins.append(entry); |
182 | |
183 | } else if (sections[0] == QLatin1String("internal" )) { |
184 | if (sectionCount != 3) { |
185 | reportError(lineNumber, -1, |
186 | QString::fromUtf8("internal types require 2 arguments, but %1 were provided" ).arg(sectionCount + 1)); |
187 | continue; |
188 | } |
189 | Component entry(sections[1], sections[2], -1, -1); |
190 | entry.internal = true; |
191 | _components.append(entry); |
192 | } else if (sections[0] == QLatin1String("typeinfo" )) { |
193 | if (sectionCount != 2) { |
194 | reportError(lineNumber, -1, |
195 | QString::fromUtf8("typeinfo requires 1 argument, but %1 were provided" ).arg(sectionCount - 1)); |
196 | continue; |
197 | } |
198 | #ifdef QT_CREATOR |
199 | TypeInfo typeInfo(sections[1]); |
200 | _typeInfos.append(typeInfo); |
201 | #endif |
202 | |
203 | } else if (sectionCount == 2) { |
204 | // No version specified (should only be used for relative qmldir files) |
205 | const Component entry(sections[0], sections[1], -1, -1); |
206 | _components.append(entry); |
207 | } else if (sectionCount == 3) { |
208 | const QString &version = sections[1]; |
209 | const int dotIndex = version.indexOf(QLatin1Char('.')); |
210 | |
211 | if (dotIndex == -1) { |
212 | reportError(lineNumber, -1, QLatin1String("expected '.'" )); |
213 | } else if (version.indexOf(QLatin1Char('.'), dotIndex + 1) != -1) { |
214 | reportError(lineNumber, -1, QLatin1String("unexpected '.'" )); |
215 | } else { |
216 | bool validVersionNumber = false; |
217 | const int majorVersion = version.left(dotIndex).toInt(&validVersionNumber); |
218 | |
219 | if (validVersionNumber) { |
220 | const int minorVersion = version.mid(dotIndex + 1).toInt(&validVersionNumber); |
221 | |
222 | if (validVersionNumber) { |
223 | const Component entry(sections[0], sections[2], majorVersion, minorVersion); |
224 | |
225 | _components.append(entry); |
226 | } |
227 | } |
228 | } |
229 | } else { |
230 | reportError(lineNumber, -1, |
231 | QString::fromUtf8("a component declaration requires 3 arguments, but %1 were provided" ).arg(sectionCount + 1)); |
232 | } |
233 | } |
234 | |
235 | return hasError(); |
236 | } |
237 | |
238 | void QDeclarativeDirParser::reportError(int line, int column, const QString &description) |
239 | { |
240 | QDeclarativeError error; |
241 | error.setUrl(_url); |
242 | error.setLine(line); |
243 | error.setColumn(column); |
244 | error.setDescription(description); |
245 | _errors.append(error); |
246 | } |
247 | |
248 | bool QDeclarativeDirParser::hasError() const |
249 | { |
250 | if (! _errors.isEmpty()) |
251 | return true; |
252 | |
253 | return false; |
254 | } |
255 | |
256 | QList<QDeclarativeError> QDeclarativeDirParser::errors(const QString &uri) const |
257 | { |
258 | QList<QDeclarativeError> errors = _errors; |
259 | for (int i = 0; i < errors.size(); ++i) { |
260 | QDeclarativeError &e = errors[i]; |
261 | QString description = e.description(); |
262 | description.replace(QLatin1String("$$URI$$" ), uri); |
263 | e.setDescription(description); |
264 | } |
265 | return errors; |
266 | } |
267 | |
268 | QList<QDeclarativeDirParser::Plugin> QDeclarativeDirParser::plugins() const |
269 | { |
270 | return _plugins; |
271 | } |
272 | |
273 | QList<QDeclarativeDirParser::Component> QDeclarativeDirParser::components() const |
274 | { |
275 | return _components; |
276 | } |
277 | |
278 | #ifdef QT_CREATOR |
279 | QList<QDeclarativeDirParser::TypeInfo> QDeclarativeDirParser::typeInfos() const |
280 | { |
281 | return _typeInfos; |
282 | } |
283 | #endif |
284 | |
285 | QT_END_NAMESPACE |
286 | |