/* * Copyright (C) 2004-2012 Geometer Plus * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include #include #include #include #include #include "StyleSheetParser.h" StyleSheetTableParser::StyleSheetTableParser(StyleSheetTable &table) : myTable(table) { //ZLLogger::Instance().registerClass("CSS"); } void StyleSheetTableParser::storeData(const std::string &tagName, const std::string &className, const StyleSheetTable::AttributeMap &map) { myTable.addMap(tagName, className, map); } shared_ptr StyleSheetSingleStyleParser::parseString(const char *text) { myReadState = ATTRIBUTE_NAME; parse(text, strlen(text), true); shared_ptr control = StyleSheetTable::createControl(myMap); reset(); return control; } StyleSheetParser::StyleSheetParser() : myReadState(TAG_NAME), myInsideComment(false) { } StyleSheetParser::~StyleSheetParser() { } void StyleSheetParser::reset() { myWord.erase(); myAttributeName.erase(); myReadState = TAG_NAME; myInsideComment = false; myTagName.erase(); myClassName.erase(); myMap.clear(); } void StyleSheetParser::parse(ZLInputStream &stream) { if (stream.open()) { char *buffer = new char[1024]; while (true) { int len = stream.read(buffer, 1024); if (len == 0) { break; } parse(buffer, len); } delete[] buffer; stream.close(); } } void StyleSheetParser::parse(const char *text, int len, bool final) { const char *start = text; const char *end = text + len; for (const char *ptr = start; ptr != end; ++ptr) { if (isspace(*ptr)) { if (start != ptr) { myWord.append(start, ptr - start); } processWord(myWord); myWord.erase(); start = ptr + 1; } else if (isControlSymbol(*ptr)) { if (start != ptr) { myWord.append(start, ptr - start); } processWord(myWord); myWord.erase(); processControl(*ptr); start = ptr + 1; } } if (start < end) { myWord.append(start, end - start); if (final) { processWord(myWord); myWord.erase(); } } } bool StyleSheetParser::isControlSymbol(const char symbol) { switch (symbol) { case '{': case '}': case ';': case ':': return true; default: return false; } } void StyleSheetParser::storeData(const std::string&, const std::string&, const StyleSheetTable::AttributeMap&) { } void StyleSheetParser::processControl(const char control) { switch (control) { case '{': myReadState = (myReadState == TAG_NAME) ? ATTRIBUTE_NAME : BROKEN; break; case '}': if (myReadState != BROKEN) { storeData(myTagName, myClassName, myMap); } myReadState = TAG_NAME; myTagName.erase(); myClassName.erase(); myMap.clear(); break; case ';': myReadState = ((myReadState == ATTRIBUTE_VALUE) || (myReadState == ATTRIBUTE_NAME)) ? ATTRIBUTE_NAME : BROKEN; break; case ':': myReadState = (myReadState == ATTRIBUTE_NAME) ? ATTRIBUTE_VALUE : BROKEN; break; } } void StyleSheetParser::processWord(std::string &word) { while (!word.empty()) { int index = word.find(myInsideComment ? "*/" : "/*"); if (!myInsideComment) { if (index == -1) { processWordWithoutComments(word); } else if (index > 0) { processWordWithoutComments(word.substr(0, index)); } } if (index == -1) { break; } myInsideComment = !myInsideComment; word.erase(0, index + 2); } } void StyleSheetParser::processWordWithoutComments(const std::string &word) { switch (myReadState) { case TAG_NAME: { int index = word.find('.'); if (index == -1) { if (myTagName.empty()) { myTagName = word; } else { myTagName += ' ' + word; } } else { if (myTagName.empty()) { myTagName = word.substr(0, index); myClassName = word.substr(index + 1); } else { myTagName += ' ' + word.substr(0, index); myClassName += ' ' + word.substr(index + 1); } } myMap.clear(); break; } case ATTRIBUTE_NAME: myAttributeName = word; myMap[myAttributeName].clear(); break; case ATTRIBUTE_VALUE: { const size_t l = word.length(); if (l >= 2 && (word[0] == '"' || word[0] == '\'') && word[0] == word[l - 1]) { myMap[myAttributeName].push_back(word.substr(1, l - 2)); } else { myMap[myAttributeName].push_back(word); } break; } case BROKEN: break; } }