File indexing completed on 2024-05-19 05:57:13

0001 /*
0002     SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
0003     SPDX-License-Identifier: LGPL-2.0-or-later
0004 */
0005 
0006 #include "mecardparser.h"
0007 
0008 #include <QDebug>
0009 
0010 MeCardParser::MeCardParser() = default;
0011 MeCardParser::~MeCardParser() = default;
0012 
0013 bool MeCardParser::Element::operator<(QStringView other) const
0014 {
0015     return key < other;
0016 }
0017 
0018 bool MeCardParser::parse(const QString &data)
0019 {
0020     m_header = {};
0021     m_elements.clear();
0022     m_data = data;
0023 
0024     const auto idx = data.indexOf(QLatin1Char(':'));
0025     if (idx <= 0 || idx >= data.size() - 1) {
0026         return false;
0027     }
0028     m_header = QStringView(data).left(idx);
0029 
0030     auto remaining = QStringView(data).mid(idx + 1);
0031     while (remaining.size() > 0) {
0032         const auto keyIdx = remaining.indexOf(QLatin1Char(':'));
0033         if (keyIdx <= 0 || keyIdx + 2 >= remaining.size()) {
0034             break;
0035         }
0036 
0037         QString value;
0038         auto elemIdx = keyIdx + 1;
0039         bool inQuote = false;
0040         for (; elemIdx < remaining.size() - 1; ++elemIdx) {
0041             auto c = remaining.at(elemIdx);
0042             if (elemIdx == (keyIdx + 1) && c == QLatin1Char('"')) { // leading quote
0043                 inQuote = true;
0044                 continue;
0045             }
0046             if (inQuote && c == QLatin1Char('"') && remaining.at(elemIdx + 1) == QLatin1Char(';')) { // trailing quote
0047                 break;
0048             }
0049             if (c == QLatin1Char(';')) { // end of element
0050                 break;
0051             }
0052             if (c == QLatin1Char('\\')) { // quoted character
0053                 ++elemIdx;
0054                 c = remaining.at(elemIdx);
0055             }
0056             value.push_back(c);
0057         }
0058 
0059         const auto key = remaining.left(keyIdx);
0060         auto it = std::lower_bound(m_elements.begin(), m_elements.end(), key);
0061         if (it == m_elements.end()) {
0062             m_elements.push_back(Element());
0063             it = std::prev(m_elements.end());
0064         } else if ((*it).key != key) {
0065             it = m_elements.insert(it, Element());
0066         }
0067         (*it).key = key;
0068         (*it).values.push_back(value);
0069 
0070         remaining = remaining.mid(elemIdx + 1);
0071     }
0072 
0073     return !m_elements.empty();
0074 }
0075 
0076 QStringView MeCardParser::header() const
0077 {
0078     return m_header;
0079 }
0080 
0081 QString MeCardParser::value(QStringView key) const
0082 {
0083     const auto it = std::lower_bound(m_elements.begin(), m_elements.end(), key);
0084     if (it != m_elements.end() && (*it).key == key && (*it).values.size() == 1) {
0085         return (*it).values.at(0);
0086     }
0087     return {};
0088 }
0089 
0090 QStringList MeCardParser::values(QStringView key) const
0091 {
0092     const auto it = std::lower_bound(m_elements.begin(), m_elements.end(), key);
0093     if (it != m_elements.end() && (*it).key == key) {
0094         return (*it).values;
0095     }
0096     return {};
0097 }