From 9a57ca69a026d4280d90ee8f2b20ba6689c8a629 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20T=C5=AFma?= Date: Fri, 1 Nov 2019 19:07:21 +0100 Subject: [PATCH] Added support for mangled POI files --- src/data/gpiparser.cpp | 56 ++++++++++++++++++++++++++++++++++++------ src/data/gpiparser.h | 2 +- 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/src/data/gpiparser.cpp b/src/data/gpiparser.cpp index 595fe212..fc91e0e2 100644 --- a/src/data/gpiparser.cpp +++ b/src/data/gpiparser.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include "gpiparser.h" @@ -26,6 +27,32 @@ private: QString _str; }; + +#define BLOCK_KEY 0xf870b5 + +void demangle(quint8 *data, quint32 size, quint32 key) +{ + static const unsigned char shuf[] = { + 0xb, 0xc, 0xa, 0x0, + 0x8, 0xf, 0x2, 0x1, + 0x6, 0x4, 0x9, 0x3, + 0xd, 0x5, 0x7, 0xe + }; + + int hiCnt = 0, loCnt; + quint8 sum = shuf[(key >> 0x10) + key + (key >> 0x18) + (key >> 8) & 0xf]; + + for (quint32 i = 0; i < size; i++) { + quint8 hiAdd = shuf[key >> (hiCnt << 2) & 0xf] + sum; + loCnt = (hiCnt > 6) ? 0 : hiCnt + 1; + quint8 loAdd = shuf[key >> (loCnt << 2) & 0xf] + sum; + quint8 hi = data[i] + hiAdd * 0xf0; + quint8 lo = data[i] - loAdd; + data[i] = (hi & 0xf0) | (lo & 0x0f); + hiCnt = (loCnt > 6) ? 0 : loCnt + 1; + } +} + static inline double toWGS(qint32 v) { return (double)(((double)v / (double)(1U<<31)) * (double)180); @@ -306,7 +333,7 @@ static quint32 readFileDataRecord(QDataStream &stream, QTextCodec *codec) return rs + rh.size; } -bool GPIParser::readFileHeader(QDataStream &stream) +bool GPIParser::readFileHeader(QDataStream &stream, quint32 &ebs) { RecordHeader rh; quint32 ds, s7; @@ -326,10 +353,7 @@ bool GPIParser::readFileHeader(QDataStream &stream) if (rh.flags & 8) ds += readFprsRecord(stream); - if (s8 & 0x4) { - _errorString = "Encrypted GPI files not supported"; - return false; - } + ebs = (s8 & 0x4) ? s9 * 8 + 8 : 0; if (stream.status() != QDataStream::Ok || ds != rh.size) { _errorString = "Invalid file header"; @@ -432,13 +456,31 @@ bool GPIParser::parse(QFile *file, QList &tracks, Q_UNUSED(polygons); QDataStream stream(file); QTextCodec *codec = 0; + quint32 ebs; + bool ret; stream.setByteOrder(QDataStream::LittleEndian); - if (!readFileHeader(stream) || !readGPIHeader(stream, codec)) + if (!readFileHeader(stream, ebs) || !readGPIHeader(stream, codec)) return false; - if (!readData(stream, codec, waypoints)) { + if (ebs) { + QByteArray ba(stream.device()->readAll()); + for (int i = 0; i < (ba.size() / (int)ebs); i++) + demangle((quint8*)(ba.data() + i * ebs), ebs, BLOCK_KEY); + demangle((quint8*)(ba.data() + (ba.size() / (int)ebs) * ebs), + ba.size() - ((ba.size() / (int)ebs) * ebs), BLOCK_KEY); + + QBuffer buffer(&ba); + buffer.open(QIODevice::ReadOnly); + QDataStream memStream(&buffer); + memStream.setByteOrder(QDataStream::LittleEndian); + ret = readData(memStream, codec, waypoints); + } else + ret = readData(stream, codec, waypoints); + + + if (!ret) { _errorString = "Invalid/corrupted GPI data"; return false; } else diff --git a/src/data/gpiparser.h b/src/data/gpiparser.h index 62c144f1..d6bb61a3 100644 --- a/src/data/gpiparser.h +++ b/src/data/gpiparser.h @@ -15,7 +15,7 @@ public: int errorLine() const {return 0;} private: - bool readFileHeader(QDataStream &stream); + bool readFileHeader(QDataStream &stream, quint32 &ebs); bool readGPIHeader(QDataStream &stream, QTextCodec *codec); bool readData(QDataStream &stream, QTextCodec *codec, QVector &waypoints);