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"