1 /*******************************************************************
2
3 Part of the Fritzing project - http://fritzing.org
4 Copyright (c) 2007-2014 Fachhochschule Potsdam - http://fh-potsdam.de
5
6 Fritzing is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 Fritzing 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
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Fritzing. If not, see <http://www.gnu.org/licenses/>.
18
19 ********************************************************************
20
21 $Revision: 6904 $:
22 $Author: irascibl@gmail.com $:
23 $Date: 2013-02-26 16:26:03 +0100 (Di, 26. Feb 2013) $
24
25 ********************************************************************/
26
27 #include "svgpathlexer.h"
28 #include "svgpathgrammar_p.h"
29 #include "../utils/textutils.h"
30 #include <qdebug.h>
31
32 static const QRegExp findWhitespaceBefore(" ([AaCcMmVvTtQqSsLlVvHhZz,])");
33 static const QRegExp findWhitespaceAfter("([AaCcMmVvTtQqSsLlVvHhZz,]) ");
34 static const QRegExp findWhitespaceAtEnd(" $");
35
SVGPathLexer(const QString & source)36 SVGPathLexer::SVGPathLexer(const QString &source)
37 {
38 m_source = clean(source);
39 m_chars = m_source.unicode();
40 m_size = m_source.size();
41 //qDebug() << m_source;
42 m_pos = 0;
43 m_current = next();
44 }
45
~SVGPathLexer()46 SVGPathLexer::~SVGPathLexer()
47 {
48 }
49
clean(const QString & source)50 QString SVGPathLexer::clean(const QString & source) {
51 // SVG path grammar is ambiguous, so clean it up to make it easier to parse
52 // the rules are WSP* , WSP* ==> ,
53 // WSP* command WSP* ==> command
54 // WSP+ ==> WSP
55 // where WSP is whitespace, command is one of the path commands such as M C V ...
56
57
58 QString s1 = source;
59 s1.replace(TextUtils::FindWhitespace, " ");
60 s1.replace(findWhitespaceBefore, "\\1"); // replace with the captured character
61 s1.replace(findWhitespaceAfter, "\\1"); // replace with the captured character
62 s1.replace(findWhitespaceAtEnd, "");
63 return s1;
64
65 }
66
lex()67 int SVGPathLexer::lex()
68 {
69 if (TextUtils::floatingPointMatcher.indexIn(m_source, m_pos - 1) == m_pos - 1) {
70 m_currentNumber = m_source.mid(m_pos - 1, TextUtils::floatingPointMatcher.matchedLength()).toDouble();
71 m_pos += TextUtils::floatingPointMatcher.matchedLength() - 1;
72 next();
73 return SVGPathGrammar::NUMBER;
74 }
75
76 if (m_current.isSpace()) {
77 next();
78 return SVGPathGrammar::WHITESPACE;
79 }
80 else if (m_current.isNull()) {
81 return SVGPathGrammar::EOF_SYMBOL;
82 }
83 else if (m_current == QLatin1Char('V')) {
84 m_currentCommand = m_current;
85 next();
86 return SVGPathGrammar::VEE;
87 }
88 else if (m_current == QLatin1Char('v')) {
89 m_currentCommand = m_current;
90 next();
91 return SVGPathGrammar::VEE;
92 }
93 else if (m_current == QLatin1Char('T')) {
94 m_currentCommand = m_current;
95 next();
96 return SVGPathGrammar::TEE;
97 }
98 else if (m_current == QLatin1Char('t')) {
99 m_currentCommand = m_current;
100 next();
101 return SVGPathGrammar::TEE;
102 }
103 else if (m_current == QLatin1Char(FakeClosePathChar)) {
104 m_currentCommand = m_current;
105 next();
106 return SVGPathGrammar::EKS;
107 }
108 else if (m_current == QLatin1Char('C')) {
109 m_currentCommand = m_current;
110 next();
111 return SVGPathGrammar::CEE;
112 }
113 else if (m_current == QLatin1Char('c')) {
114 m_currentCommand = m_current;
115 next();
116 return SVGPathGrammar::CEE;
117 }
118 else if (m_current == QLatin1Char('Q')) {
119 m_currentCommand = m_current;
120 next();
121 return SVGPathGrammar::KYU;
122 }
123 else if (m_current == QLatin1Char('q')) {
124 m_currentCommand = m_current;
125 next();
126 return SVGPathGrammar::KYU;
127 }
128 else if (m_current == QLatin1Char('S')) {
129 m_currentCommand = m_current;
130 next();
131 return SVGPathGrammar::ESS;
132 }
133 else if (m_current == QLatin1Char('s')) {
134 m_currentCommand = m_current;
135 next();
136 return SVGPathGrammar::ESS;
137 }
138 else if (m_current == QLatin1Char('H')) {
139 m_currentCommand = m_current;
140 next();
141 return SVGPathGrammar::AITCH;
142 }
143 else if (m_current == QLatin1Char('h')) {
144 m_currentCommand = m_current;
145 next();
146 return SVGPathGrammar::AITCH;
147 }
148 else if (m_current == QLatin1Char('L')) {
149 m_currentCommand = m_current;
150 next();
151 return SVGPathGrammar::EL;
152 }
153 else if (m_current == QLatin1Char('l')) {
154 m_currentCommand = m_current;
155 next();
156 return SVGPathGrammar::EL;
157 }
158 else if (m_current == QLatin1Char('M')) {
159 m_currentCommand = m_current;
160 next();
161 return SVGPathGrammar::EM;
162 }
163 else if (m_current == QLatin1Char('m')) {
164 m_currentCommand = m_current;
165 next();
166 return SVGPathGrammar::EM;
167 }
168 else if (m_current == QLatin1Char('A')) {
169 m_currentCommand = m_current;
170 next();
171 return SVGPathGrammar::AE;
172 }
173 else if (m_current == QLatin1Char('a')) {
174 m_currentCommand = m_current;
175 next();
176 return SVGPathGrammar::AE;
177 }
178 else if (m_current == QLatin1Char('Z')) {
179 m_currentCommand = m_current;
180 next();
181 return SVGPathGrammar::ZEE;
182 }
183 else if (m_current == QLatin1Char('z')) {
184 m_currentCommand = m_current;
185 next();
186 return SVGPathGrammar::ZEE;
187 }
188 else if (m_current == QLatin1Char(',')) {
189 next();
190 return SVGPathGrammar::COMMA;
191 }
192
193
194 return -1;
195 }
196
next()197 QChar SVGPathLexer::next()
198 {
199 if (m_pos < m_size)
200 m_current = m_chars[m_pos++];
201 else
202 m_current = QChar();
203 return m_current;
204 }
205
currentCommand()206 QChar SVGPathLexer::currentCommand() {
207 return m_currentCommand;
208 }
209
currentNumber()210 double SVGPathLexer::currentNumber() {
211 return m_currentNumber;
212 }
213
214