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