From 53e960fabea4d413e43fab0389eaa17e80d384e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20T=C5=AFma?= Date: Thu, 4 Jul 2019 18:18:03 +0200 Subject: [PATCH] Improved IMG map memory management --- src/map/IMG/img.cpp | 83 +++++++++++++++++++++++++--------------- src/map/IMG/img.h | 11 ++++-- src/map/IMG/trefile.cpp | 34 +++++++++------- src/map/IMG/trefile.h | 3 +- src/map/IMG/vectortile.h | 1 + src/map/imgmap.cpp | 24 ++++++++---- src/map/imgmap.h | 4 ++ 7 files changed, 103 insertions(+), 57 deletions(-) diff --git a/src/map/IMG/img.cpp b/src/map/IMG/img.cpp index ec3ae439..f6292343 100644 --- a/src/map/IMG/img.cpp +++ b/src/map/IMG/img.cpp @@ -5,6 +5,8 @@ #include "img.h" +#define CACHE_SIZE 8388608 /* 8MB */ + #define CHECK(condition) \ if (!(condition)) { \ _errorString = "Invalid/corrupted IMG file"; \ @@ -25,7 +27,8 @@ struct CTX QList *points; }; -IMG::IMG(const QString &fileName) : _file(fileName), _valid(false) +IMG::IMG(const QString &fileName) + : _file(fileName), _typ(0), _style(0), _valid(false) { if (!_file.open(QFile::ReadOnly)) { _errorString = _file.errorString(); @@ -50,6 +53,7 @@ IMG::IMG(const QString &fileName) : _file(fileName), _valid(false) QByteArray nba(QByteArray(d1, sizeof(d1)) + QByteArray(d2, sizeof(d2))); _name = QString(nba).trimmed(); _blockSize = 1 << (e1 + e2); + _blockCache.setMaxCost(CACHE_SIZE / _blockSize); // Read the FAT table quint8 flag; @@ -72,7 +76,7 @@ IMG::IMG(const QString &fileName) : _file(fileName), _valid(false) QMap tileMap; - QMap TYPMap; + QString typFile; // Read FAT blocks describing the IMG sub-files for (int i = 0; i < cnt; i++) { @@ -108,20 +112,22 @@ IMG::IMG(const QString &fileName) : _file(fileName), _valid(false) file->addBlock(block); } } else if (tt == SubFile::TYP) { - SubFile *typ; - QMap::iterator it = TYPMap.find(fn); - if (it == TYPMap.end()) { - typ = new SubFile(this, size); - TYPMap.insert(fn, typ); - } else - typ = *it; + SubFile *typ = 0; + if (typFile.isNull()) { + _typ = new SubFile(this, size); + typ = _typ; + typFile = fn; + } else if (fn == typFile) + typ = _typ; - _file.seek(offset + 0x20); - for (int i = 0; i < 240; i++) { - CHECK(readValue(block)); - if (block == 0xFFFF) - break; - typ->addBlock(block); + if (typ) { + _file.seek(offset + 0x20); + for (int i = 0; i < 240; i++) { + CHECK(readValue(block)); + if (block == 0xFFFF) + break; + typ->addBlock(block); + } } } @@ -143,22 +149,6 @@ IMG::IMG(const QString &fileName) : _file(fileName), _valid(false) _bounds |= (*it)->bounds(); } - // Read TYP file if any - if (!TYPMap.isEmpty()) { - if (TYPMap.size() > 1) - qWarning("%s: Multiple TYP files, using %s", - qPrintable(_file.fileName()), qPrintable(TYPMap.keys().first())); - SubFile *typ = TYPMap.values().first(); - _style = Style(typ); - qDeleteAll(TYPMap); - } else { - QFile typFile(ProgramPaths::typFile()); - if (typFile.exists()) { - SubFile typ(&typFile); - _style = Style(&typ); - } - } - _valid = true; } @@ -167,6 +157,37 @@ IMG::~IMG() TileTree::Iterator it; for (_tileTree.GetFirst(it); !_tileTree.IsNull(it); _tileTree.GetNext(it)) delete _tileTree.GetAt(it); + + delete _typ; + delete _style; +} + +void IMG::load() +{ + Q_ASSERT(!_style); + + if (_typ && _typ->isValid()) + _style = new Style(_typ); + else { + QFile typFile(ProgramPaths::typFile()); + if (typFile.exists()) { + SubFile typ(&typFile); + _style = new Style(&typ); + } else + _style = new Style(); + } +} + +void IMG::clear() +{ + TileTree::Iterator it; + for (_tileTree.GetFirst(it); !_tileTree.IsNull(it); _tileTree.GetNext(it)) + _tileTree.GetAt(it)->clear(); + + delete _style; + _style = 0; + + _blockCache.clear(); } static bool cb(VectorTile *tile, void *context) diff --git a/src/map/IMG/img.h b/src/map/IMG/img.h index e2a6deb8..925963e9 100644 --- a/src/map/IMG/img.h +++ b/src/map/IMG/img.h @@ -48,13 +48,16 @@ public: IMG(const QString &fileName); ~IMG(); + void load(); + void clear(); + QString fileName() const {return _file.fileName();} const QString &name() const {return _name;} const RectC &bounds() const {return _bounds;} void objects(const RectC &rect, int bits, QList *polygons, QList *lines, QList *points); - const Style &style() const {return _style;} + const Style *style() const {return _style;} bool isValid() const {return _valid;} const QString &errorString() const {return _errorString;} @@ -75,11 +78,11 @@ private: int _blockSize; QCache _blockCache; - TileTree _tileTree; - QString _name; RectC _bounds; - Style _style; + TileTree _tileTree; + SubFile *_typ; + Style *_style; bool _valid; QString _errorString; diff --git a/src/map/IMG/trefile.cpp b/src/map/IMG/trefile.cpp index ae6f42f1..4a4496ad 100644 --- a/src/map/IMG/trefile.cpp +++ b/src/map/IMG/trefile.cpp @@ -40,18 +40,7 @@ static void unlock(quint8 *dst, const quint8 *src, quint32 size, quint32 key) TREFile::~TREFile() { - SubDivTree::Iterator jt; - - for (QMap::iterator it = _subdivs.begin(); - it != _subdivs.end(); ++it) { - SubDivTree *tree = *it; - for (tree->GetFirst(jt); !tree->IsNull(jt); tree->GetNext(jt)) - delete tree->GetAt(jt); - } - - for (QMap::iterator it = _subdivs.begin(); - it != _subdivs.end(); ++it) - delete *it; + clear(); } bool TREFile::init() @@ -69,7 +58,7 @@ bool TREFile::init() return true; } -bool TREFile::init2() +bool TREFile::load() { Handle hdl; quint8 locked; @@ -202,9 +191,26 @@ bool TREFile::init2() return true; } +void TREFile::clear() +{ + SubDivTree::Iterator jt; + + for (QMap::iterator it = _subdivs.begin(); + it != _subdivs.end(); ++it) { + SubDivTree *tree = *it; + for (tree->GetFirst(jt); !tree->IsNull(jt); tree->GetNext(jt)) + delete tree->GetAt(jt); + } + + qDeleteAll(_subdivs); + + _subdivs.clear(); + _levels.clear(); +} + int TREFile::level(int bits) { - if (_levels.isEmpty() && !init2()) + if (_levels.isEmpty() && !load()) return -1; int l = _levels.first(); diff --git a/src/map/IMG/trefile.h b/src/map/IMG/trefile.h index 07548cb1..2f92a86a 100644 --- a/src/map/IMG/trefile.h +++ b/src/map/IMG/trefile.h @@ -17,6 +17,7 @@ public: ~TREFile(); bool init(); + void clear(); const RectC &bounds() const {return _bounds;} QList subdivs(const RectC &rect, int bits); @@ -24,7 +25,7 @@ public: private: typedef RTree SubDivTree; - bool init2(); + bool load(); int level(int bits); bool parsePoly(Handle hdl, quint32 pos, const QMap &level2bits, QMap &map); diff --git a/src/map/IMG/vectortile.h b/src/map/IMG/vectortile.h index 20fc24b3..782d137a 100644 --- a/src/map/IMG/vectortile.h +++ b/src/map/IMG/vectortile.h @@ -14,6 +14,7 @@ public: ~VectorTile() {delete _tre; delete _rgn; delete _lbl; delete _net;} bool init(); + void clear() {_tre->clear();} const RectC &bounds() const {return _tre->bounds();} diff --git a/src/map/imgmap.cpp b/src/map/imgmap.cpp index 4d6c45cc..96e9ae81 100644 --- a/src/map/imgmap.cpp +++ b/src/map/imgmap.cpp @@ -174,6 +174,16 @@ IMGMap::IMGMap(const QString &fileName, QObject *parent) _valid = true; } +void IMGMap::load() +{ + _img.load(); +} + +void IMGMap::unload() +{ + _img.clear(); +} + QRectF IMGMap::bounds() { RectD prect(_img.bounds(), _projection); @@ -248,12 +258,12 @@ Coordinates IMGMap::xy2ll(const QPointF &p) void IMGMap::drawPolygons(QPainter *painter, const QList &polygons) { - for (int n = 0; n < _img.style().drawOrder().size(); n++) { + for (int n = 0; n < _img.style()->drawOrder().size(); n++) { for (int i = 0; i < polygons.size(); i++) { const IMG::Poly &poly = polygons.at(i); - if (poly.type != _img.style().drawOrder().at(n)) + if (poly.type != _img.style()->drawOrder().at(n)) continue; - const Style::Polygon &style = _img.style().polygon(poly.type); + const Style::Polygon &style = _img.style()->polygon(poly.type); painter->setPen(style.pen()); painter->setBrush(style.brush()); @@ -268,7 +278,7 @@ void IMGMap::drawLines(QPainter *painter, const QList &lines) for (int i = 0; i < lines.size(); i++) { const IMG::Poly &poly = lines.at(i); - const Style::Line &style = _img.style().line(poly.type); + const Style::Line &style = _img.style()->line(poly.type); if (style.background() == Qt::NoPen) continue; @@ -279,7 +289,7 @@ void IMGMap::drawLines(QPainter *painter, const QList &lines) for (int i = 0; i < lines.size(); i++) { const IMG::Poly &poly = lines.at(i); - const Style::Line &style = _img.style().line(poly.type); + const Style::Line &style = _img.style()->line(poly.type); if (!style.img().isNull()) BitmapLine::draw(painter, poly.points, style.img()); @@ -326,7 +336,7 @@ void IMGMap::processLines(QList &lines, const QPoint &tile, if (_zoom >= LINE_TEXT_MIN_ZOOM) { for (int i = 0; i < lines.size(); i++) { IMG::Poly &poly = lines[i]; - const Style::Line &style = _img.style().line(poly.type); + const Style::Line &style = _img.style()->line(poly.type); if (style.img().isNull() && style.foreground() == Qt::NoPen) continue; @@ -415,7 +425,7 @@ void IMGMap::processPoints(QList &points, for (int i = 0; i < points.size(); i++) { IMG::Point &point = points[i]; - const Style::Point &style = _img.style().point(point.type); + const Style::Point &style = _img.style()->point(point.type); if (point.poi && _zoom < minPOIZoom(Style::poiClass(point.type))) continue; diff --git a/src/map/imgmap.h b/src/map/imgmap.h index 73a14bd2..39a0dcc7 100644 --- a/src/map/imgmap.h +++ b/src/map/imgmap.h @@ -34,6 +34,9 @@ public: void setProjection(const Projection &projection); + void load(); + void unload(); + bool isValid() const {return _valid;} QString errorString() const {return _errorString;} @@ -56,6 +59,7 @@ private: Range _zooms; Projection _projection; Transform _transform; + bool _valid; QString _errorString; };