File indexing completed on 2024-11-24 04:45:11

0001 /*
0002     SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "iatabcbp.h"
0008 #include "iatabcbpconstants_p.h"
0009 #include "logging.h"
0010 
0011 #include <QScopeGuard>
0012 
0013 #include <cctype>
0014 
0015 using namespace KItinerary;
0016 using namespace KItinerary::IataBcbpConstants;
0017 
0018 IataBcbp::IataBcbp() = default;
0019 
0020 IataBcbp::IataBcbp(const QString& data)
0021 {
0022     if (data.size() < MinimumViableSize || data[0] != QLatin1Char('M') || !data[1].isDigit()) {
0023         return;
0024     }
0025     const auto trimmed = QStringView(data).trimmed(); // tolerance against e.g. trailing newlines
0026     if (std::any_of(trimmed.begin(), trimmed.end(), [](QChar c) { return c.row() != 0 || !c.isPrint(); })) {
0027         return;
0028     }
0029     m_data = data;
0030     auto resetOnInvalid = qScopeGuard([this] { m_data.clear(); });
0031 
0032     if (!uniqueMandatorySection().isValid()) {
0033         return;
0034     }
0035     if (hasUniqueConditionalSection() && !uniqueConditionalSection().isValid()) {
0036         return;
0037     }
0038 
0039     const auto legCount = uniqueMandatorySection().numberOfLegs();
0040     int offset = UniqueMandatorySize;
0041     for (int i = 0; i < legCount; ++i) {
0042         if (offset > m_data.size()) {
0043             return;
0044         }
0045         auto rms = IataBcbpRepeatedMandatorySection(QStringView(m_data).mid(offset));
0046         if (!rms.isValid()) {
0047             return;
0048         }
0049         offset += rms.variableFieldSize() + RepeatedMandatorySize;
0050     }
0051 
0052     resetOnInvalid.dismiss();
0053 }
0054 
0055 IataBcbp::~IataBcbp() = default;
0056 
0057 bool IataBcbp::isValid() const
0058 {
0059     return !m_data.isEmpty();
0060 }
0061 
0062 IataBcbpUniqueMandatorySection IataBcbp::uniqueMandatorySection() const
0063 {
0064     return IataBcbpUniqueMandatorySection(QStringView(m_data).left(UniqueMandatorySize));
0065 }
0066 
0067 bool IataBcbp::hasUniqueConditionalSection() const
0068 {
0069     return (m_data.size() > (UniqueMandatorySize + RepeatedMandatorySize))
0070         && (m_data.at(UniqueMandatorySize + RepeatedMandatorySize) == QLatin1Char('>'))
0071         && repeatedMandatorySection(0).variableFieldSize() > MinimumUniqueConditionalSize;
0072 }
0073 
0074 IataBcbpUniqueConditionalSection IataBcbp::uniqueConditionalSection() const
0075 {
0076     if (hasUniqueConditionalSection()) {
0077         return IataBcbpUniqueConditionalSection(QStringView(m_data).mid(UniqueMandatorySize + RepeatedMandatorySize));
0078     }
0079     return IataBcbpUniqueConditionalSection(QStringView());
0080 }
0081 
0082 IataBcbpRepeatedMandatorySection IataBcbp::repeatedMandatorySection(int leg) const
0083 {
0084     int offset = UniqueMandatorySize;
0085     for (auto i = 0; i < leg; ++i) {
0086         offset += RepeatedMandatorySize + IataBcbpRepeatedMandatorySection(QStringView(m_data).mid(offset)).variableFieldSize();
0087     }
0088     return IataBcbpRepeatedMandatorySection(QStringView(m_data).mid(offset, RepeatedMandatorySize));
0089 }
0090 
0091 IataBcbpRepeatedConditionalSection IataBcbp::repeatedConditionalSection(int leg) const
0092 {
0093     int offset = UniqueMandatorySize;
0094     if (leg == 0 && hasUniqueConditionalSection()) {
0095         offset += uniqueConditionalSection().fieldSize() + MinimumUniqueConditionalSize;
0096     }
0097     for (auto i = 0; i < leg; ++i) {
0098         offset += RepeatedMandatorySize + IataBcbpRepeatedMandatorySection(QStringView(m_data).mid(offset)).variableFieldSize();
0099     }
0100     return IataBcbpRepeatedConditionalSection(QStringView(m_data).mid(offset + RepeatedMandatorySize));
0101 }
0102 
0103 QString IataBcbp::airlineUseSection(int leg) const
0104 {
0105     int offset = UniqueMandatorySize;
0106     for (auto i = 0; i < leg; ++i) {
0107         offset += RepeatedMandatorySize + IataBcbpRepeatedMandatorySection(QStringView(m_data).mid(offset)).variableFieldSize();
0108     }
0109     auto length = IataBcbpRepeatedMandatorySection(QStringView(m_data).mid(offset)).variableFieldSize();
0110     if (leg == 0 && hasUniqueConditionalSection()) {
0111         const auto s = uniqueConditionalSection().fieldSize() + MinimumUniqueConditionalSize;
0112         offset += uniqueConditionalSection().fieldSize() + MinimumUniqueConditionalSize;
0113         length -= s;
0114     }
0115     if (leg == 0 && !hasUniqueConditionalSection()) { // Easyjet special case that has a airline use section right after the mandatory block
0116         return m_data.mid(offset + RepeatedMandatorySize, length);
0117     }
0118     const auto offset2 = IataBcbpRepeatedConditionalSection(QStringView(m_data).mid(offset + RepeatedMandatorySize)).conditionalFieldSize() + 2 + RepeatedMandatorySize;
0119     return m_data.mid(offset + offset2, length - offset2 + RepeatedMandatorySize);
0120 }
0121 
0122 bool IataBcbp::hasSecuritySection() const
0123 {
0124     int offset = UniqueMandatorySize;
0125     for (auto i = 0; i < uniqueMandatorySection().numberOfLegs(); ++i) {
0126         offset += RepeatedMandatorySize + IataBcbpRepeatedMandatorySection(QStringView(m_data).mid(offset)).variableFieldSize();
0127     }
0128     return offset < m_data.size() && m_data[offset] == QLatin1Char('^');
0129 }
0130 
0131 IataBcbpSecuritySection IataBcbp::securitySection() const
0132 {
0133     int offset = UniqueMandatorySize;
0134     for (auto i = 0; i < uniqueMandatorySection().numberOfLegs(); ++i) {
0135         offset += RepeatedMandatorySize + IataBcbpRepeatedMandatorySection(QStringView(m_data).mid(offset)).variableFieldSize();
0136     }
0137     return IataBcbpSecuritySection(QStringView(m_data).mid(offset));
0138 }
0139 
0140 QString IataBcbp::rawData() const
0141 {
0142     return m_data;
0143 }
0144 
0145 bool IataBcbp::maybeIataBcbp(const QByteArray &data)
0146 {
0147     return data.size() >= MinimumViableSize && data[0] == 'M' && std::isdigit(data[1]);
0148 }
0149 
0150 bool IataBcbp::maybeIataBcbp(const QString &data)
0151 {
0152     return data.size() >= MinimumViableSize && data[0] == QLatin1Char('M') && data[1].isDigit();
0153 }
0154 
0155 #include "moc_iatabcbp.cpp"