File indexing completed on 2024-11-24 04:15:37

0001 /*
0002     SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "levelparser_p.h"
0008 #include "logging.h"
0009 
0010 #include <osm/element.h>
0011 
0012 // ### ugly workaround for locale-ignoring string to float conversion
0013 // std::from_chars offers that with C++17, but isn't actually implemented yet for floats/doubles...
0014 #include <private/qlocale_tools_p.h>
0015 
0016 #include <cstdlib>
0017 #include <limits>
0018 
0019 using namespace KOSMIndoorMap;
0020 
0021 // NOTE string to float conversion in here must be done ignoring the locale!
0022 void LevelParser::parse(QByteArray &&level, OSM::Element e, const std::function<void(int, OSM::Element)> &callback)
0023 {
0024     int rangeBegin = std::numeric_limits<int>::max();
0025     int numStartIdx = -1;
0026 
0027     for (int i = 0; i < level.size(); ++i) {
0028         auto &c = level[i];
0029 
0030         if (c == ',') { // fix decimal separator errors
0031             qCDebug(Log) << "syntax error in level tag:" << level << e.url();
0032             c = '.';
0033         }
0034 
0035         if (std::isdigit(static_cast<unsigned char>(c)) || c == '.') {
0036             if (numStartIdx < 0) {
0037                 numStartIdx = i;
0038             }
0039             continue;
0040         }
0041 
0042         if (c == ';') {
0043             const int l = std::round(qstrtod(level.constData() + numStartIdx, nullptr, nullptr) * 10.0); // ### waiting for std::from_chars
0044             if (rangeBegin <= l) {
0045                 for (int j = rangeBegin; j <= l; j += 10) {
0046                     callback(j, e);
0047                 }
0048                 rangeBegin = std::numeric_limits<int>::max();
0049             } else {
0050                 callback(l, e);
0051             }
0052             numStartIdx = -1;
0053             continue;
0054         }
0055 
0056         if (c == QLatin1Char('-')) {
0057             if (numStartIdx < 0) {
0058                 numStartIdx = i;
0059             } else {
0060                 rangeBegin = std::round(qstrtod(level.constData() + numStartIdx, nullptr, nullptr) * 10.0); // ### waiting for std::from_chars
0061                 numStartIdx = -1;
0062             }
0063         }
0064     }
0065 
0066     if (numStartIdx >= level.size() || numStartIdx < 0) {
0067         return;
0068     }
0069     const int l = std::round(qstrtod(level.constData() + numStartIdx, nullptr, nullptr) * 10.0); // ### waiting for std::from_chars
0070     if (rangeBegin <= l) {
0071         for (int j = rangeBegin; j <= l; j += 10) {
0072             callback(j, e);
0073         }
0074     } else {
0075         callback(l, e);
0076     }
0077 }