File indexing completed on 2024-11-17 04:17:27
0001 /* 0002 SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "mapcssparser.h" 0008 #include "mapcssparser_p.h" 0009 #include "logging.h" 0010 0011 #include "mapcssparser_impl.h" 0012 #include "mapcssdeclaration_p.h" 0013 #include "mapcssrule_p.h" 0014 #include "mapcssscanner.h" 0015 #include "mapcssstyle.h" 0016 #include "mapcssstyle_p.h" 0017 0018 #include <QDebug> 0019 #include <QFile> 0020 #include <QFileInfo> 0021 #include <QScopeGuard> 0022 0023 #include <cstring> 0024 0025 char* unquoteString(const char *str) 0026 { 0027 const auto size = strlen(str) - 2; 0028 if (size <= 0) { 0029 return nullptr; 0030 } 0031 auto out = (char*)malloc(size + 1); 0032 memset(out, 0, size + 1); 0033 auto outIt = out; 0034 for (auto it = str + 1; it < str + size + 1; ++it, ++outIt) { 0035 if (*it == '\\') { 0036 ++it; 0037 switch (*it) { 0038 case '\\': 0039 case '"': 0040 *outIt = *it; break; 0041 case 'n': 0042 *outIt = '\n'; break; 0043 case 't': 0044 *outIt = '\t'; break; 0045 default: 0046 *outIt++ = '\\'; 0047 *outIt = *it; 0048 } 0049 } else { 0050 *outIt = *it; 0051 } 0052 } 0053 return out; 0054 } 0055 0056 using namespace KOSMIndoorMap; 0057 0058 MapCSSParser::MapCSSParser() 0059 : d(new MapCSSParserPrivate) 0060 { 0061 } 0062 0063 MapCSSParser::~MapCSSParser() = default; 0064 0065 bool MapCSSParser::hasError() const 0066 { 0067 return d->m_error; 0068 } 0069 0070 QString MapCSSParser::fileName() const 0071 { 0072 return d->m_currentFileName; 0073 } 0074 0075 QString MapCSSParser::errorMessage() const 0076 { 0077 if (!d->m_error) { 0078 return {}; 0079 } 0080 0081 return d->m_errorMsg + QLatin1String(": ") + fileName() + QLatin1Char(':') + QString::number(d->m_line) + QLatin1Char(':') + QString::number(d->m_column); 0082 } 0083 0084 MapCSSStyle MapCSSParser::parse(const QString &fileName) 0085 { 0086 d->m_error = true; 0087 0088 MapCSSStyle style; 0089 d->parse(&style, fileName, {}); 0090 if (d->m_error) { 0091 return MapCSSStyle(); 0092 } 0093 0094 return style; 0095 } 0096 0097 void MapCSSParserPrivate::parse(MapCSSStyle *style, const QString &fileName, ClassSelectorKey importClass) 0098 { 0099 QFile f(fileName); 0100 if (!f.open(QFile::ReadOnly)) { 0101 qCWarning(Log) << f.fileName() << f.errorString(); 0102 m_error = true; 0103 m_errorMsg = f.errorString(); 0104 return; 0105 } 0106 m_currentFileName = fileName; 0107 m_currentStyle = style; 0108 m_importClass = importClass; 0109 0110 yyscan_t scanner; 0111 if (yylex_init(&scanner)) { 0112 return; 0113 } 0114 const auto lexerCleanup = qScopeGuard([&scanner]{ yylex_destroy(scanner); }); 0115 0116 const auto b = f.readAll(); 0117 YY_BUFFER_STATE state; 0118 state = yy_scan_string(b.constData(), scanner); 0119 if (yyparse(this, scanner)) { 0120 m_error = true; 0121 return; 0122 } 0123 0124 yy_delete_buffer(state, scanner); 0125 0126 m_error = false; 0127 m_currentStyle = nullptr; 0128 m_importClass = {}; 0129 } 0130 0131 bool MapCSSParserPrivate::addImport(char* fileName, ClassSelectorKey importClass) 0132 { 0133 auto cssFile = QString::fromUtf8(fileName); 0134 free(fileName); 0135 0136 if (QFileInfo(cssFile).isRelative()) { 0137 cssFile = QFileInfo(m_currentFileName).absolutePath() + QLatin1Char('/') + cssFile; 0138 } 0139 0140 MapCSSParser p; 0141 p.d->parse(m_currentStyle, cssFile, importClass); 0142 if (p.hasError()) { 0143 m_error = p.d->m_error; 0144 m_errorMsg = p.errorMessage(); 0145 } 0146 return !p.hasError(); 0147 } 0148 0149 void MapCSSParserPrivate::addRule(MapCSSRule *rule) 0150 { 0151 if (!m_importClass.isNull()) { 0152 auto decl = new MapCSSDeclaration(MapCSSDeclaration::ClassDeclaration); 0153 decl->setClassSelectorKey(m_importClass); 0154 rule->addDeclaration(decl); 0155 } 0156 MapCSSStylePrivate::get(m_currentStyle)->m_rules.push_back(std::unique_ptr<MapCSSRule>(rule)); 0157 } 0158 0159 void MapCSSParserPrivate::setError(const QString &msg, int line, int column) 0160 { 0161 m_error = true; 0162 m_errorMsg = msg; 0163 m_line = line; 0164 m_column = column; 0165 } 0166 0167 ClassSelectorKey MapCSSParserPrivate::makeClassSelector(const char *str, std::size_t len) const 0168 { 0169 return MapCSSStylePrivate::get(m_currentStyle)->m_classSelectorRegistry.makeKey(str, len, OSM::StringMemory::Transient); 0170 } 0171 0172 LayerSelectorKey MapCSSParserPrivate::makeLayerSelector(const char *str, std::size_t len) const 0173 { 0174 if (!str || std::strcmp(str, "default") == 0) { 0175 return {}; 0176 } 0177 return MapCSSStylePrivate::get(m_currentStyle)->m_layerSelectorRegistry.makeKey(str, len, OSM::StringMemory::Transient); 0178 }