1 /*
2 * Copyright (C) 2004-2010 Geometer Plus <contact@geometerplus.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 */
19
20 #include <cctype>
21 #include <cstring>
22
23 #include <ZLStringUtil.h>
24 #include <ZLInputStream.h>
25
26 #include "StyleSheetParser.h"
27
StyleSheetTableParser(StyleSheetTable & table)28 StyleSheetTableParser::StyleSheetTableParser(StyleSheetTable &table) : myTable(table) {
29 }
30
storeData(const std::string & tagName,const std::string & className,const StyleSheetTable::AttributeMap & map)31 void StyleSheetTableParser::storeData(const std::string &tagName, const std::string &className, const StyleSheetTable::AttributeMap &map) {
32 myTable.addMap(tagName, className, map);
33 }
34
parseString(const char * text)35 shared_ptr<ZLTextStyleEntry> StyleSheetSingleStyleParser::parseString(const char *text) {
36 myReadState = ATTRIBUTE_NAME;
37 parse(text, strlen(text), true);
38 shared_ptr<ZLTextStyleEntry> control = StyleSheetTable::createControl(myMap);
39 reset();
40 return control;
41 }
42
StyleSheetParser()43 StyleSheetParser::StyleSheetParser() : myReadState(TAG_NAME), myInsideComment(false) {
44 }
45
~StyleSheetParser()46 StyleSheetParser::~StyleSheetParser() {
47 }
48
reset()49 void StyleSheetParser::reset() {
50 myWord.erase();
51 myAttributeName.erase();
52 myReadState = TAG_NAME;
53 myInsideComment = false;
54 myTagName.erase();
55 myClassName.erase();
56 myMap.clear();
57 }
58
parse(ZLInputStream & stream)59 void StyleSheetParser::parse(ZLInputStream &stream) {
60 if (stream.open()) {
61 char *buffer = new char[1024];
62 while (true) {
63 int len = stream.read(buffer, 1024);
64 if (len == 0) {
65 break;
66 }
67 parse(buffer, len);
68 }
69 delete[] buffer;
70 stream.close();
71 }
72 }
73
parse(const char * text,int len,bool final)74 void StyleSheetParser::parse(const char *text, int len, bool final) {
75 const char *start = text;
76 const char *end = text + len;
77 for (const char *ptr = start; ptr != end; ++ptr) {
78 if (isspace(*ptr)) {
79 if (start != ptr) {
80 myWord.append(start, ptr - start);
81 }
82 processWord(myWord);
83 myWord.erase();
84 start = ptr + 1;
85 } else if (isControlSymbol(*ptr)) {
86 if (start != ptr) {
87 myWord.append(start, ptr - start);
88 }
89 processWord(myWord);
90 myWord.erase();
91 processControl(*ptr);
92 start = ptr + 1;
93 }
94 }
95 if (start < end) {
96 myWord.append(start, end - start);
97 if (final) {
98 processWord(myWord);
99 myWord.erase();
100 }
101 }
102 }
103
isControlSymbol(const char symbol)104 bool StyleSheetParser::isControlSymbol(const char symbol) {
105 switch (symbol) {
106 case '{':
107 case '}':
108 case ';':
109 case ':':
110 return true;
111 default:
112 return false;
113 }
114 }
115
storeData(const std::string &,const std::string &,const StyleSheetTable::AttributeMap &)116 void StyleSheetParser::storeData(const std::string&, const std::string&, const StyleSheetTable::AttributeMap&) {
117 }
118
processControl(const char control)119 void StyleSheetParser::processControl(const char control) {
120 switch (control) {
121 case '{':
122 myReadState = (myReadState == TAG_NAME) ? ATTRIBUTE_NAME : BROKEN;
123 break;
124 case '}':
125 if (myReadState != BROKEN) {
126 storeData(myTagName, myClassName, myMap);
127 }
128 myReadState = TAG_NAME;
129 myTagName.erase();
130 myClassName.erase();
131 myMap.clear();
132 break;
133 case ';':
134 myReadState =
135 ((myReadState == ATTRIBUTE_VALUE) ||
136 (myReadState == ATTRIBUTE_NAME)) ? ATTRIBUTE_NAME : BROKEN;
137 break;
138 case ':':
139 myReadState = (myReadState == ATTRIBUTE_NAME) ? ATTRIBUTE_VALUE : BROKEN;
140 break;
141 }
142 }
143
processWord(std::string & word)144 void StyleSheetParser::processWord(std::string &word) {
145 while (!word.empty()) {
146 int index = word.find(myInsideComment ? "*/" : "/*");
147 if (!myInsideComment) {
148 if (index == -1) {
149 processWordWithoutComments(word);
150 } else if (index > 0) {
151 processWordWithoutComments(word.substr(0, index));
152 }
153 }
154 if (index == -1) {
155 break;
156 }
157 myInsideComment = !myInsideComment;
158 word.erase(0, index + 2);
159 }
160 }
161
processWordWithoutComments(const std::string & word)162 void StyleSheetParser::processWordWithoutComments(const std::string &word) {
163 switch (myReadState) {
164 case TAG_NAME:
165 {
166 int index = word.find('.');
167 if (index == -1) {
168 if (myTagName.empty()) {
169 myTagName = word;
170 } else {
171 myTagName += ' ' + word;
172 }
173 } else {
174 if (myTagName.empty()) {
175 myTagName = word.substr(0, index);
176 myClassName = word.substr(index + 1);
177 } else {
178 myTagName += ' ' + word.substr(0, index);
179 myClassName += ' ' + word.substr(index + 1);
180 }
181 }
182 myMap.clear();
183 break;
184 }
185 case ATTRIBUTE_NAME:
186 myAttributeName = word;
187 myMap[myAttributeName].clear();
188 break;
189 case ATTRIBUTE_VALUE:
190 myMap[myAttributeName].push_back(word);
191 break;
192 case BROKEN:
193 break;
194 }
195 }
196