File indexing completed on 2024-05-12 04:42:34
0001 /* 0002 SPDX-FileCopyrightText: 2019 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #ifndef KPUBLICTRANSPORT_HAFASJOURNEYRESPONSE_P_H 0008 #define KPUBLICTRANSPORT_HAFASJOURNEYRESPONSE_P_H 0009 0010 #include <QStringDecoder> 0011 0012 #include <cstdint> 0013 0014 namespace KPublicTransport { 0015 0016 #pragma pack(push) 0017 #pragma pack(1) 0018 0019 // occurs once at offset 0 0020 struct HafasJourneyResponseHeader 0021 { 0022 uint16_t version; 0023 uint16_t departureNameStr; 0024 uint16_t padding1; 0025 uint16_t departureType; 0026 uint32_t departureLongitude; 0027 uint32_t departureLatitude; 0028 uint16_t arrivalNameStr; 0029 uint16_t padding2; 0030 uint16_t arrivalType; 0031 uint32_t arrivalLongitude; 0032 uint32_t arrivalLatitude; 0033 // amount of journeys in the response 0034 uint16_t numJourneys; 0035 uint32_t serviceDaysTableOffset; 0036 // offset to HafasJourneyResponseStringTable 0037 uint32_t stringTableOffset; 0038 // base date for all times in the response, in days after 1980-01-01 0039 uint16_t date; 0040 uint8_t padding3[12]; 0041 // offset to HafasJourneyResponseStation table 0042 uint32_t stationTableOffset; 0043 uint32_t commentTableOffset; 0044 uint8_t padding4[8]; 0045 // offset to HafasJourneyResponseExtendedHeader 0046 uint32_t extendedHeaderOffset; 0047 }; 0048 static_assert(sizeof(HafasJourneyResponseHeader) == 0x4a, "size of response header is wrong"); 0049 static_assert(alignof(HafasJourneyResponseHeader) == 1, "broken alignment for binary response struct"); 0050 0051 // extended header, occurs once at offset HafasJourneyResponseHeader::extendedHeaderOffset 0052 struct HafasJourneyResponseExtendedHeader 0053 { 0054 // length of the extended header (should >= sizeof(HafasJourneyResponseExtendedHeader) 0055 uint32_t length; 0056 uint32_t padding1; 0057 uint16_t seqNum; 0058 uint16_t requestIdStr; 0059 // offset to HafasJourneyResponseDetailsHeader 0060 uint32_t detailsOffset; 0061 // error code for the journey query, 0 means success 0062 uint16_t errorCode; 0063 uint16_t padding2; 0064 uint32_t disruptionTableOffset; 0065 uint8_t padding3[8]; 0066 // string table index for the name of the encoding used in the string table 0067 uint16_t encodingStr; 0068 uint16_t ldStr; 0069 // base offset for attributes table 0070 uint32_t attributesOffset; 0071 uint32_t padding4; 0072 // if > 0 this is an index into a uint16_t table with the journey attribute offsets 0073 uint32_t journeyAttributesIndexOffset; 0074 }; 0075 static_assert(alignof(HafasJourneyResponseExtendedHeader) == 1, "broken alignment for binary response struct"); 0076 0077 // journey details header, occurs once at offset HafasJourneyResponseExtendedHeader::detailsOffset 0078 struct HafasJourneyResponseDetailsHeader 0079 { 0080 uint16_t version; 0081 uint16_t padding; 0082 uint16_t journeyDetailsIndexOffset; 0083 uint16_t sectionDetailsOffset; 0084 uint16_t sectionDetailsSize; 0085 uint16_t stopsSize; 0086 uint16_t stopsOffset; 0087 }; 0088 static_assert(alignof(HafasJourneyResponseDetailsHeader) == 1, "broken alignment for binary response struct"); 0089 0090 // occurs HafasJourneyResponseHeader::numJourneys times, right after HafasJourneyResponseHeader at offset 0x4a 0091 struct HafasJourneyResponseJourney 0092 { 0093 uint16_t serviceDaysTableOffset; 0094 // offset for the HafasJourneyResponseSection table to start 0095 uint32_t sectionsOffset; 0096 // number of sections in this journey 0097 uint16_t numSections; 0098 uint16_t numChanges; 0099 uint16_t duration; 0100 }; 0101 static_assert(sizeof(HafasJourneyResponseJourney) == 12, "size of journey structure is wrong"); 0102 static_assert(alignof(HafasJourneyResponseJourney) == 1, "broken alignment for binary response struct"); 0103 0104 // occurs HafasJourneyResponseJourney::numSections times, after HafasJourneyResponseHeader + HafasJourneyResponseJourney::sectionsOffset 0105 struct HafasJourneyResponseSection 0106 { 0107 // hours * 100 + minutes 0108 uint16_t scheduledDepartureTime; 0109 // index into station table 0110 uint16_t departureStationIdx; 0111 uint16_t scheduledArrivalTime; 0112 uint16_t arrivalStationIdx; 0113 // section mode, see enum below 0114 uint16_t type; 0115 // index into string table 0116 uint16_t lineNameStr; 0117 // index into string table 0118 uint16_t scheduledDeparturePlatformStr; 0119 uint16_t scheduledArrivalPlatformStr; 0120 // section attribute table index 0121 uint16_t sectionAttributeIndex; 0122 uint16_t commentIdx; 0123 }; 0124 static_assert(sizeof(HafasJourneyResponseSection) == 20, "size of section structure is wrong"); 0125 static_assert(alignof(HafasJourneyResponseSection) == 1, "broken alignment for binary response struct"); 0126 0127 // values for HafasJourneyResponseSection::type 0128 namespace HafasJourneyResponseSectionMode { 0129 enum Mode { 0130 Walk = 1, 0131 PublicTransport = 2, 0132 Transfer1 = 3, 0133 Transfer2 = 4 0134 }; 0135 } 0136 0137 struct HafasJourneyResponseSectionDetail 0138 { 0139 // see above for format 0140 uint16_t expectedDepartureTime; 0141 uint16_t expectedArrivalTime; 0142 // indexes into string table 0143 uint16_t expectedDeparturePlatformStr; 0144 uint16_t expectedArrivalPlatformStr; 0145 uint16_t flags; 0146 uint16_t padding1; 0147 uint16_t stopIndex; 0148 uint16_t numStops; 0149 }; 0150 static_assert(alignof(HafasJourneyResponseSectionDetail) == 1, "broken alignment for binary response struct"); 0151 0152 // occurs multiple times at offset HafasJourneyResponseHeader::stationTableOffset 0153 struct HafasJourneyResponseStation 0154 { 0155 // station name as index into the string table 0156 uint16_t nameStr; 0157 uint32_t id; 0158 // geo coordinates * 1000000 0159 int32_t longitude; 0160 int32_t latitude; 0161 }; 0162 static_assert(sizeof(HafasJourneyResponseStation) == 14, "size of station structure is wrong"); 0163 static_assert(alignof(HafasJourneyResponseStation) == 1, "broken alignment for binary response struct"); 0164 0165 // attribute table entries: pair if string table indexes 0166 // can be iterated until atEnd() returns @c true 0167 struct HafasJourneyResponseAttribute 0168 { 0169 uint16_t keyStr; 0170 uint16_t valueStr; 0171 0172 inline bool atEnd() const { return keyStr == 0; } 0173 }; 0174 static_assert(sizeof(HafasJourneyResponseAttribute) == 4, "size of attribute structure is wrong"); 0175 static_assert(alignof(HafasJourneyResponseAttribute) == 1, "broken alignment for binary response struct"); 0176 0177 struct HafasJourneyResponseDisruption; 0178 // disruption table 0179 struct HafasJourneyResponseDisruptionTable 0180 { 0181 uint16_t padding1; // version? 0182 // followed by one uint16_t for each journey, containing the offset of the first HafasJourneyResponseDisruption entry for that journey 0183 0184 /** First disruption entry for journey @p journeyIdx, or @c nullptr if none present. */ 0185 inline const HafasJourneyResponseDisruption* firstDisruptionForJourney(uint16_t journeyIdx) const { 0186 const auto offset = *reinterpret_cast<const uint16_t*>(reinterpret_cast<const char*>(this) + sizeof(HafasJourneyResponseDisruptionTable) + journeyIdx * sizeof(uint16_t)); 0187 return offset ? reinterpret_cast<const HafasJourneyResponseDisruption*>(reinterpret_cast<const char*>(this) + offset) : nullptr; 0188 } 0189 }; 0190 static_assert(alignof(HafasJourneyResponseDisruptionTable) == 1, "broken alignment for binary response struct"); 0191 0192 // intermediate stops, located at HafasJourneyResponseDetailsHeader::stopsOffset 0193 struct HafasJourneyResponseStop 0194 { 0195 uint16_t scheduledDepartureTime; 0196 uint16_t scheduledArrivalTime; 0197 uint16_t scheduledDeparturePlatformStr; 0198 uint16_t scheduledArrivalPlatformStr; 0199 uint32_t unknown1; 0200 uint16_t expectedDepartureTime; 0201 uint16_t expectedArrivalTime; 0202 uint16_t expectedDeparturePlatformStr; 0203 uint16_t expectedArrivalPlatformStr; 0204 uint16_t flags; // 0x10 arrival cancelled, 0x20 departure cancelled 0205 uint16_t unknown2; 0206 uint16_t stationIdx; 0207 }; 0208 0209 // disruption table entry 0210 struct HafasJourneyResponseDisruption 0211 { 0212 uint16_t padding1; 0213 // index of the affected section 0214 uint16_t section; 0215 uint16_t bitmask; 0216 // indexes into string table 0217 uint16_t startStr; 0218 uint16_t endStr; 0219 uint16_t idStr; 0220 uint16_t titleStr; 0221 uint16_t messageStr; 0222 // offset from start of disruption table to the next element 0223 uint16_t nextOffset; 0224 // index into attribute table 0225 uint16_t disruptionAttributeIndex; 0226 0227 /** Next disruption entry in the current disruption list. */ 0228 inline const HafasJourneyResponseDisruption* next(const HafasJourneyResponseDisruptionTable *disruptionTable) const 0229 { 0230 return nextOffset ? reinterpret_cast<const HafasJourneyResponseDisruption*>(reinterpret_cast<const char*>(disruptionTable) + nextOffset) : nullptr; 0231 } 0232 }; 0233 static_assert(alignof(HafasJourneyResponseDisruption) == 1, "broken alignment for binary response struct"); 0234 0235 #pragma pack(pop) 0236 0237 // occurs once, at offset HafasJourneyResponseHeader::stringTableOffset 0238 class HafasJourneyResponseStringTable 0239 { 0240 public: 0241 explicit inline HafasJourneyResponseStringTable(const QByteArray &data, uint32_t stringTableOffset, uint16_t codecIdx) : 0242 m_data(data.constData() + stringTableOffset) 0243 { 0244 m_codec = QStringDecoder(QByteArray(m_data + codecIdx).constData()); 0245 } 0246 0247 inline QString lookup(uint16_t index) 0248 { 0249 // null terminated strings in the given codec 0250 return m_codec.decode(m_data + index); 0251 } 0252 0253 private: 0254 const char *m_data; 0255 QStringDecoder m_codec; 0256 }; 0257 0258 namespace HafasJourneyResponse { 0259 /** Returns the attribute at @p attributeIdx. */ 0260 inline const HafasJourneyResponseAttribute* attribute(const char *data, const HafasJourneyResponseExtendedHeader *extHeader, uint16_t attributeIdx) 0261 { 0262 return reinterpret_cast<const HafasJourneyResponseAttribute*>(data + extHeader->attributesOffset + attributeIdx * sizeof(HafasJourneyResponseAttribute)); 0263 } 0264 0265 /** Returns the disruption table. */ 0266 inline const HafasJourneyResponseDisruptionTable* disruptionTable(const char *data, const HafasJourneyResponseExtendedHeader *extHeader) 0267 { 0268 return reinterpret_cast<const HafasJourneyResponseDisruptionTable*>(data + extHeader->disruptionTableOffset); 0269 } 0270 0271 } 0272 0273 } 0274 0275 #endif // KPUBLICTRANSPORT_HAFASJOURNEYRESPONSE_P_H