Commit 576c4fdc authored by Volker Krause's avatar Volker Krause
Browse files

Automatically generate code for decoding uPER sequence headers

This includes parsing of the extension marker if needed as well as the
optional fields bitmap. This removes the last need for dealing with the
optional field bitmap manually.
parent 9c576f71
......@@ -98,3 +98,14 @@ QByteArray UPERDecoder::readIA5String(size_type minLength, size_type maxLength)
}
return readIA5StringData(len);
}
QList<int> UPERDecoder::readSequenceOfConstrainedWholeNumber(int64_t minimum, int64_t maximum)
{
const auto size = readLengthDeterminant();
QList<int> result;
result.reserve(size);
for (size_type i = 0; i < size; ++i) {
result.push_back(readConstrainedWholeNumber(minimum, maximum));
}
return result;
}
......@@ -80,6 +80,7 @@ public:
}
return result;
}
QList<int> readSequenceOfConstrainedWholeNumber(int64_t minimum, int64_t maximum);
/** Read enumerated value.
* @see X.691 §14
......
......@@ -6,6 +6,8 @@
#ifndef KITINERARY_UPERELEMENT_H
#define KITINERARY_UPERELEMENT_H
#include "uperdecoder.h"
namespace KItinerary {
// The property counter thing is based on the approach described here https://woboq.com/blog/verdigris-implementation-tricks.html
......@@ -17,9 +19,17 @@ template <int N = 255> struct num : public num<N - 1> {
template <> struct num<0> { static constexpr int value = 0; };
}
// start of an ASN.1 SEQUENCE definition
#define UPER_GADGET \
Q_GADGET \
static constexpr detail::num<0> _uper_optional_counter(detail::num<0>) { return {}; }
static constexpr detail::num<0> _uper_optional_counter(detail::num<0>) { return {}; } \
static constexpr bool _uper_ExtensionMarker = false;
// same as UPER_GADGET, for SEQUENCES with an extension marker
#define UPER_EXTENDABLE_GADGET \
Q_GADGET \
static constexpr detail::num<0> _uper_optional_counter(detail::num<0>) { return {}; } \
static constexpr bool _uper_ExtensionMarker = true;
#define UPER_ELEMENT(Type, Name) \
public: \
......@@ -54,6 +64,12 @@ public: \
void decode(UPERDecoder &decoder); \
private: \
static constexpr auto _uper_OptionalCount = decltype(_uper_optional_counter(detail::num<>()))::value; \
std::bitset<_uper_OptionalCount> m_optionals;
std::bitset<_uper_OptionalCount> m_optionals; \
inline void decodeSequence(UPERDecoder &decoder) { \
if constexpr (_uper_ExtensionMarker) { \
assert(!decoder.readBoolean()); /* TODO either handle this properly, or switch to an error state. */ \
} \
m_optionals = decoder.readBitset<_uper_OptionalCount>(); \
}
#endif // KITINERARY_UPERELEMENT_H
......@@ -29,6 +29,18 @@
if (Name ## IsSet()) \
Name = decoder.readEnumeratedWithExtensionMarker<decltype(Name)>()
#define FCB_READ_CUSTOM(Name) \
if (Name ## IsSet()) \
Name.decode(decoder);
#define FCB_READ_SEQUENCE_OF_CONTRAINED_INT(Name, Min, Max) \
if (Name ## IsSet()) \
Name = decoder.readSequenceOfConstrainedWholeNumber(Min, Max)
#define FCB_READ_SEQUENCE_OF_CUSTOM(Name) \
if (Name ## IsSet()) \
Name = decoder.readSequenceOf<decltype(Name)::value_type>();
#define FCB_READ_INT_IA5_PAIR(Name, Min, Max) \
FCB_READ_CONSTAINED_INT(Name ## Num, Min, Max); \
FCB_READ_IA5STRING(Name ## IA5)
......@@ -39,10 +51,16 @@
using namespace KItinerary;
void Fcb::ExtensionData::decode(KItinerary::UPERDecoder &decoder)
{
decodeSequence(decoder);
extensionId = decoder.readIA5String();
// extensionData = TODO
}
void Fcb::IssuingData::decode(UPERDecoder &decoder)
{
assert(!decoder.readBoolean()); // TODO extension marker
m_optionals = decoder.readBitset<14>();
decodeSequence(decoder);
FCB_READ_INT_IA5_PAIR(securityProvider, 1, 32000);
FCB_READ_INT_IA5_PAIR(issuer, 1, 32000);
issuingYear = decoder.readConstrainedWholeNumber(2016, 2269);
......@@ -57,7 +75,7 @@ void Fcb::IssuingData::decode(UPERDecoder &decoder)
}
FCB_READ_CONSTAINED_INT(currencyFract, 1, 3);
FCB_READ_IA5STRING(issuerPNR);
assert(!m_optionals[4]); // TODO ExtensionData
FCB_READ_CUSTOM(extension);
FCB_READ_INT_IA5_PAIR_UNCONSTRAINED(issuedOnTrain);
FCB_READ_UNCONSTRAINED_INT(issuedOnLine);
assert(!m_optionals[0]); // TODO GeoCoordinateType
......@@ -65,9 +83,7 @@ void Fcb::IssuingData::decode(UPERDecoder &decoder)
void Fcb::TravelerType::decode(UPERDecoder &decoder)
{
assert(!decoder.readBoolean()); // TODO extension marker
m_optionals = decoder.readBitset<17>();
decodeSequence(decoder);
FCB_READ_UTF8STRING(firstName);
FCB_READ_UTF8STRING(secondName);
FCB_READ_UTF8STRING(lastName);
......@@ -92,12 +108,8 @@ void Fcb::TravelerType::decode(UPERDecoder &decoder)
void Fcb::TravelerData::decode(UPERDecoder &decoder)
{
assert(!decoder.readBoolean()); // TODO extension marker
m_optionals = decoder.readBitset<3>();
if (travelerIsSet()) {
traveler = decoder.readSequenceOf<TravelerType>();
}
decodeSequence(decoder);
FCB_READ_SEQUENCE_OF_CUSTOM(traveler);
if (preferredLanguageIsSet()) {
preferredLanguage = decoder.readIA5String(2, 2);
}
......@@ -106,7 +118,7 @@ void Fcb::TravelerData::decode(UPERDecoder &decoder)
void Fcb::TrainLinkType::decode(UPERDecoder &decoder)
{
m_optionals = decoder.readBitset<9>();
decodeSequence(decoder);
FCB_READ_INT_IA5_PAIR_UNCONSTRAINED(train);
travelDate = decoder.readConstrainedWholeNumber(-1, 370);
departureTime = decoder.readConstrainedWholeNumber(0, 1440);
......@@ -141,11 +153,25 @@ void Fcb::ReturnRouteDescriptionType::decode(UPERDecoder &decoder)
assert(false);
}
void Fcb::OpenTicketData::decode(UPERDecoder &decoder)
void Fcb::TariffType::decode(UPERDecoder &decoder)
{
assert(!decoder.readBoolean()); // TODO extension marker
decodeSequence(decoder);
FCB_READ_CONSTAINED_INT(numberOfPassengers, 1, 200);
FCB_READ_EXTENDED_ENUM(passengerType);
FCB_READ_CONSTAINED_INT(ageBelow, 1, 64);
FCB_READ_CONSTAINED_INT(ageAbove, 1, 128);
FCB_READ_SEQUENCE_OF_CONTRAINED_INT(travelerid, 0, 254);
restrictedToCountryOfResidence = decoder.readBoolean();
// FCB_READ_CUSTOM(restrictedToRouteSection); TODO
// FCB_READ_CUSTOM(seriesDataDetails); TODO
FCB_READ_INT_IA5_PAIR_UNCONSTRAINED(tariffId);
FCB_READ_UTF8STRING(tariffDesc);
// FCB_READ_SEQUENCE_OF_CUSTOM(reductionCard); TODO
}
m_optionals = decoder.readBitset<38>();
void Fcb::OpenTicketData::decode(UPERDecoder &decoder)
{
decodeSequence(decoder);
FCB_READ_INT_IA5_PAIR_UNCONSTRAINED(reference);
FCB_READ_INT_IA5_PAIR(productOwner, 1, 32000);
FCB_READ_INT_IA5_PAIR(productId, 0, 32000);
......@@ -160,31 +186,32 @@ void Fcb::OpenTicketData::decode(UPERDecoder &decoder)
FCB_READ_UTF8STRING(fromStationNameUTF8);
FCB_READ_UTF8STRING(toStationNameUTF8);
FCB_READ_UTF8STRING(validRegionDesc);
if (validRegionIsSet()) {
validRegion = decoder.readSequenceOf<RegionalValidityType>();
}
if (returnDescriptionIsSet()) {
returnDescription.decode(decoder);
}
FCB_READ_SEQUENCE_OF_CUSTOM(validRegion);
FCB_READ_CUSTOM(returnDescription);
FCB_READ_CONSTAINED_INT(validFromDay, -1, 700);
FCB_READ_CONSTAINED_INT(validFromTime, 0, 1440);
FCB_READ_CONSTAINED_INT(validFromUTCOffset, -60, 60);
FCB_READ_CONSTAINED_INT(validUntilDay, 0, 370);
FCB_READ_CONSTAINED_INT(validUntilTime, 0, 1440);
FCB_READ_CONSTAINED_INT(validUntilUTCOffset, -60, 60);
assert(!activatedDayIsSet()); // TODO activatedDay
if (classCodeIsSet()) {
classCode = decoder.readEnumeratedWithExtensionMarker<TravelClassType>();
}
FCB_READ_SEQUENCE_OF_CONTRAINED_INT(activatedDay, 0, 370);
FCB_READ_EXTENDED_ENUM(classCode);
FCB_READ_IA5STRING(serviceLevel);
FCB_READ_SEQUENCE_OF_CONTRAINED_INT(carrierNum, 1, 32000);
// TODO carrierIA5
FCB_READ_SEQUENCE_OF_CONTRAINED_INT(includedServiceBrands, 1, 32000);
FCB_READ_SEQUENCE_OF_CONTRAINED_INT(excludedServiceBrands, 1, 32000);
FCB_READ_SEQUENCE_OF_CUSTOM(tariffs);
FCB_READ_UNCONSTRAINED_INT(price);
// FCB_READ_SEQUENCE_OF_CUSTOM(vatDetail); TODO
FCB_READ_UTF8STRING(infoText);
// TODO
FCB_READ_CUSTOM(extension);
}
void Fcb::DocumentData::decode(UPERDecoder &decoder)
{
assert(!decoder.readBoolean()); // TODO extension marker
m_optionals = decoder.readBitset<1>();
decodeSequence(decoder);
assert(!m_optionals[0]); // TODO token
assert(!decoder.readBoolean()); // TODO extension marker for CHOICE
......@@ -199,6 +226,12 @@ void Fcb::DocumentData::decode(UPERDecoder &decoder)
}
}
void Fcb::ControlData::decode(UPERDecoder &decoder)
{
decodeSequence(decoder);
// TODO
}
Fcb::UicRailTicketData::UicRailTicketData() = default;
Fcb::UicRailTicketData::UicRailTicketData(const Uic9183Block &block)
......@@ -210,15 +243,11 @@ Fcb::UicRailTicketData::UicRailTicketData(const Uic9183Block &block)
void Fcb::UicRailTicketData::decode(UPERDecoder &decoder)
{
assert(!decoder.readBoolean()); // TODO extension marker
m_optionals = decoder.readBitset<4>();
decodeSequence(decoder);
issuingDetail.decode(decoder);
if (travelerDetailIsSet()) {
travelerDetail.decode(decoder);
}
if (transportDocumentIsSet()) {
transportDocument = decoder.readSequenceOf<DocumentData>();
}
FCB_READ_CUSTOM(travelerDetail);
FCB_READ_SEQUENCE_OF_CUSTOM(transportDocument)
FCB_READ_CUSTOM(controlDetail)
}
#include "moc_fcbticket.cpp"
......@@ -30,8 +30,7 @@ class ExtensionData {
UPER_GADGET
UPER_ELEMENT(QByteArray, extensionId)
UPER_ELEMENT(QByteArray, extensionData)
public:
void decode(UPERDecoder &decoder);
UPER_GADGET_FINALIZE
};
class GeoCoordinateType {
......@@ -40,7 +39,7 @@ class GeoCoordinateType {
};
class IssuingData {
UPER_GADGET
UPER_EXTENDABLE_GADGET
UPER_ELEMENT_OPTIONAL(int, securityProviderNum)
UPER_ELEMENT_OPTIONAL(QByteArray, securityProviderIA5)
UPER_ELEMENT_OPTIONAL(int, issuerNum)
......@@ -93,7 +92,7 @@ class CustomerStatusType {
};
class TravelerType {
UPER_GADGET
UPER_EXTENDABLE_GADGET
UPER_ELEMENT_OPTIONAL(QString, firstName)
UPER_ELEMENT_OPTIONAL(QString, secondName)
UPER_ELEMENT_OPTIONAL(QString, lastName)
......@@ -116,7 +115,7 @@ class TravelerType {
};
class TravelerData {
UPER_GADGET
UPER_EXTENDABLE_GADGET
UPER_ELEMENT_OPTIONAL(QList<KItinerary::Fcb::TravelerType>, traveler)
UPER_ELEMENT_OPTIONAL(QByteArray, preferredLanguage)
UPER_ELEMENT_OPTIONAL(QString, groupName)
......@@ -149,14 +148,14 @@ class TrainLinkType {
};
class RegionalValidityType {
UPER_GADGET
UPER_EXTENDABLE_GADGET
UPER_ELEMENT(QVariant, value)
public:
void decode(UPERDecoder &decoder);
};
class ReturnRouteDescriptionType {
UPER_GADGET
UPER_EXTENDABLE_GADGET
// TODO
public:
void decode(UPERDecoder &decoder);
......@@ -174,28 +173,54 @@ enum TravelClassType {
};
Q_ENUM_NS(TravelClassType)
class TariffType {
class RouteSectionType {
UPER_GADGET
// TODO
};
class SeriesDetailType {
UPER_GADGET
};
class CardReferenceType {
UPER_EXTENDABLE_GADGET
// TODO
};
class TariffType {
UPER_EXTENDABLE_GADGET
UPER_ELEMENT_DEFAULT(int, numberOfPassengers, 1)
UPER_ELEMENT_OPTIONAL(KItinerary::Fcb::PassengerType, passengerType)
UPER_ELEMENT_OPTIONAL(int, ageBelow)
UPER_ELEMENT_OPTIONAL(int, ageAbove)
UPER_ELEMENT_OPTIONAL(QList<int>, travelerid)
UPER_ELEMENT(bool, restrictedToCountryOfResidence)
UPER_ELEMENT_OPTIONAL(KItinerary::Fcb::RouteSectionType, restrictedToRouteSection)
UPER_ELEMENT_OPTIONAL(KItinerary::Fcb::SeriesDetailType, seriesDataDetails)
UPER_ELEMENT_OPTIONAL(int, tariffIdNum)
UPER_ELEMENT_OPTIONAL(QByteArray, tariffIdIA5)
UPER_ELEMENT_OPTIONAL(QString, tariffDesc)
UPER_ELEMENT_OPTIONAL(QList<KItinerary::Fcb::CardReferenceType>, reductionCard)
UPER_GADGET_FINALIZE
};
class VatDetailType {
UPER_GADGET
// TODO
};
class IncludedOpenTicketType {
UPER_GADGET
UPER_EXTENDABLE_GADGET
// TODO
};
class LuggageRestrictionType {
UPER_GADGET
UPER_EXTENDABLE_GADGET
// TODO
};
class OpenTicketData {
UPER_GADGET
UPER_EXTENDABLE_GADGET
UPER_ELEMENT_OPTIONAL(int, referenceNum)
UPER_ELEMENT_OPTIONAL(QByteArray, referenceIA5)
UPER_ELEMENT_OPTIONAL(int, productOwnerNum)
......@@ -240,23 +265,44 @@ class OpenTicketData {
class TokenType {
UPER_GADGET
// TODO
UPER_ELEMENT_OPTIONAL(int, tokenProviderNum)
UPER_ELEMENT_OPTIONAL(QByteArray, tokenProviderIA5)
UPER_ELEMENT_OPTIONAL(QByteArray, tokenSpecification)
UPER_ELEMENT(QByteArray, token)
UPER_GADGET_FINALIZE
};
class DocumentData {
UPER_GADGET
UPER_EXTENDABLE_GADGET
UPER_ELEMENT_OPTIONAL(KItinerary::Fcb::TokenType, token)
UPER_ELEMENT(QVariant, ticket)
UPER_GADGET_FINALIZE
};
class ControlData {
UPER_GADGET
class TicketLinkType {
UPER_EXTENDABLE_GADGET
// TODO
};
class ControlData {
UPER_EXTENDABLE_GADGET
UPER_ELEMENT_OPTIONAL(QList <KItinerary::Fcb::CardReferenceType>, identificationByCardReference)
UPER_ELEMENT(bool, identificationByIdCard)
UPER_ELEMENT(bool, identificationByPassportId)
UPER_ELEMENT_OPTIONAL(int, identificationItem)
UPER_ELEMENT(bool, passportValidationRequired)
UPER_ELEMENT(bool, onlineValidationRequired)
UPER_ELEMENT_OPTIONAL(int, randomDetailedValidationRequired)
UPER_ELEMENT(bool, ageCheckRequired)
UPER_ELEMENT(bool, reductionCardCheckRequired)
UPER_ELEMENT_OPTIONAL(QString, infoString)
UPER_ELEMENT_OPTIONAL(QList<KItinerary::Fcb::TicketLinkType>, includedTickets)
UPER_ELEMENT_OPTIONAL(KItinerary::Fcb::ExtensionData, extension)
UPER_GADGET_FINALIZE
};
class KITINERARY_EXPORT UicRailTicketData {
UPER_GADGET
UPER_EXTENDABLE_GADGET
UPER_ELEMENT(KItinerary::Fcb::IssuingData, issuingDetail)
UPER_ELEMENT_OPTIONAL(KItinerary::Fcb::TravelerData, travelerDetail)
UPER_ELEMENT_OPTIONAL(QList<KItinerary::Fcb::DocumentData>, transportDocument)
......@@ -284,6 +330,8 @@ Q_DECLARE_METATYPE(KItinerary::Fcb::CustomerStatusType)
Q_DECLARE_METATYPE(KItinerary::Fcb::TravelerData)
Q_DECLARE_METATYPE(KItinerary::Fcb::RegionalValidityType)
Q_DECLARE_METATYPE(KItinerary::Fcb::ReturnRouteDescriptionType)
Q_DECLARE_METATYPE(KItinerary::Fcb::RouteSectionType)
Q_DECLARE_METATYPE(KItinerary::Fcb::SeriesDetailType)
Q_DECLARE_METATYPE(KItinerary::Fcb::TariffType)
Q_DECLARE_METATYPE(KItinerary::Fcb::VatDetailType)
Q_DECLARE_METATYPE(KItinerary::Fcb::IncludedOpenTicketType)
......@@ -291,6 +339,8 @@ Q_DECLARE_METATYPE(KItinerary::Fcb::LuggageRestrictionType)
Q_DECLARE_METATYPE(KItinerary::Fcb::OpenTicketData)
Q_DECLARE_METATYPE(KItinerary::Fcb::TokenType)
Q_DECLARE_METATYPE(KItinerary::Fcb::DocumentData)
Q_DECLARE_METATYPE(KItinerary::Fcb::CardReferenceType)
Q_DECLARE_METATYPE(KItinerary::Fcb::TicketLinkType)
Q_DECLARE_METATYPE(KItinerary::Fcb::ControlData)
Q_DECLARE_METATYPE(KItinerary::Fcb::UicRailTicketData)
......
Supports Markdown
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