Commit 1467ab53 authored by Volker Krause's avatar Volker Krause
Browse files

Add basic bit layout for ERA SSB v2 tickets

This is (mostly) what Trenitalia is using, although in the second half
this isn't matching their content it seems. Even if that turns out to not
be a bug in our code this is already worth it, as this manages to properly
decode international destination codes, unlike our previous code.
parent 3b66eae3
Pipeline #61319 passed with stages
in 12 minutes and 23 seconds
......@@ -34,6 +34,7 @@ set(kitinerary_lib_srcs
era/ssbticketbase.cpp
era/ssbv1ticket.cpp
era/ssbv2ticket.cpp
era/ssbv3ticket.cpp
extractors/iatabcbpextractor.cpp
......
/*
SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "ssbv2ticket.h"
#include <QDebug>
using namespace KItinerary;
enum {
SSB_DATA_SIZE_MIN = 67,
SSB_DATA_SIZE_MAX = 114,
SSB_VERSION = 2,
};
SSBv2Ticket::SSBv2Ticket() = default;
SSBv2Ticket::SSBv2Ticket(const QByteArray &data)
{
if (maybeSSB(data)) {
m_data = data;
} else {
qWarning() << "Trying to construct an SSB ticket from invalid data!";
}
}
SSBv2Ticket::~SSBv2Ticket() = default;
bool SSBv2Ticket::isValid() const
{
return !m_data.isEmpty();
}
bool SSBv2Ticket::maybeSSB(const QByteArray& data)
{
if (data.size() < SSB_DATA_SIZE_MIN || data.size() > SSB_DATA_SIZE_MAX) {
return false;
}
return (data.at(0) >> 4) == SSB_VERSION;
}
QByteArray SSBv2Ticket::rawData() const
{
return m_data;
}
/*
SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#ifndef KITINERARY_SSBV2TICKET_H
#define KITINERARY_SSBV2TICKET_H
#include "kitinerary_export.h"
#include "ssbticketbase.h"
#include <QMetaType>
namespace KItinerary {
/** ERA SSB ticket barcode (version 2).
* @see ERA TAP TSI TD B.12 - §15 Appendix B - SSB - old version
*/
class KITINERARY_EXPORT SSBv2Ticket : protected SSBTicketBase
{
Q_GADGET
SSB_NUM_PROPERTY(version, 0, 4)
SSB_NUM_PROPERTY(issuerCode, 4, 14)
SSB_NUM_PROPERTY(publicKeyVersion, 18, 4)
SSB_NUM_PROPERTY(rct2TypeIndicator, 22, 1)
SSB_NUM_PROPERTY(numberOfTickets, 23, 6)
SSB_NUM_PROPERTY(numberOfAdultPassengers, 29, 7)
SSB_NUM_PROPERTY(numberOfChildPassengers, 36, 7)
SSB_NUM_PROPERTY(firstDayOfValidity, 43, 9)
SSB_NUM_PROPERTY(lastDayOfValidity, 52, 9)
SSB_NUM_PROPERTY(customerNumberType, 61, 1)
SSB_LONG_PROPERTY(customerNumber, 62, 47)
SSB_NUM_PROPERTY(departureStationType, 109, 1)
SSB_NUM_PROPERTY(departureStationNum, 110, 30)
SSB_STR_PROPERTY(departureStationAlpha, 110, 5)
SSB_NUM_PROPERTY(arrivalStationType, 140, 1)
SSB_NUM_PROPERTY(arrivalStationNum, 141, 30)
SSB_STR_PROPERTY(arrivalStationAlpha, 141, 5)
SSB_NUM_PROPERTY(departureTime, 171, 6)
SSB_NUM_PROPERTY(trainNumber, 177, 25) // alpha 5 encoding??
SSB_LONG_PROPERTY(reservationReference, 202, 40)
SSB_NUM_PROPERTY(classOfTransport, 242, 6)
SSB_NUM_PROPERTY(coachNumber, 248, 10)
SSB_NUM_PROPERTY(seatNumber, 258, 7) // 250 in trenitalia??
SSB_STR_PROPERTY(berthNumber, 265, 1)
SSB_NUM_PROPERTY(overbookingIndicator, 211, 1)
SSB_STR_PROPERTY(issuerPNRNumber, 272, 7)
SSB_NUM_PROPERTY(ticketType, 314, 4)
SSB_NUM_PROPERTY(specimen, 318, 1)
SSB_STR_PROPERTY(viaStations, 319, 5) // is that the correct encoding? page 131 of TAP TSI Annex B.6 could also be read as 6 times 5 bit content
SSB_NUM_PROPERTY(railwayCarrierCode, 349, 14)
SSB_STR_PROPERTY(reference, 363, 8)
Q_PROPERTY(QByteArray rawData READ rawData)
public:
SSBv2Ticket();
explicit SSBv2Ticket(const QByteArray &data);
~SSBv2Ticket();
/** Returns @c true if this is a valid SSB ticket. */
bool isValid() const;
/** Raw barcode data. */
QByteArray rawData() const;
/** Returns @c true if @p data might be an ERA SSB ticket. */
static bool maybeSSB(const QByteArray &data);
};
}
Q_DECLARE_METATYPE(KItinerary::SSBv2Ticket)
#endif // KITINERARY_SSBV2TICKET_H
......@@ -5,6 +5,7 @@
*/
#include "../lib/era/ssbv1ticket.h"
#include "../lib/era/ssbv2ticket.h"
#include "../lib/era/ssbv3ticket.h"
#include "../lib/uic9183/uic9183head.h"
#include "../lib/uic9183/uic9183header.h"
......@@ -68,6 +69,29 @@ static void dumpSsbv3Ticket(const QByteArray &data)
}
}
static void dumpSsbv2Ticket(const QByteArray &data)
{
SSBv2Ticket ticket(data);
for (auto i = 0; i < SSBv2Ticket::staticMetaObject.propertyCount(); ++i) {
const auto prop = SSBv2Ticket::staticMetaObject.property(i);
const auto value = prop.readOnGadget(&ticket);
switch (value.type()) {
case QVariant::Int:
std::cout << prop.name() << ": " << value.toInt() << std::endl;
break;
case QVariant::ByteArray:
if (std::strcmp(prop.name(), "rawData") == 0) {
break;
}
[[fallthrough]];
default:
std::cout << prop.name() << ": " << qPrintable(value.toString()) << std::endl;
break;
}
}
}
static void dumpSsbv1Ticket(const QByteArray &data)
{
SSBv1Ticket ticket(data);
......@@ -280,6 +304,9 @@ int main(int argc, char **argv)
} else if (SSBv3Ticket::maybeSSB(data)) {
std::cout << "ERA SSB Ticket" << std::endl;
dumpSsbv3Ticket(data);
} else if (SSBv2Ticket::maybeSSB(data)) {
std::cout << "ERA SSB Ticket" << std::endl;
dumpSsbv2Ticket(data);
} else if (SSBv1Ticket::maybeSSB(data)) {
std::cout << "ERA SSB Ticket" << std::endl;
dumpSsbv1Ticket(data);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment