diff --git a/src/map/IMG/gmap.h b/src/map/IMG/gmap.h index 6f761341..5f04397f 100644 --- a/src/map/IMG/gmap.h +++ b/src/map/IMG/gmap.h @@ -12,7 +12,7 @@ public: GMAP(const QString &fileName); ~GMAP(); - QString fileName() const {return _fileName;} + const QString &fileName() const {return _fileName;} static bool isGMAP(const QString &path); diff --git a/src/map/IMG/img.cpp b/src/map/IMG/img.cpp index 634ee636..1b866a95 100644 --- a/src/map/IMG/img.cpp +++ b/src/map/IMG/img.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "vectortile.h" #include "img.h" @@ -24,7 +25,7 @@ static SubFile::Type tileType(const char str[3]) return SubFile::Unknown; } -IMG::IMG(const QString &fileName) : _file(fileName) +IMG::IMG(const QString &fileName) : _fileName(fileName) { #define CHECK(condition) \ if (!(condition)) { \ @@ -33,19 +34,20 @@ IMG::IMG(const QString &fileName) : _file(fileName) return; \ } + QFile file(fileName); TileMap tileMap; QByteArray typFile; - if (!_file.open(QFile::ReadOnly)) { - _errorString = _file.errorString(); + if (!file.open(QFile::ReadOnly)) { + _errorString = file.errorString(); return; } // Read IMG header char signature[7], identifier[7]; - _file.read((char*)&_key, 1) && _file.seek(0x10) - && read(signature, sizeof(signature)) && _file.seek(0x41) - && read(identifier, sizeof(identifier)); + file.read((char*)&_key, 1) && file.seek(0x10) + && read(file, signature, sizeof(signature)) && file.seek(0x41) + && read(file, identifier, sizeof(identifier)); if (memcmp(signature, "DSKIMG", sizeof(signature)) || memcmp(identifier, "GARMIN", sizeof(identifier))) { _errorString = "Not a Garmin IMG file"; @@ -53,9 +55,9 @@ IMG::IMG(const QString &fileName) : _file(fileName) } char d1[20], d2[31]; quint8 e1, e2; - CHECK(_file.seek(0x49) && read(d1, sizeof(d1)) && _file.seek(0x61) - && readValue(e1) && readValue(e2) && _file.seek(0x65) - && read(d2, sizeof(d2))); + CHECK(file.seek(0x49) && read(file, d1, sizeof(d1)) && file.seek(0x61) + && readValue(file, e1) && readValue(file, e2) && file.seek(0x65) + && read(file, d2, sizeof(d2))); QByteArray nba(QByteArray(d1, sizeof(d1)) + QByteArray(d2, sizeof(d2))); _name = QString::fromLatin1(nba.constData(), nba.size()-1).trimmed(); @@ -66,7 +68,7 @@ IMG::IMG(const QString &fileName) : _file(fileName) quint64 offset = 0x200; // Skip unused FAT blocks if any while (true) { - CHECK(_file.seek(offset) && readValue(flag)); + CHECK(file.seek(offset) && readValue(file, flag)); if (flag) break; offset += 512; @@ -76,15 +78,17 @@ IMG::IMG(const QString &fileName) : _file(fileName) char name[8], type[3]; quint32 size; quint16 part; - CHECK(_file.seek(offset + 12) && readValue(size)); + CHECK(file.seek(offset + 12) && readValue(file, size)); offset += 512; int cnt = (size - offset) / 512; // Read FAT blocks describing the IMG sub-files for (int i = 0; i < cnt; i++) { quint16 block; - CHECK(_file.seek(offset) && readValue(flag) && read(name, sizeof(name)) - && read(type, sizeof(type)) && readValue(size) && readValue(part)); + CHECK(file.seek(offset) && readValue(file, flag) + && read(file, name, sizeof(name)) + && read(file, type, sizeof(type)) && readValue(file, size) + && readValue(file, part)); SubFile::Type tt = tileType(type); QByteArray fn(name, sizeof(name)); @@ -97,16 +101,16 @@ IMG::IMG(const QString &fileName) : _file(fileName) } else tile = *it; - SubFile *file = part ? tile->file(tt) + SubFile *subFile = part ? tile->file(tt) : tile->addFile(this, tt); - CHECK(file); + CHECK(subFile); - _file.seek(offset + 0x20); + file.seek(offset + 0x20); for (int i = 0; i < 240; i++) { - CHECK(readValue(block)); + CHECK(readValue(file, block)); if (block == 0xFFFF) break; - file->addBlock(block); + subFile->addBlock(block); } } else if (tt == SubFile::TYP) { SubFile *typ = 0; @@ -118,9 +122,9 @@ IMG::IMG(const QString &fileName) : _file(fileName) typ = _typ; if (typ) { - _file.seek(offset + 0x20); + file.seek(offset + 0x20); for (int i = 0; i < 240; i++) { - CHECK(readValue(block)); + CHECK(readValue(file, block)); if (block == 0xFFFF) break; typ->addBlock(block); @@ -138,7 +142,7 @@ IMG::IMG(const QString &fileName) : _file(fileName) VectorTile *tile = it.value(); if (!tile->init()) { - qWarning("%s: %s: Invalid map tile", qPrintable(_file.fileName()), + qWarning("%s: %s: Invalid map tile", qPrintable(file.fileName()), qPrintable(it.key())); delete tile; continue; @@ -178,20 +182,20 @@ IMG::IMG(const QString &fileName) : _file(fileName) _valid = true; } -qint64 IMG::read(char *data, qint64 maxSize) +qint64 IMG::read(QFile &file, char *data, qint64 maxSize) { - qint64 ret = _file.read(data, maxSize); + qint64 ret = file.read(data, maxSize); if (_key) for (int i = 0; i < ret; i++) data[i] ^= _key; return ret; } -template bool IMG::readValue(T &val) +template bool IMG::readValue(QFile &file, T &val) { T data; - if (read((char*)&data, sizeof(T)) < (qint64)sizeof(T)) + if (read(file, (char*)&data, sizeof(T)) < (qint64)sizeof(T)) return false; val = qFromLittleEndian(data); @@ -199,11 +203,11 @@ template bool IMG::readValue(T &val) return true; } -bool IMG::readBlock(int blockNum, char *data) +bool IMG::readBlock(QFile &file, int blockNum, char *data) { - if (!_file.seek((quint64)blockNum << _blockBits)) + if (!file.seek((quint64)blockNum << _blockBits)) return false; - if (read(data, 1ULL<<_blockBits) < (qint64)(1ULL<<_blockBits)) + if (read(file, data, 1ULL<<_blockBits) < (qint64)(1ULL<<_blockBits)) return false; return true; diff --git a/src/map/IMG/img.h b/src/map/IMG/img.h index 4718c8c3..fd6a65e1 100644 --- a/src/map/IMG/img.h +++ b/src/map/IMG/img.h @@ -1,25 +1,26 @@ #ifndef IMG_H #define IMG_H -#include #include "mapdata.h" +class QFile; + class IMG : public MapData { public: IMG(const QString &fileName); - QString fileName() const {return _file.fileName();} + const QString &fileName() const {return _fileName;} private: friend class SubFile; unsigned blockBits() const {return _blockBits;} - bool readBlock(int blockNum, char *data); - qint64 read(char *data, qint64 maxSize); - template bool readValue(T &val); + bool readBlock(QFile &file, int blockNum, char *data); + qint64 read(QFile &file, char *data, qint64 maxSize); + template bool readValue(QFile &file, T &val); - QFile _file; + QString _fileName; quint8 _key; unsigned _blockBits; }; diff --git a/src/map/IMG/lblfile.cpp b/src/map/IMG/lblfile.cpp index da5bb06d..f4c3e96a 100644 --- a/src/map/IMG/lblfile.cpp +++ b/src/map/IMG/lblfile.cpp @@ -94,20 +94,23 @@ bool LBLFile::load(Handle &hdl, const RGNFile *rgn, Handle &rgnHdl) } if (hdrLen >= 0x19A) { - quint32 size, flags; - if (!(seek(hdl, _gmpOffset + 0x184) && readUInt32(hdl, _imgOffsetsOffset) - && readUInt32(hdl, size) && readUInt16(hdl, _imgOffsetsRecordSize) + quint32 offset, recordSize, size, flags; + if (!(seek(hdl, _gmpOffset + 0x184) && readUInt32(hdl, offset) + && readUInt32(hdl, size) && readUInt16(hdl, recordSize) && readUInt32(hdl, flags) && readUInt32(hdl, _imgOffset) && readUInt32(hdl, _imgSize))) return false; - _imgOffsetsCount = size ? size / _imgOffsetsRecordSize : 0; + quint32 count = size ? size / recordSize : 0; - quint32 maxId = _imgOffsetsCount - 1; + quint32 maxId = count - 1; _imgOffsetIdSize = 0; do { _imgOffsetIdSize++; maxId = maxId >> 8; } while (maxId != 0); + + if (!loadFiles(hdl, count, offset, recordSize)) + return false; } if (_encoding == 11) { @@ -301,31 +304,43 @@ Label LBLFile::label(Handle &hdl, quint32 offset, bool poi, bool capitalize) con } } -QByteArray LBLFile::readImage(Handle &hdl, quint32 id) const +bool LBLFile::loadFiles(Handle &hdl, quint32 count, quint32 offset, + quint32 recordSize) { - quint32 offset, nextOffset, size; + _rasters.resize(count); - if (id >= _imgOffsetsCount) - return QByteArray(); + for (quint32 i = 0; i < count; i++) { + quint32 currentOffset, nextOffset, size; - if (!(seek(hdl, _imgOffsetsOffset + id * _imgOffsetsRecordSize) - && readVUInt32(hdl, _imgOffsetsRecordSize, offset))) - return QByteArray(); - if (id == _imgOffsetsCount - 1) - nextOffset = _imgSize; - else { - if (!readVUInt32(hdl, _imgOffsetsRecordSize, nextOffset)) - return QByteArray(); + if (!(seek(hdl, offset + i * recordSize) + && readVUInt32(hdl, recordSize, currentOffset))) + return false; + if (i == count - 1) + nextOffset = _imgSize; + else { + if (!readVUInt32(hdl, recordSize, nextOffset)) + return false; + } + size = nextOffset - currentOffset; + + _rasters[i] = File(currentOffset, size); } - size = nextOffset - offset; - if (!seek(hdl, _imgOffset + offset)) - return QByteArray(); - QByteArray ba; - ba.resize(size); - for (quint32 i = 0; i < size; i++) - if (!readUInt8(hdl, *(ba.data() + i))) - return QByteArray(); - - return ba; + return true; +} + +QImage LBLFile::readImage(Handle &hdl, quint32 id) const +{ + if (id >= (quint32)_rasters.size()) + return QImage(); + + if (!seek(hdl, _imgOffset + _rasters.at(id).offset)) + return QImage(); + QByteArray ba; + ba.resize(_rasters.at(id).size); + for (int i = 0; i < ba.size(); i++) + if (!readUInt8(hdl, *(ba.data() + i))) + return QImage(); + + return QImage::fromData(ba); } diff --git a/src/map/IMG/lblfile.h b/src/map/IMG/lblfile.h index 222a2772..a2d7a020 100644 --- a/src/map/IMG/lblfile.h +++ b/src/map/IMG/lblfile.h @@ -1,6 +1,7 @@ #ifndef LBLFILE_H #define LBLFILE_H +#include #include "common/textcodec.h" #include "subfile.h" #include "label.h" @@ -13,16 +14,16 @@ class LBLFile : public SubFile public: LBLFile(IMG *img) : SubFile(img), _huffmanText(0), _table(0), _offset(0), _size(0), - _poiOffset(0), _poiSize(0), _imgOffsetsCount(0), _imgOffsetIdSize(0), - _poiMultiplier(0), _multiplier(0), _encoding(0) {} + _poiOffset(0), _poiSize(0), _imgOffsetIdSize(0), _poiMultiplier(0), + _multiplier(0), _encoding(0) {} LBLFile(const QString *path) : SubFile(path), _huffmanText(0), _table(0), _offset(0), _size(0), - _poiOffset(0), _poiSize(0), _imgOffsetsCount(0), _imgOffsetIdSize(0), - _poiMultiplier(0), _multiplier(0), _encoding(0) {} + _poiOffset(0), _poiSize(0), _imgOffsetIdSize(0), _poiMultiplier(0), + _multiplier(0), _encoding(0) {} LBLFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset), _huffmanText(0), _table(0), _offset(0), _size(0), _poiOffset(0), - _poiSize(0), _imgOffsetsCount(0), _imgOffsetIdSize(0), _poiMultiplier(0), - _multiplier(0), _encoding(0) {} + _poiSize(0), _imgOffsetIdSize(0), _poiMultiplier(0), _multiplier(0), + _encoding(0) {} ~LBLFile(); bool load(Handle &hdl, const RGNFile *rgn, Handle &rgnHdl); @@ -32,13 +33,23 @@ public: bool capitalize = true) const; quint8 imageIdSize() const {return _imgOffsetIdSize;} - QByteArray readImage(Handle &hdl, quint32 id) const; + QImage readImage(Handle &hdl, quint32 id) const; private: + struct File { + File() : offset(0), size(0) {} + File(quint32 offset, quint32 size) : offset(offset), size(size) {} + + quint32 offset; + quint32 size; + }; + Label str2label(const QVector &str, bool capitalize) const; Label label6b(Handle &hdl, quint32 offset, bool capitalize) const; Label label8b(Handle &hdl, quint32 offset, bool capitalize) const; Label labelHuffman(Handle &hdl, quint32 offset, bool capitalize) const; + bool loadFiles(Handle &hdl, quint32 count, quint32 offset, + quint32 recordSize); HuffmanText *_huffmanText; quint32 *_table; @@ -47,15 +58,14 @@ private: quint32 _size; quint32 _poiOffset; quint32 _poiSize; - quint32 _imgOffsetsOffset; - quint32 _imgOffsetsCount; - quint32 _imgOffsetsRecordSize; quint32 _imgOffset; quint32 _imgSize; quint8 _imgOffsetIdSize; quint8 _poiMultiplier; quint8 _multiplier; quint8 _encoding; + + QVector _rasters; }; #endif // LBLFILE_H diff --git a/src/map/IMG/mapdata.h b/src/map/IMG/mapdata.h index 49a615ce..ab1b3848 100644 --- a/src/map/IMG/mapdata.h +++ b/src/map/IMG/mapdata.h @@ -60,7 +60,7 @@ public: void load(); void clear(); - virtual QString fileName() const = 0; + virtual const QString &fileName() const = 0; bool isValid() const {return _valid;} QString errorString() const {return _errorString;} diff --git a/src/map/IMG/raster.h b/src/map/IMG/raster.h index b5b70991..1d31095f 100644 --- a/src/map/IMG/raster.h +++ b/src/map/IMG/raster.h @@ -2,34 +2,37 @@ #define RASTER_H #include -#include #include #include "common/rectc.h" #include "common/garmin.h" +class LBLFile; + class Raster { public: - Raster() {} - Raster(const QByteArray &img, const QRect &rect) : _img(img), _rect(rect) {} + Raster() : _lbl(0) {} + Raster(const LBLFile *lbl, quint32 id, const QRect &rect) + : _lbl(lbl), _id(id), _rect(rect) {} - const QByteArray &img() const {return _img;} + const LBLFile *lbl() const {return _lbl;} + quint32 id() const {return _id;} const RectC rect() const { return RectC(Coordinates(toWGS32(_rect.left()), toWGS32(_rect.top())), Coordinates(toWGS32(_rect.right()), toWGS32(_rect.bottom()))); } - bool isValid() const {return !_img.isNull();} + bool isValid() const {return (_lbl != 0);} private: - QByteArray _img; + const LBLFile *_lbl; + quint32 _id; QRect _rect; }; #ifndef QT_NO_DEBUG inline QDebug operator<<(QDebug dbg, const Raster &raster) { - dbg.nospace() << "Raster(" << raster.img().size() << ", " << raster.rect() - << ")"; + dbg.nospace() << "Raster(" << raster.rect() << ")"; return dbg.space(); } #endif // QT_NO_DEBUG diff --git a/src/map/IMG/rastertile.cpp b/src/map/IMG/rastertile.cpp index b762958d..6a5dc1d9 100644 --- a/src/map/IMG/rastertile.cpp +++ b/src/map/IMG/rastertile.cpp @@ -5,6 +5,7 @@ #include "textpointitem.h" #include "bitmapline.h" #include "style.h" +#include "lblfile.h" #include "rastertile.h" @@ -224,8 +225,11 @@ void RasterTile::drawPolygons(QPainter *painter) QPointF br(_map->ll2xy(r.bottomRight())); QSize size(QRectF(tl, br).toRect().size()); - painter->drawImage(tl, QImage::fromData(poly.raster.img()). - scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + SubFile::Handle hdl(poly.raster.lbl()); + QImage img(poly.raster.lbl()->readImage(hdl, poly.raster.id())); + + painter->drawImage(tl, img.scaled(size, Qt::IgnoreAspectRatio, + Qt::SmoothTransformation)); //painter->setPen(Qt::blue); //painter->setBrush(Qt::NoBrush); diff --git a/src/map/IMG/rgnfile.cpp b/src/map/IMG/rgnfile.cpp index 08f48d94..7be1996e 100644 --- a/src/map/IMG/rgnfile.cpp +++ b/src/map/IMG/rgnfile.cpp @@ -30,7 +30,7 @@ RGNFile::~RGNFile() } bool RGNFile::readClassFields(Handle &hdl, SegmentType segmentType, - MapData::Poly *poly, const LBLFile *lbl, Handle *lblHdl) const + MapData::Poly *poly, const LBLFile *lbl) const { quint8 flags; quint32 rs; @@ -67,8 +67,8 @@ bool RGNFile::readClassFields(Handle &hdl, SegmentType segmentType, && readUInt32(hdl, bottom) && readUInt32(hdl, left))) return false; - poly->raster = Raster(lbl->readImage(*lblHdl, id), - QRect(QPoint(left, top), QPoint(right, bottom))); + poly->raster = Raster(lbl, id, QRect(QPoint(left, top), QPoint(right, + bottom))); rs -= lbl->imageIdSize() + 16; } @@ -336,8 +336,7 @@ bool RGNFile::extPolyObjects(Handle &hdl, const SubDiv *subdiv, quint32 shift, if (subtype & 0x20 && !readUInt24(hdl, labelPtr)) return false; - if (subtype & 0x80 && !readClassFields(hdl, segmentType, &poly, lbl, - &lblHdl)) + if (subtype & 0x80 && !readClassFields(hdl, segmentType, &poly, lbl)) return false; if (subtype & 0x40 && !skipLclFields(hdl, segmentType == Line ? _linesLclFlags : _polygonsLclFlags)) diff --git a/src/map/IMG/rgnfile.h b/src/map/IMG/rgnfile.h index e1a08db6..8567ce86 100644 --- a/src/map/IMG/rgnfile.h +++ b/src/map/IMG/rgnfile.h @@ -61,7 +61,7 @@ private: QMap segments(Handle &hdl, SubDiv *subdiv) const; bool readClassFields(Handle &hdl, SegmentType segmentType, - MapData::Poly *poly = 0, const LBLFile *lbl = 0, Handle *lblHdl = 0) const; + MapData::Poly *poly = 0, const LBLFile *lbl = 0) const; bool skipLclFields(Handle &hdl, const quint32 flags[3]) const; bool skipGblFields(Handle &hdl, quint32 flags) const; diff --git a/src/map/IMG/subfile.cpp b/src/map/IMG/subfile.cpp index 108f9ac0..12fd33a5 100644 --- a/src/map/IMG/subfile.cpp +++ b/src/map/IMG/subfile.cpp @@ -7,38 +7,37 @@ bool SubFile::seek(Handle &handle, quint32 pos) const { - if (handle._file) { - int blockNum = pos >> BLOCK_BITS; - - if (handle._blockNum != blockNum) { - if (!handle._file->seek((quint64)blockNum << BLOCK_BITS)) - return false; - if (handle._file->read(handle._data.data(), (1<blockBits(); int blockNum = pos >> blockBits; if (handle._blockNum != blockNum) { if (blockNum >= _blocks->size()) return false; - if (!_img->readBlock(_blocks->at(blockNum), handle._data.data())) + if (!_img->readBlock(handle._file, _blocks->at(blockNum), + handle._data.data())) return false; handle._blockNum = blockNum; } handle._blockPos = mod2n(pos, 1U<> BLOCK_BITS; - return true; + if (handle._blockNum != blockNum) { + if (!handle._file.seek((quint64)blockNum << BLOCK_BITS)) + return false; + if (handle._file.read(handle._data.data(), (1<_path) { - _file = new QFile(*(subFile->_path)); - _file->open(QIODevice::ReadOnly); + if (!subFile) + return; + + if (subFile->_path) { + _file.setFileName(*(subFile->_path)); _data.resize(1U<_img->fileName()); _data.resize(1U<_img->blockBits()); + } + + _file.open(QIODevice::ReadOnly); } - ~Handle() {delete _file;} private: friend class SubFile; - QFile *_file; + QFile _file; QByteArray _data; int _blockNum; int _blockPos;