diff --git a/gpxsee.pro b/gpxsee.pro index e031ade6..444ce500 100644 --- a/gpxsee.pro +++ b/gpxsee.pro @@ -82,7 +82,8 @@ HEADERS += src/config.h \ src/emptymap.h \ src/ozimap.h \ src/mapdir.h \ - src/matrix.h + src/matrix.h \ + src/tar.h SOURCES += src/main.cpp \ src/gui.cpp \ src/poi.cpp \ @@ -140,7 +141,8 @@ SOURCES += src/main.cpp \ src/emptymap.cpp \ src/ozimap.cpp \ src/mapdir.cpp \ - src/matrix.cpp + src/matrix.cpp \ + src/tar.cpp RESOURCES += gpxsee.qrc TRANSLATIONS = lang/gpxsee_cs.ts \ lang/gpxsee_sv.ts diff --git a/src/ozimap.cpp b/src/ozimap.cpp index 5a395a6a..70357f27 100644 --- a/src/ozimap.cpp +++ b/src/ozimap.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "misc.h" #include "rd.h" #include "wgs84.h" @@ -152,19 +153,16 @@ bool OziMap::computeResolution(QList &points) return true; } -bool OziMap::getTileInfo(QDir &set) +bool OziMap::getTileName(const QStringList &tiles) { - QFileInfoList tiles = set.entryInfoList(QDir::Files); - if (tiles.isEmpty()) { qWarning("%s: empty tile set", qPrintable(_name)); return false; } for (int i = 0; i < tiles.size(); i++) { - if (tiles.at(i).fileName().contains("_0_0.")) { - _tileName = QString(tiles.at(i).fileName()) - .replace("_0_0.", "_%1_%2."); + if (tiles.at(i).contains("_0_0.")) { + _tileName = QString(tiles.at(i)).replace("_0_0.", "_%1_%2."); break; } } @@ -172,14 +170,27 @@ bool OziMap::getTileInfo(QDir &set) qWarning("%s: invalid tile names", qPrintable(_name)); return false; } - _tileName = set.absolutePath() + "/" + _tileName; - QImage tile(_tileName.arg("0", "0")); + return true; +} + +bool OziMap::getTileSize() +{ + QString tileName(_tileName.arg(QString::number(0), QString::number(0))); + QImage tile; + + if (_tar.isOpen()) { + QByteArray ba = _tar.file(tileName); + tile = QImage::fromData(ba); + } else + tile = QImage(tileName); + if (tile.isNull()) { qWarning("%s: error retrieving tile size: %s: invalid image", - qPrintable(_name), qPrintable(_tileName.arg("0", "0"))); + qPrintable(_name), qPrintable(QFileInfo(tileName).fileName())); return false; } + _tileSize = tile.size(); return true; @@ -187,25 +198,45 @@ bool OziMap::getTileInfo(QDir &set) OziMap::OziMap(const QString &path, QObject *parent) : Map(parent) { - int errorLine; + int errorLine = -2; QList points; _valid = false; QFileInfo fi(path); - _name = fi.baseName(); + _name = fi.fileName(); QDir dir(path); - QFileInfoList list = dir.entryInfoList(QStringList("*.map"), QDir::Files); - if (!list.count()) { - qWarning("%s: map file not found", qPrintable(_name)); - return; + QFileInfoList mapFiles = dir.entryInfoList(QDir::Files); + for (int i = 0; i < mapFiles.count(); i++) { + const QString &fileName = mapFiles.at(i).fileName(); + if (fileName.endsWith(".tar")) { + if (!_tar.load(mapFiles.at(0).absoluteFilePath())) { + qWarning("%s: %s: error loading tar file", qPrintable(_name), + qPrintable(fileName)); + return; + } + QStringList tarFiles = _tar.files(); + for (int j = 0; j < tarFiles.size(); j++) { + if (tarFiles.at(j).endsWith(".map")) { + QByteArray ba = _tar.file(tarFiles.at(j)); + QBuffer buffer(&ba); + errorLine = parseMapFile(buffer, points); + break; + } + } + break; + } else if (fileName.endsWith(".map")) { + QFile mapFile(mapFiles.at(i).absoluteFilePath()); + errorLine = parseMapFile(mapFile, points); + break; + } } - - QFile mapFile(list[0].absoluteFilePath()); - if ((errorLine = parseMapFile(mapFile, points))) { - if (errorLine < 0) + if (errorLine) { + if (errorLine == -2) + qWarning("%s: no map file found", qPrintable(_name)); + else if (errorLine == -1) qWarning("%s: error opening map file", qPrintable(_name)); else qWarning("%s: map file parse error on line: %d", qPrintable(_name), @@ -224,19 +255,29 @@ OziMap::OziMap(const QString &path, QObject *parent) : Map(parent) return; } - QDir set(fi.absoluteFilePath() + "/" + "set"); - if (set.exists()) { - if (!getTileInfo(set)) + if (_tar.isOpen()) { + if (!getTileName(_tar.files())) + return; + if (!getTileSize()) return; } else { - QFileInfo ii(_imgPath); - if (ii.isRelative()) - _imgPath = fi.absoluteFilePath() + "/" + _imgPath; - ii = QFileInfo(_imgPath); - if (!ii.exists()) { - qWarning("%s: %s: no such image", qPrintable(_name), - qPrintable(ii.absoluteFilePath())); - return; + QDir set(fi.absoluteFilePath() + "/" + "set"); + if (set.exists()) { + if (!getTileName(set.entryList())) + return; + _tileName = set.absolutePath() + "/" + _tileName; + if (!getTileSize()) + return; + } else { + QFileInfo ii(_imgPath); + if (ii.isRelative()) + _imgPath = fi.absoluteFilePath() + "/" + _imgPath; + ii = QFileInfo(_imgPath); + if (!ii.exists()) { + qWarning("%s: %s: no such image", qPrintable(_name), + qPrintable(ii.absoluteFilePath())); + return; + } } } @@ -302,8 +343,16 @@ void OziMap::draw(QPainter *painter, const QRectF &rect) for (int j = 0; j < ceil(s.height() / _tileSize.height()); j++) { int x = tl.x() + i * _tileSize.width(); int y = tl.y() + j * _tileSize.height(); - QPixmap pixmap(_tileName.arg(QString::number(x), + QString tileName(_tileName.arg(QString::number(x), QString::number(y))); + QPixmap pixmap; + + if (_tar.isOpen()) { + QByteArray ba = _tar.file(tileName); + pixmap = QPixmap::fromImage(QImage::fromData(ba)); + } else + pixmap = QPixmap(tileName); + if (pixmap.isNull()) { qWarning("%s: error loading tile image", qPrintable( _tileName.arg(QString::number(x), QString::number(y)))); diff --git a/src/ozimap.h b/src/ozimap.h index c74904df..ef61d62a 100644 --- a/src/ozimap.h +++ b/src/ozimap.h @@ -4,6 +4,7 @@ #include #include #include "map.h" +#include "tar.h" #include "coordinates.h" class QIODevice; @@ -42,7 +43,8 @@ private: int parseMapFile(QIODevice &device, QList &points); bool computeTransformation(const QList &points); bool computeResolution(QList &points); - bool getTileInfo(QDir &set); + bool getTileName(const QStringList &tiles); + bool getTileSize(); QString _name; QString _imgPath; @@ -50,6 +52,7 @@ private: QTransform _transform; qreal _resolution; + Tar _tar; QImage *_img; QSize _tileSize; QString _tileName; diff --git a/src/tar.cpp b/src/tar.cpp new file mode 100644 index 00000000..4a08d5ca --- /dev/null +++ b/src/tar.cpp @@ -0,0 +1,74 @@ +#include +#include +#include "tar.h" + + +#define BLOCKSIZE 512 + +#define BLOCKCOUNT(size) \ + ((size)/BLOCKSIZE + ((size) % BLOCKSIZE > 0 ? 1 : 0)) + +struct Header +{ + char name[100]; /* 0 */ + char mode[8]; /* 100 */ + char uid[8]; /* 108 */ + char gid[8]; /* 116 */ + char size[12]; /* 124 */ + char mtime[12]; /* 136 */ + char chksum[8]; /* 148 */ + char typeflag; /* 156 */ + char linkname[100]; /* 157 */ + char magic[6]; /* 257 */ + char version[2]; /* 263 */ + char uname[32]; /* 265 */ + char gname[32]; /* 297 */ + char devmajor[8]; /* 329 */ + char devminor[8]; /* 337 */ + char prefix[155]; /* 345 */ + /* 500 */ +}; + +static quint64 number(const char* data, size_t size) +{ + const char *sp; + quint64 val = 0; + + for (sp = data; sp < data + size; sp++) + if (isdigit(*sp)) + break; + for (; sp < data + size && isdigit(*sp); sp++) + val = val * 8 + *sp - '0'; + + return val; +} + +bool Tar::load(const QString &path) +{ + struct Header hdr; + quint64 size; + + _file.setFileName(path); + if (!_file.open(QIODevice::ReadOnly)) + return false; + + while (_file.read((char*)&hdr, BLOCKSIZE)) { + size = number(hdr.size, sizeof(hdr.size)); + if (size) + _index.insert(hdr.name, Info(size, _file.pos())); + _file.seek(_file.pos() + BLOCKCOUNT(size) * BLOCKSIZE); + } + + return true; +} + +QByteArray Tar::file(const QString &name) +{ + QMap::const_iterator it = _index.find(name); + Q_ASSERT(it != _index.end()); + + if (_file.seek(it.value().offset())) + return _file.read(it.value().size()); + else + return QByteArray(); +} diff --git a/src/tar.h b/src/tar.h new file mode 100644 index 00000000..e7a6aeb6 --- /dev/null +++ b/src/tar.h @@ -0,0 +1,35 @@ +#ifndef TAR_H +#define TAR_H + +#include +#include +#include + +class Tar +{ +public: + bool load(const QString &path); + + QStringList files() const {return _index.keys();} + QByteArray file(const QString &name); + + bool isOpen() const {return _file.isOpen();} + +private: + class Info + { + public: + Info(quint64 size, quint64 offset) : _size(size), _offset(offset) {} + quint64 size() const {return _size;} + quint64 offset() const {return _offset;} + + private: + quint64 _size; + quint64 _offset; + }; + + QFile _file; + QMap _index; +}; + +#endif // TAR_H