KItinerary

vendor0080block.cpp
1/*
2 SPDX-FileCopyrightText: 2019 Volker Krause <vkrause@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "vendor0080block.h"
8#include "vendor0080vublockdata.h"
9#include "uic9183utils.h"
10#include "logging.h"
11
12#include <QString>
13
14using namespace KItinerary;
15
16enum {
17 SBlockFirstByte = 'S',
18 SBlockTypeOffset = 1,
19 SBlockLengthOffset = 4,
20 SBlockLengthSize = 4,
21 SBlockHeaderSize = 8
22};
23
24// 0080BL vendor block sub-block ("S block")
25// 1x 'S'
26// 3x field type
27// 4x field value length
28// nx field value
29
30// S001: price model (textual)
31// S002: product class (numeric: 0 = C, 1 = B, 2 = A)
32// S003: product class outbound (A, B, or C)
33// S004: produce class return
34// S009: [num adults]-[num adults with Bahncard]-[Bahncard type] (49 = BC25, 19,78 = BC50)
35// S012: number of children
36// S014: S[class of travel]
37// S015: departure station name (outbound)
38// S016: arrival station name (outbound)
39// S017: departure station name (return)
40// S018: arrival station name (return)
41// S019, S020: Rail&Fly specific
42// S021: via
43// S023: traveler name
44// S026: price type (numeric) (12 = Normalpreis, 13 = Sparpreis, 3 = Rail&Fly)
45// S027: id number (no longer used)
46// S028: [given name]#[family name]
47// S031: first day of validity, dd.MM.yyyy
48// S032: last day of validity, dd.MM.yyyy
49// S035: departure station IBNR without country prefix (outbound)
50// S036: arrival station IBNR without country prefix (outbound)
51// S040: number of persons?
52// S041: number of tickets?
53
54Vendor0080BLSubBlock::Vendor0080BLSubBlock() = default;
55
56Vendor0080BLSubBlock::Vendor0080BLSubBlock(const Uic9183Block &block, int offset)
57 : m_offset(offset)
58{
59 if (block.isNull()) {
60 return;
61 }
62
63 if (block.contentSize() < offset + SBlockHeaderSize) {
64 qCWarning(Log) << "0080BL S-block too small";
65 return;
66 }
67 if (*(block.content() + offset) != SBlockFirstByte) {
68 qCWarning(Log) << "0080BL invalid S-block header";
69 return;
70 }
71
72 m_block = block;
73 if (block.contentSize() < offset + size()) {
74 qCWarning(Log) << "0080BL S-block size exceeds 0080BL block size";
75 m_block = {};
76 }
77}
78
79bool Vendor0080BLSubBlock::isNull() const
80{
81 return m_block.isNull();
82}
83
85{
86 return contentSize() + SBlockHeaderSize;
87}
88
90{
91 if (m_offset + size() >= m_block.contentSize()) { // we are the last block
92 return {};
93 }
94 return Vendor0080BLSubBlock(m_block, m_offset + size());
95}
96
98{
99 if (isNull()) {
100 return 0;
101 }
102 return Uic9183Utils::readAsciiEncodedNumber(m_block.content(), m_block.size(), m_offset + SBlockLengthOffset, SBlockLengthSize);
103}
104
105const char* Vendor0080BLSubBlock::id() const
106{
107 if (isNull()) {
108 return nullptr;
109 }
110 return m_block.content() + m_offset + SBlockTypeOffset;
111}
112
113const char* Vendor0080BLSubBlock::content() const
114{
115 if (isNull()) {
116 return nullptr;
117 }
118 return m_block.content() + m_offset + SBlockHeaderSize;
119}
120
122{
123 if (isNull()) {
124 return {};
125 }
126 return QString::fromUtf8(content(), contentSize());
127}
128
129
130Vendor0080BLOrderBlock::Vendor0080BLOrderBlock() = default;
131Vendor0080BLOrderBlock::Vendor0080BLOrderBlock(const Uic9183Block &block, int offset)
132 : m_block(block)
133 , m_offset(offset)
134{
135}
136
137bool Vendor0080BLOrderBlock::isNull() const
138{
139 return m_block.isNull();
140}
141
142QDate Vendor0080BLOrderBlock::validFrom() const
143{
144 switch (m_block.version()) {
145 case 2:
146 return QDate::fromString(Uic9183Utils::readUtf8String(m_block, m_offset + 22, 8), QStringLiteral("ddMMyyyy"));
147 case 3:
148 return QDate::fromString(Uic9183Utils::readUtf8String(m_block, m_offset, 8), QStringLiteral("ddMMyyyy"));
149 }
150 return {};
151}
152
153QDate Vendor0080BLOrderBlock::validTo() const
154{
155 switch (m_block.version()) {
156 case 2:
157 return QDate::fromString(Uic9183Utils::readUtf8String(m_block, m_offset + 22 + 8, 8), QStringLiteral("ddMMyyyy"));
158 case 3:
159 return QDate::fromString(Uic9183Utils::readUtf8String(m_block, m_offset + 8, 8), QStringLiteral("ddMMyyyy"));
160 }
161 return {};
162}
163
164QString Vendor0080BLOrderBlock::serialNumber() const
165{
166 switch (m_block.version()) {
167 case 2:
168 return Uic9183Utils::readUtf8String(m_block, m_offset + 22 + 8 + 8, 8);
169 case 3:
170 return Uic9183Utils::readUtf8String(m_block, m_offset + 8 + 8, 10);
171 }
172 return {};
173}
174
175// 0080BL vendor block (DB) (version 2/3, dynamic size)
176// 2x stuff
177// 1x number of certificate blocks
178// 22+8+8+8x (v2) or 8+8+10x (v3) certificate block
179// 2x number of sub blocks
180
181Vendor0080BLBlock::Vendor0080BLBlock(const Uic9183Block &block)
182{
183 if (block.isNull()) {
184 return;
185 }
186 if (block.version() != 2 && block.version() != 3) {
187 qCWarning(Log) << "Unsupported version of 0080BL vendor block." << block.version();
188 return;
189 }
190 if (block.isNull() || block.contentSize() < 3 || subblockOffset(block) > block.size()) {
191 return;
192 }
193 m_block = block;
194}
195
196bool Vendor0080BLBlock::isValid() const
197{
198 return !m_block.isNull();
199}
200
201int Vendor0080BLBlock::orderBlockCount() const
202{
203 return Uic9183Utils::readAsciiEncodedNumber(m_block, 2, 1);
204}
205
207{
208 if (i >= 0 && i < orderBlockCount()) {
209 switch (m_block.version()) {
210 case 2: return Vendor0080BLOrderBlock(m_block, 3 + i * (22 + 8 + 8 + 8));
211 case 3: return Vendor0080BLOrderBlock(m_block, 3 + i * (8 + 8 + 10));
212 }
213 }
214 return {};
215}
216
218{
219 return Vendor0080BLSubBlock(m_block, subblockOffset(m_block));
220}
221
223{
224 auto sblock = firstBlock();
225 while (!sblock.isNull()) {
226 if (strncmp(sblock.id(), id, 3) == 0) {
227 return sblock;
228 }
229 sblock = sblock.nextBlock();
230 }
231 return {};
232}
233
235{
236 if (str.size() != 3 || !isValid()) {
237 return {};
238 }
239 const auto b = findSubBlock(str.toUtf8().constData());
240 return b.isNull() ? QVariant() : QVariant::fromValue(b);
241}
242
243int Vendor0080BLBlock::subblockOffset(const Uic9183Block& block)
244{
245 const auto certCount = *(block.content() + 2) - '0';
246 const auto certSize = block.version() == 2 ? 46 : 26;
247 return 3 + certSize * certCount + 2;
248}
249
250
251Vendor0080VUBlock::Vendor0080VUBlock(const Uic9183Block &block)
252{
253 if (block.isNull() || block.contentSize() < (int)sizeof(Vendor0080VUCommonData)) {
254 return;
255 }
256
257 m_block = block;
258}
259
260bool Vendor0080VUBlock::isValid() const
261{
262 return !m_block.isNull();
263}
264
265const Vendor0080VUCommonData* Vendor0080VUBlock::commonData() const
266{
267 return m_block.isNull() ? nullptr : reinterpret_cast<const Vendor0080VUCommonData*>(m_block.content());
268}
269
270const Vendor0080VUTicketData* Vendor0080VUBlock::ticketData(int index) const
271{
272 auto offset = sizeof(Vendor0080VUCommonData);
273 auto ticket = reinterpret_cast<const Vendor0080VUTicketData*>(m_block.content() + offset);
274 while (index-- > 0) {
275 offset += sizeof(Vendor0080VUTicketData) + ticket->validityAreaDataSize - sizeof(VdvTicketValidityAreaData);
276 ticket = reinterpret_cast<const Vendor0080VUTicketData*>(m_block.content() + offset);
277 }
278 return ticket;
279}
280
281#include "moc_vendor0080block.cpp"
A data block from a UIC 918.3 ticket.
int contentSize() const
Returns the size of the content data.
bool isNull() const
Checks if the block is valid or empty/default constructed.
int version() const
Returns the version number of this block.
int size() const
Returns the size of the entire block data.
const char * content() const
Returns the payload data (not including the block header).
Ticket validity area data block.
Q_INVOKABLE KItinerary::Vendor0080BLOrderBlock orderBlock(int i) const
Order block at index i.
Vendor0080BLSubBlock firstBlock() const
First S-block, for iterating.
Vendor0080BLSubBlock findSubBlock(const char id[3]) const
Finds a S-block by type.
UIC 918.3 0080BL vendor data block order block.
UIC 918.3 0080BL vendor data block sub-block.
QString toString() const
Content as Unicode string.
const char * id() const
Type of the S-block.
Vendor0080BLSubBlock nextBlock() const
Next S-block in the 0080BL block.
int size() const
Size of the entire S-block.
int contentSize() const
Size of the content of the S-block.
Classes for reservation/travel data models, data extraction and data augmentation.
Definition berelement.h:17
const char * constData() const const
QDate fromString(QStringView string, QStringView format, QCalendar cal)
QString fromUtf8(QByteArrayView str)
qsizetype size() const const
QByteArray toUtf8() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Dec 6 2024 12:03:24 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.