1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-24 11:45:53 +01:00

Huffman encoded labels

+ more or less related fixes/refactoring
This commit is contained in:
Martin Tůma 2020-11-10 00:58:19 +01:00
parent 0644bb72a0
commit f139d33502
23 changed files with 660 additions and 309 deletions

View File

@ -93,8 +93,10 @@ HEADERS += src/common/config.h \
src/map/IMG/bitstream.h \ src/map/IMG/bitstream.h \
src/map/IMG/deltastream.h \ src/map/IMG/deltastream.h \
src/map/IMG/gmap.h \ src/map/IMG/gmap.h \
src/map/IMG/huffmanbuffer.h \
src/map/IMG/huffmanstream.h \ src/map/IMG/huffmanstream.h \
src/map/IMG/huffmantable.h \ src/map/IMG/huffmantable.h \
src/map/IMG/huffmantext.h \
src/map/IMG/nodfile.h \ src/map/IMG/nodfile.h \
src/map/IMG/mapdata.h \ src/map/IMG/mapdata.h \
src/map/IMG/rastertile.h \ src/map/IMG/rastertile.h \
@ -258,8 +260,10 @@ SOURCES += src/main.cpp \
src/map/IMG/bitstream.cpp \ src/map/IMG/bitstream.cpp \
src/map/IMG/deltastream.cpp \ src/map/IMG/deltastream.cpp \
src/map/IMG/gmap.cpp \ src/map/IMG/gmap.cpp \
src/map/IMG/huffmanbuffer.cpp \
src/map/IMG/huffmanstream.cpp \ src/map/IMG/huffmanstream.cpp \
src/map/IMG/huffmantable.cpp \ src/map/IMG/huffmantable.cpp \
src/map/IMG/huffmantext.cpp \
src/map/IMG/nodfile.cpp \ src/map/IMG/nodfile.cpp \
src/map/IMG/mapdata.cpp \ src/map/IMG/mapdata.cpp \
src/map/IMG/rastertile.cpp \ src/map/IMG/rastertile.cpp \

View File

@ -15,4 +15,15 @@ inline double toWGS24(qint32 v)
return toWGS32(LS(v, 8)); return toWGS32(LS(v, 8));
} }
inline quint8 vs(const quint8 b0)
{
static const quint8 sizes[] = {4, 1, 2, 1, 3, 1, 2, 1};
return sizes[b0 & 0x07];
}
inline quint8 bs(const quint8 val)
{
return (val + 7) >> 3;
}
#endif // GARMIN_H #endif // GARMIN_H

View File

@ -81,7 +81,11 @@ bool GMAP::loadTile(const QDir &dir, bool baseMap)
QFileInfoList ml = dir.entryInfoList(QDir::Files); QFileInfoList ml = dir.entryInfoList(QDir::Files);
for (int i = 0; i < ml.size(); i++) { for (int i = 0; i < ml.size(); i++) {
const QFileInfo &fi = ml.at(i); const QFileInfo &fi = ml.at(i);
tile->addFile(fi.absoluteFilePath(), tileType(fi.suffix())); SubFile::Type tt = tileType(fi.suffix());
if (VectorTile::isTileFile(tt)) {
_files.append(new QString(fi.absoluteFilePath()));
tile->addFile(_files.last(), tt);
}
} }
if (!tile->init()) { if (!tile->init()) {
@ -131,8 +135,10 @@ GMAP::GMAP(const QString &fileName) : _fileName(fileName)
fi.absoluteFilePath() == baseMap.absoluteFilePath()); fi.absoluteFilePath() == baseMap.absoluteFilePath());
} }
if (baseDir.exists(typFilePath)) if (baseDir.exists(typFilePath)) {
_typ = new SubFile(baseDir.filePath(typFilePath)); _files.append(new QString(baseDir.filePath(typFilePath)));
_typ = new SubFile(_files.last());
}
if (!_tileTree.Count()) if (!_tileTree.Count())
_errorString = "No usable map tile found"; _errorString = "No usable map tile found";
@ -140,6 +146,11 @@ GMAP::GMAP(const QString &fileName) : _fileName(fileName)
_valid = true; _valid = true;
} }
GMAP::~GMAP()
{
qDeleteAll(_files);
}
bool GMAP::isGMAP(const QString &path) bool GMAP::isGMAP(const QString &path)
{ {
QFile file(path); QFile file(path);

View File

@ -10,6 +10,7 @@ class GMAP : public MapData
{ {
public: public:
GMAP(const QString &fileName); GMAP(const QString &fileName);
~GMAP();
QString fileName() const {return _fileName;} QString fileName() const {return _fileName;}
@ -25,6 +26,7 @@ private:
bool loadTile(const QDir &dir, bool baseMap); bool loadTile(const QDir &dir, bool baseMap);
QString _fileName; QString _fileName;
QList<const QString*> _files;
}; };
#endif // GMAP_H #endif // GMAP_H

View File

@ -0,0 +1,24 @@
#include "rgnfile.h"
#include "huffmanbuffer.h"
bool HuffmanBuffer::load(const RGNFile *rgn, SubFile::Handle &rgnHdl)
{
quint32 recordSize, recordOffset = rgn->dictOffset();
for (int i = 0; i <= _id; i++) {
if (!rgn->seek(rgnHdl, recordOffset))
return false;
if (!rgn->readVUInt32(rgnHdl, recordSize))
return false;
recordOffset = rgn->pos(rgnHdl) + recordSize;
if (recordOffset > rgn->dictOffset() + rgn->dictSize())
return false;
};
resize(recordSize);
for (int i = 0; i < QByteArray::size(); i++)
if (!rgn->readUInt8(rgnHdl, *((quint8*)(data() + i))))
return false;
return true;
}

View File

@ -0,0 +1,21 @@
#ifndef HUFFMANBUFFER_H
#define HUFFMANBUFFER_H
#include <QByteArray>
#include "subfile.h"
class RGNFile;
class HuffmanBuffer : public QByteArray
{
public:
HuffmanBuffer(quint8 id) : _id(id) {}
quint8 id() const {return _id;}
bool load(const RGNFile *rgn, SubFile::Handle &rgnHdl);
private:
quint8 _id;
};
#endif // HUFFMANBUFFER_H

View File

@ -1,17 +1,7 @@
#include "common/garmin.h"
#include "huffmantable.h" #include "huffmantable.h"
static quint8 vs(const quint8 b0)
{
static const quint8 sizes[] = {4, 1, 2, 1, 3, 1, 2, 1};
return sizes[b0 & 0x07];
}
static inline quint8 bs(const quint8 val)
{
return (val + 7) >> 3;
}
static inline quint32 readVUint32(const quint8 *buffer, quint32 bytes) static inline quint32 readVUint32(const quint8 *buffer, quint32 bytes)
{ {
quint32 val = 0; quint32 val = 0;
@ -22,10 +12,9 @@ static inline quint32 readVUint32(const quint8 *buffer, quint32 bytes)
return val; return val;
} }
bool HuffmanTable::load(const SubFile &file, SubFile::Handle &hdl, bool HuffmanTable::load(const RGNFile *rgn, SubFile::Handle &rgnHdl)
quint32 offset, quint32 size, quint32 id)
{ {
if (!getBuffer(file, hdl, offset, size, id)) if (!_buffer.load(rgn, rgnHdl))
return false; return false;
_s0 = (quint8)_buffer.at(0) & 0x0F; _s0 = (quint8)_buffer.at(0) & 0x0F;
@ -42,31 +31,6 @@ bool HuffmanTable::load(const SubFile &file, SubFile::Handle &hdl,
_s10 = _s14 + _s1c * _s1d; _s10 = _s14 + _s1c * _s1d;
_s18 = _s10 + (_s1 << _s0); _s18 = _s10 + (_s1 << _s0);
_id = id;
return true;
}
bool HuffmanTable::getBuffer(const SubFile &file, SubFile::Handle &hdl,
quint32 offset, quint32 size, quint8 id)
{
quint32 recordSize, recordOffset = offset;
for (int i = 0; i <= id; i++) {
if (!file.seek(hdl, recordOffset))
return false;
if (!file.readVUInt32(hdl, recordSize))
return false;
recordOffset = file.pos(hdl) + recordSize;
if (recordOffset > offset + size)
return false;
};
_buffer.resize(recordSize);
for (int i = 0; i < _buffer.size(); i++)
if (!file.readUInt8(hdl, *((quint8*)(_buffer.data() + i))))
return false;
return true; return true;
} }

View File

@ -1,31 +1,26 @@
#ifndef HUFFMANTABLE_H #ifndef HUFFMANTABLE_H
#define HUFFMANTABLE_H #define HUFFMANTABLE_H
#include "subfile.h" #include "huffmanbuffer.h"
class RGNFile;
class HuffmanTable { class HuffmanTable {
public: public:
HuffmanTable() : _s2(0) {} HuffmanTable(quint8 id) : _buffer(id) {}
bool load(const SubFile &file, SubFile::Handle &hdl, quint32 offset, bool load(const RGNFile *rgn, SubFile::Handle &rgnHdl);
quint32 size, quint32 id);
bool isNull() const {return _s2 == 0;}
quint8 maxSymbolSize() const {return _s2;} quint8 maxSymbolSize() const {return _s2;}
quint32 symbol(quint32 data, quint8 &size) const; quint32 symbol(quint32 data, quint8 &size) const;
quint8 id() const {return _id;} quint8 id() const {return _buffer.id();}
private: private:
bool getBuffer(const SubFile &file, SubFile::Handle &hdl, quint32 offset, HuffmanBuffer _buffer;
quint32 size, quint8 id);
QByteArray _buffer;
quint8 _s0, _s1, _s2, _s3; quint8 _s0, _s1, _s2, _s3;
quint8 *_s10, *_s14, *_s18; quint8 *_s10, *_s14, *_s18;
quint8 _s1c, _s1d, _s1e, _s1f, _s20; quint8 _s1c, _s1d, _s1e, _s1f, _s20;
quint16 _s22; quint16 _s22;
quint8 _id;
}; };
#endif // HUFFMANTABLE_H #endif // HUFFMANTABLE_H

169
src/map/IMG/huffmantext.cpp Normal file
View File

@ -0,0 +1,169 @@
#include "common/garmin.h"
#include "subfile.h"
#include "huffmantext.h"
static inline quint32 readVUint32(const quint8 *buffer, quint32 bytes)
{
quint32 val = 0;
for (quint32 i = 0; i < bytes; i++)
val = val | (quint32)*(buffer - i) << ((bytes - i - 1) << 3);
return val;
}
bool HuffmanText::load(const RGNFile *rgn, SubFile::Handle &rgnHdl)
{
if (!_buffer.load(rgn, rgnHdl))
return false;
quint8 *buffer = (quint8 *)_buffer.constData();
_b0 = buffer[0];
_b1 = buffer[1];
_b2 = buffer[2];
_b3 = buffer[3];
_vs = vs(buffer[4]);
_bs3 = bs(_b3);
_bs1 = bs(_b1);
_mul = _bs1 + 1 + _vs;
_bp1 = buffer + _vs + 4;
_bp2 = _bp1 + _mul * _b2;
_bp3 = _bp2 + ((_bs3 + 1) << (_b0 & 0xf));
_bp4 = _bp3 - 1;
return true;
}
bool HuffmanText::fetch(const SubFile *file, SubFile::Handle &hdl,
quint32 &data, quint32 &bits, quint32 &usedBits, quint32 &usedData) const
{
quint32 rs, ls, old;
bits = _b1 - bits;
if (usedBits < bits) {
old = usedBits ? usedData >> (0x20 - usedBits) : 0;
if (!file->readVUInt32SW(hdl, 4, usedData))
return false;
ls = bits - usedBits;
rs = 0x20 - (bits - usedBits);
old = usedData >> rs | old << ls;
} else {
ls = bits;
rs = usedBits - bits;
old = usedData >> (0x20 - bits);
}
usedData = usedData << ls;
data = data | old << (0x20 - _b1);
usedBits = rs;
return true;
}
bool HuffmanText::decode(const SubFile *file, SubFile::Handle &hdl,
QVector<quint8> &str) const
{
quint32 bits = 0;
quint32 data = 0;
quint32 usedBits = 0;
quint32 usedData = 0;
quint32 ls = 8;
quint32 lo = _vs * 8 - 8;
while (true) {
if (!fetch(file, hdl, data, bits, usedBits, usedData))
return false;
quint32 off = (data >> (0x20 - (_b0 & 0xf))) * (_bs3 + 1);
quint32 sb = _bp2[off];
quint32 ss = 0;
quint32 sym = _b2 - 1;
quint32 size;
if ((_b0 & 0xf) == 0 || (sb & 1) == 0) {
if ((_b0 & 0xf) != 0) {
ss = sb >> 1;
sym = _bp2[off + 1];
}
quint8 *tp = _bp1 + ss * _mul;
quint32 sd = data >> (0x20 - _b1);
while (ss < sym) {
quint32 cnt = (sym + 1 + ss) >> 1;
quint8 *prev = _bp1 + cnt * _mul;
quint32 nd = readVUint32(prev + _bs1 - 1, _bs1);
if (sd <= nd) {
sym = cnt - (sd < nd);
if (sd < nd) {
prev = tp;
cnt = ss;
}
}
tp = prev;
ss = cnt;
}
quint32 o1 = readVUint32(tp + _bs1 - 1, _bs1);
tp = tp + _bs1;
quint32 o2 = readVUint32(tp + _vs, _vs);
size = tp[0];
quint32 os = (sd - o1) >> (_b1 - size);
if ((_b0 & 0x10) == 0) {
sym = readVUint32(_bp4 + (o2 + 1 + os) * _bs3, _bs3);
} else {
quint32 v = (os + o2) * _b3;
quint32 idx = v >> 3;
quint32 r = v & 7;
quint32 shift = 8 - r;
sym = _bp3[idx] >> r;
if (shift < _b3) {
quint32 sz = bs(_b3 - shift);
quint32 val = readVUint32(_bp3 + idx + sz, sz);
sym = sym | val << shift;
}
}
} else {
sym = readVUint32(_bp2 + off + _bs3, _bs3);
size = (sb >> 1);
}
if (_b1 < size)
return false;
data = data << size;
bits = _b1 - size;
if ((_b3 & 7) == 0) {
for (quint32 i = 0; i < (_b3 >> 3); i++) {
str.append((quint8)sym);
if (((quint8)sym == '\0'))
return true;
sym = sym >> 8;
}
} else {
quint32 cnt = _b3;
if (ls <= _b3) {
do {
quint32 shift = ls;
lo = sym << (8 - shift) | (quint32)((quint8)lo >> shift);
sym = sym >> shift;
str.append((uchar)lo);
if (((uchar)lo == '\0'))
return true;
cnt = cnt - ls;
ls = 8;
} while (7 < cnt);
ls = 8;
}
if (cnt != 0) {
lo = sym << (8 - cnt) | (quint32)((quint8)lo >> cnt);
ls = ls - cnt;
}
}
}
}

35
src/map/IMG/huffmantext.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef HUFFMANTEXT_H
#define HUFFMANTEXT_H
#include "huffmanbuffer.h"
class HuffmanText
{
public:
HuffmanText() : _buffer(0) {}
bool load(const RGNFile *rgn, SubFile::Handle &rgnHdl);
bool decode(const SubFile *file, SubFile::Handle &hdl,
QVector<quint8> &str) const;
private:
bool fetch(const SubFile *file, SubFile::Handle &hdl, quint32 &data,
quint32 &bits, quint32 &usedBits, quint32 &usedData) const;
HuffmanBuffer _buffer;
quint32 _b0;
quint32 _b1;
quint32 _b2;
quint32 _b3;
quint32 _vs;
quint32 _bs3;
quint32 _bs1;
quint32 _mul;
quint8 *_bp1;
quint8 *_bp2;
quint8 *_bp3;
quint8 *_bp4;
};
#endif // HUFFMANTEXT_H

View File

@ -1,4 +1,6 @@
#include <QTextCodec> #include <QTextCodec>
#include "huffmantext.h"
#include "rgnfile.h"
#include "lblfile.h" #include "lblfile.h"
enum Charset {Normal, Symbol, Special}; enum Charset {Normal, Symbol, Special};
@ -55,21 +57,48 @@ static QString capitalized(const QString &str)
} }
bool LBLFile::init(Handle &hdl) LBLFile::~LBLFile()
{ {
quint16 codepage; delete _huffmanText;
quint8 multiplier, poiMultiplier; delete _table;
}
if (!(seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset) bool LBLFile::load(Handle &hdl, const RGNFile *rgn, Handle &rgnHdl)
&& readUInt32(hdl, _size) && readUInt8(hdl, multiplier) {
quint16 hdrLen, codepage;
if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen)
&& seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset)
&& readUInt32(hdl, _size) && readUInt8(hdl, _multiplier)
&& readUInt8(hdl, _encoding) && seek(hdl, _gmpOffset + 0x57) && readUInt8(hdl, _encoding) && seek(hdl, _gmpOffset + 0x57)
&& readUInt32(hdl, _poiOffset) && readUInt32(hdl, _poiSize) && readUInt32(hdl, _poiOffset) && readUInt32(hdl, _poiSize)
&& readUInt8(hdl, poiMultiplier) && seek(hdl, _gmpOffset + 0xAA) && readUInt8(hdl, _poiMultiplier) && seek(hdl, _gmpOffset + 0xAA)
&& readUInt16(hdl, codepage))) && readUInt16(hdl, codepage)))
return false; return false;
_multiplier = 1<<multiplier; if (hdrLen >= 0x132) {
_poiMultiplier = 1<<poiMultiplier; quint32 offset, size;
quint16 recordSize;
if (!(seek(hdl, _gmpOffset + 0x124) && readUInt32(hdl, offset)
&& readUInt32(hdl, size) && readUInt16(hdl, recordSize)))
return false;
if (size && recordSize) {
_table = new quint32[size / recordSize];
if (!seek(hdl, offset))
return false;
for (quint32 i = 0; i < size / recordSize; i++) {
if (!readVUInt32(hdl, recordSize, _table[i]))
return false;
}
}
}
if (_encoding == 11) {
_huffmanText = new HuffmanText();
if (!_huffmanText->load(rgn, rgnHdl))
return false;
}
if (codepage == 65001) if (codepage == 65001)
_codec = QTextCodec::codecForName("UTF-8"); _codec = QTextCodec::codecForName("UTF-8");
@ -82,6 +111,14 @@ bool LBLFile::init(Handle &hdl)
return true; return true;
} }
void LBLFile::clear()
{
delete _huffmanText;
delete _table;
_huffmanText = 0;
_table = 0;
}
Label LBLFile::label6b(Handle &hdl, quint32 offset, bool capitalize) const Label LBLFile::label6b(Handle &hdl, quint32 offset, bool capitalize) const
{ {
Label::Shield::Type shieldType = Label::Shield::None; Label::Shield::Type shieldType = Label::Shield::None;
@ -135,20 +172,16 @@ Label LBLFile::label6b(Handle &hdl, quint32 offset, bool capitalize) const
} }
} }
Label LBLFile::label8b(Handle &hdl, quint32 offset, bool capitalize) const Label LBLFile::str2label(const QVector<quint8> &str, bool capitalize) const
{ {
Label::Shield::Type shieldType = Label::Shield::None; Label::Shield::Type shieldType = Label::Shield::None;
QByteArray label, shieldLabel; QByteArray label, shieldLabel;
QByteArray *bap = &label; QByteArray *bap = &label;
quint8 c;
if (!seek(hdl, offset)) for (int i = 0; i < str.size(); i++) {
return Label(); const quint8 &c = str.at(i);
while (true) { if (c == 0 || c == 0x1d)
if (!readUInt8(hdl, c))
return Label();
if (!c || c == 0x1d)
break; break;
if (c == 0x1c) if (c == 0x1c)
@ -158,7 +191,7 @@ Label LBLFile::label8b(Handle &hdl, quint32 offset, bool capitalize) const
bap = &label; bap = &label;
else else
bap->append(' '); bap->append(' ');
} else if (c <= 0x07) { } else if (c < 0x07) {
shieldType = static_cast<Label::Shield::Type>(c); shieldType = static_cast<Label::Shield::Type>(c);
bap = &shieldLabel; bap = &shieldLabel;
} else if (bap == &shieldLabel && c == 0x20) { } else if (bap == &shieldLabel && c == 0x20) {
@ -175,21 +208,74 @@ Label LBLFile::label8b(Handle &hdl, quint32 offset, bool capitalize) const
Label::Shield(shieldType, shieldText)); Label::Shield(shieldType, shieldText));
} }
Label LBLFile::label(Handle &hdl, quint32 offset, bool poi, bool capitalize) Label LBLFile::label8b(Handle &hdl, quint32 offset, bool capitalize) const
{ {
if (!_multiplier && !init(hdl)) QVector<quint8> str;
return QString(); quint8 c;
if (!seek(hdl, offset))
return Label();
do {
if (!readUInt8(hdl, c))
return Label();
str.append(c);
} while (c);
return str2label(str, capitalize);
}
Label LBLFile::labelHuffman(Handle &hdl, quint32 offset, bool capitalize) const
{
QVector<quint8> str;
if (!seek(hdl, offset))
return Label();
if (!_huffmanText->decode(this, hdl, str))
return Label();
if (!_table)
return str2label(str, capitalize);
QVector<quint8> str2;
for (int i = 0; i < str.size(); i++) {
quint32 val = _table[str.at(i)];
if (val) {
if (!seek(hdl, _offset + ((val & 0x7fffff) << _multiplier)))
return Label();
if (str2.size() && str2.back() == '\0')
str2[str2.size() - 1] = ' ';
else if (str2.size())
str2.append(' ');
if (!_huffmanText->decode(this, hdl, str2))
return Label();
} else {
if (str.at(i) == 7) {
str2.append(0);
break;
}
if (str2.size() && str2.back() == '\0')
str2[str2.size() - 1] = ' ';
str2.append(str.at(i));
}
}
return str2label(str2, capitalize);
}
Label LBLFile::label(Handle &hdl, quint32 offset, bool poi, bool capitalize) const
{
quint32 labelOffset; quint32 labelOffset;
if (poi) { if (poi) {
quint32 poiOffset; quint32 poiOffset;
if (!(_poiSize >= offset * _poiMultiplier if (!(_poiSize >= (offset << _poiMultiplier)
&& seek(hdl, _poiOffset + offset * _poiMultiplier) && seek(hdl, _poiOffset + (offset << _poiMultiplier))
&& readUInt24(hdl, poiOffset) && (poiOffset & 0x3FFFFF))) && readUInt24(hdl, poiOffset) && (poiOffset & 0x3FFFFF)))
return QString(); return QString();
labelOffset = _offset + (poiOffset & 0x3FFFFF) * _multiplier; labelOffset = _offset + ((poiOffset & 0x3FFFFF) << _multiplier);
} else } else
labelOffset = _offset + offset * _multiplier; labelOffset = _offset + (offset << _multiplier);
if (labelOffset > _offset + _size) if (labelOffset > _offset + _size)
return QString(); return QString();
@ -200,6 +286,8 @@ Label LBLFile::label(Handle &hdl, quint32 offset, bool poi, bool capitalize)
case 9: case 9:
case 10: case 10:
return label8b(hdl, labelOffset, capitalize); return label8b(hdl, labelOffset, capitalize);
case 11:
return labelHuffman(hdl, labelOffset, capitalize);
default: default:
return Label(); return Label();
} }

View File

@ -5,28 +5,40 @@
#include "label.h" #include "label.h"
class QTextCodec; class QTextCodec;
class HuffmanText;
class RGNFile;
class LBLFile : public SubFile class LBLFile : public SubFile
{ {
public: public:
LBLFile(IMG *img) LBLFile(IMG *img)
: SubFile(img), _codec(0), _offset(0), _size(0), _poiOffset(0), : SubFile(img), _huffmanText(0), _table(0), _codec(0), _offset(0),
_poiSize(0), _poiMultiplier(0), _multiplier(0), _encoding(0) {} _size(0), _poiOffset(0), _poiSize(0), _poiMultiplier(0), _multiplier(0),
LBLFile(const QString &path) _encoding(0) {}
: SubFile(path), _codec(0), _offset(0), _size(0), _poiOffset(0), LBLFile(const QString *path)
_poiSize(0), _poiMultiplier(0), _multiplier(0), _encoding(0) {} : SubFile(path), _huffmanText(0), _table(0), _codec(0), _offset(0),
_size(0), _poiOffset(0), _poiSize(0), _poiMultiplier(0), _multiplier(0),
_encoding(0) {}
LBLFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset), LBLFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset),
_codec(0), _offset(0), _size(0), _poiOffset(0), _poiSize(0), _huffmanText(0), _table(0), _codec(0), _offset(0), _size(0),
_poiMultiplier(0), _multiplier(0), _encoding(0) {} _poiOffset(0), _poiSize(0), _poiMultiplier(0), _multiplier(0),
_encoding(0) {}
~LBLFile();
bool load(Handle &hdl, const RGNFile *rgn, Handle &rgnHdl);
void clear();
Label label(Handle &hdl, quint32 offset, bool poi = false, Label label(Handle &hdl, quint32 offset, bool poi = false,
bool capitalize = true); bool capitalize = true) const;
private: private:
bool init(Handle &hdl); Label str2label(const QVector<quint8> &str, bool capitalize) const;
Label label6b(Handle &hdl, quint32 offset, bool capitalize) const; Label label6b(Handle &hdl, quint32 offset, bool capitalize) const;
Label label8b(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;
HuffmanText *_huffmanText;
quint32 *_table;
QTextCodec *_codec; QTextCodec *_codec;
quint32 _offset; quint32 _offset;

View File

@ -107,7 +107,7 @@ void MapData::load()
else { else {
QString typFile(ProgramPaths::typFile()); QString typFile(ProgramPaths::typFile());
if (!typFile.isEmpty()) { if (!typFile.isEmpty()) {
SubFile typ(typFile); SubFile typ(&typFile);
_style = new Style(&typ); _style = new Style(&typ);
} else } else
_style = new Style(); _style = new Style();

View File

@ -3,6 +3,7 @@
#include "subdiv.h" #include "subdiv.h"
#include "nodfile.h" #include "nodfile.h"
#include "lblfile.h" #include "lblfile.h"
#include "rgnfile.h"
#include "netfile.h" #include "netfile.h"
@ -93,7 +94,7 @@ static bool seekToLine(BitStream4R &bs, quint8 line)
} }
static bool readLine(BitStream4R &bs, const SubDiv *subdiv, static bool readLine(BitStream4R &bs, const SubDiv *subdiv,
const HuffmanTable &table, IMG::Poly &poly) const HuffmanTable *table, MapData::Poly &poly)
{ {
quint32 v1, v2, v2b; quint32 v1, v2, v2b;
if (!bs.readVuint32SM(v1, v2, v2b)) if (!bs.readVuint32SM(v1, v2, v2b))
@ -113,7 +114,7 @@ static bool readLine(BitStream4R &bs, const SubDiv *subdiv,
poly.boundingRect = RectC(c, c); poly.boundingRect = RectC(c, c);
poly.points.append(QPointF(c.lon(), c.lat())); poly.points.append(QPointF(c.lon(), c.lat()));
HuffmanStreamR stream(bs, table); HuffmanStreamR stream(bs, *table);
if (!stream.init()) if (!stream.init())
return false; return false;
qint32 lonDelta, latDelta; qint32 lonDelta, latDelta;
@ -132,8 +133,8 @@ static bool readLine(BitStream4R &bs, const SubDiv *subdiv,
return stream.atEnd(); return stream.atEnd();
} }
static bool readNodeGeometry(NODFile *nod, SubFile::Handle &nodHdl, static bool readNodeGeometry(const NODFile *nod, SubFile::Handle &nodHdl,
NODFile::AdjacencyInfo &adj, IMG::Poly &poly, quint16 cnt = 0xFFFF) NODFile::AdjacencyInfo &adj, MapData::Poly &poly, quint16 cnt = 0xFFFF)
{ {
for (int i = 0; i <= cnt; i++) { for (int i = 0; i <= cnt; i++) {
int ret = nod->nextNode(nodHdl, adj); int ret = nod->nextNode(nodHdl, adj);
@ -151,7 +152,7 @@ static bool readNodeGeometry(NODFile *nod, SubFile::Handle &nodHdl,
return true; return true;
} }
static bool skipNodes(NODFile *nod, SubFile::Handle &nodHdl, static bool skipNodes(const NODFile *nod, SubFile::Handle &nodHdl,
NODFile::AdjacencyInfo &adj, int cnt) NODFile::AdjacencyInfo &adj, int cnt)
{ {
for (int i = 0; i < cnt; i++) for (int i = 0; i < cnt; i++)
@ -161,10 +162,10 @@ static bool skipNodes(NODFile *nod, SubFile::Handle &nodHdl,
return true; return true;
} }
static bool readShape(NODFile *nod, SubFile::Handle &nodHdl, static bool readShape(const NODFile *nod, SubFile::Handle &nodHdl,
NODFile::AdjacencyInfo &adj, BitStream4R &bs, const HuffmanTable &table, NODFile::AdjacencyInfo &adj, BitStream4R &bs, const HuffmanTable *table,
const SubDiv *subdiv, quint32 shift, IMG::Poly &poly, quint16 cnt = 0xFFFF, const SubDiv *subdiv, quint32 shift, MapData::Poly &poly,
bool check = false) quint16 cnt = 0xFFFF, bool check = false)
{ {
quint32 v1, v2, v2b; quint32 v1, v2, v2b;
if (!bs.readVuint32SM(v1, v2, v2b)) if (!bs.readVuint32SM(v1, v2, v2b))
@ -233,7 +234,7 @@ static bool readShape(NODFile *nod, SubFile::Handle &nodHdl,
} }
} }
HuffmanStreamR stream(bs, table); HuffmanStreamR stream(bs, *table);
if (!stream.init(lonSign, latSign, flags, extraBits)) if (!stream.init(lonSign, latSign, flags, extraBits))
return false; return false;
qint32 lonDelta, latDelta; qint32 lonDelta, latDelta;
@ -345,8 +346,13 @@ static bool readShape(NODFile *nod, SubFile::Handle &nodHdl,
} }
bool NETFile::linkLabel(Handle &hdl, quint32 offset, quint32 size, LBLFile *lbl, NETFile::~NETFile()
Handle &lblHdl, Label &label) {
delete _huffmanTable;
}
bool NETFile::linkLabel(Handle &hdl, quint32 offset, quint32 size,
const LBLFile *lbl, Handle &lblHdl, Label &label) const
{ {
if (!seek(hdl, offset)) if (!seek(hdl, offset))
return false; return false;
@ -360,19 +366,13 @@ bool NETFile::linkLabel(Handle &hdl, quint32 offset, quint32 size, LBLFile *lbl,
if (!bs.readUInt24(labelPtr)) if (!bs.readUInt24(labelPtr))
return false; return false;
if (labelPtr & 0x3FFFFF) { if (labelPtr & 0x3FFFFF)
if (labelPtr & 0x400000) { label = lbl->label(lblHdl, labelPtr & 0x3FFFFF);
quint32 lblOff;
if (lblOffset(hdl, labelPtr & 0x3FFFFF, lblOff) && lblOff)
label = lbl->label(lblHdl, lblOff);
} else
label = lbl->label(lblHdl, labelPtr & 0x3FFFFF);
}
return true; return true;
} }
bool NETFile::init(Handle &hdl) bool NETFile::load(Handle &hdl, const RGNFile *rgn, Handle &rgnHdl)
{ {
quint16 hdrLen; quint16 hdrLen;
@ -385,31 +385,36 @@ bool NETFile::init(Handle &hdl)
quint32 info; quint32 info;
if (!(seek(hdl, _gmpOffset + 0x37) && readUInt32(hdl, info))) if (!(seek(hdl, _gmpOffset + 0x37) && readUInt32(hdl, info)))
return false; return false;
_tableId = ((info >> 2) & 0xF);
if (!(seek(hdl, _gmpOffset + 0x43) && readUInt32(hdl, _linksOffset) if (!(seek(hdl, _gmpOffset + 0x43) && readUInt32(hdl, _linksOffset)
&& readUInt32(hdl, _linksSize) && readUInt8(hdl, _linksShift))) && readUInt32(hdl, _linksSize) && readUInt8(hdl, _linksShift)))
return false; return false;
}
_init = true; quint8 tableId = ((info >> 2) & 0xF);
if (_linksSize && (!rgn->huffmanTable() || rgn->huffmanTable()->id()
!= tableId)) {
_huffmanTable = new HuffmanTable(tableId);
if (!_huffmanTable->load(rgn, rgnHdl))
return false;
}
_tp = _huffmanTable ? _huffmanTable : rgn->huffmanTable();
}
return true; return true;
} }
bool NETFile::link(const SubDiv *subdiv, quint32 shift, Handle &hdl, void NETFile::clear()
NODFile *nod, Handle &nodHdl, LBLFile *lbl, Handle &lblHdl,
const NODFile::BlockInfo &blockInfo, quint8 linkId, quint8 lineId,
const HuffmanTable &table, QList<IMG::Poly> *lines)
{ {
if (!_init && !init(hdl)) delete _huffmanTable;
return false; _huffmanTable = 0;
}
Q_ASSERT(_tableId == table.id()); bool NETFile::link(const SubDiv *subdiv, quint32 shift, Handle &hdl,
if (_tableId != table.id()) const NODFile *nod, Handle &nodHdl, const LBLFile *lbl, Handle &lblHdl,
return false; const NODFile::BlockInfo &blockInfo, quint8 linkId, quint8 lineId,
QList<MapData::Poly> *lines) const
IMG::Poly poly; {
MapData::Poly poly;
if (!nod->linkType(nodHdl, blockInfo, linkId, poly.type)) if (!nod->linkType(nodHdl, blockInfo, linkId, poly.type))
return false; return false;
@ -445,7 +450,7 @@ bool NETFile::link(const SubDiv *subdiv, quint32 shift, Handle &hdl,
if (s69 == 1) { if (s69 == 1) {
if (s68 == 1) { if (s68 == 1) {
if (!readShape(nod, nodHdl, adj, bs, table, subdiv, shift, poly)) if (!readShape(nod, nodHdl, adj, bs, _tp, subdiv, shift, poly))
return false; return false;
} else { } else {
if (!readNodeGeometry(nod, nodHdl, adj, poly)) if (!readNodeGeometry(nod, nodHdl, adj, poly))
@ -459,7 +464,7 @@ bool NETFile::link(const SubDiv *subdiv, quint32 shift, Handle &hdl,
if (i == lineId) { if (i == lineId) {
if (shape) { if (shape) {
bool check = (i < ca.size()) ? (ca.at(i) & mask) : false; bool check = (i < ca.size()) ? (ca.at(i) & mask) : false;
if (!readShape(nod, nodHdl, adj, bs, table, subdiv, if (!readShape(nod, nodHdl, adj, bs, _tp, subdiv,
shift, poly, step, check)) shift, poly, step, check))
return false; return false;
} else { } else {
@ -483,7 +488,7 @@ bool NETFile::link(const SubDiv *subdiv, quint32 shift, Handle &hdl,
return false; return false;
if (!seekToLine(bs, lineId)) if (!seekToLine(bs, lineId))
return false; return false;
if (!readLine(bs, subdiv, table, poly)) if (!readLine(bs, subdiv, _tp, poly))
return false; return false;
} }
@ -496,11 +501,8 @@ bool NETFile::link(const SubDiv *subdiv, quint32 shift, Handle &hdl,
return true; return true;
} }
bool NETFile::lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset) bool NETFile::lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset) const
{ {
if (!_init && !init(hdl))
return false;
if (!(seek(hdl, _offset + (netOffset << _shift)) if (!(seek(hdl, _offset + (netOffset << _shift))
&& readUInt24(hdl, lblOffset))) && readUInt24(hdl, lblOffset)))
return false; return false;

View File

@ -1,42 +1,44 @@
#ifndef NETFILE_H #ifndef NETFILE_H
#define NETFILE_H #define NETFILE_H
#include "img.h"
#include "subfile.h" #include "subfile.h"
#include "nodfile.h" #include "nodfile.h"
class NODFile;
class LBLFile; class LBLFile;
class RGNFile;
class SubDiv; class SubDiv;
class HuffmanTable; class HuffmanTable;
class NETFile : public SubFile class NETFile : public SubFile
{ {
public: public:
NETFile(IMG *img) : SubFile(img), _offset(0), _size(0), _linksOffset(0), NETFile(IMG *img) : SubFile(img), _huffmanTable(0), _tp(0), _offset(0),
_linksSize(0), _shift(0), _linksShift(0), _init(false) {} _size(0), _linksOffset(0), _linksSize(0), _shift(0), _linksShift(0) {}
NETFile(const QString &path) : SubFile(path), _offset(0), _size(0), NETFile(const QString *path) : SubFile(path), _huffmanTable(0), _tp(0),
_linksOffset(0), _linksSize(0), _shift(0), _linksShift(0),
_init(false) {}
NETFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset),
_offset(0), _size(0), _linksOffset(0), _linksSize(0), _shift(0), _offset(0), _size(0), _linksOffset(0), _linksSize(0), _shift(0),
_linksShift(0), _init(false) {} _linksShift(0) {}
NETFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset),
_huffmanTable(0), _tp(0), _offset(0), _size(0), _linksOffset(0),
_linksSize(0), _shift(0), _linksShift(0) {}
~NETFile();
bool lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset); bool load(Handle &hdl, const RGNFile *rgn, Handle &rgnHdl);
bool link(const SubDiv *subdiv, quint32 shift, Handle &hdl, NODFile *nod, void clear();
Handle &nodHdl, LBLFile *lbl, Handle &lblHdl,
bool lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset) const;
bool link(const SubDiv *subdiv, quint32 shift, Handle &hdl,
const NODFile *nod, Handle &nodHdl, const LBLFile *lbl, Handle &lblHdl,
const NODFile::BlockInfo &blockInfo, quint8 linkId, quint8 lineId, const NODFile::BlockInfo &blockInfo, quint8 linkId, quint8 lineId,
const HuffmanTable &table, QList<IMG::Poly> *lines); QList<MapData::Poly> *lines) const;
private: private:
bool init(Handle &hdl); bool linkLabel(Handle &hdl, quint32 offset, quint32 size,
bool linkLabel(Handle &hdl, quint32 offset, quint32 size, LBLFile *lbl, const LBLFile *lbl, Handle &lblHdl, Label &label) const;
Handle &lblHdl, Label &label);
HuffmanTable *_huffmanTable;
const HuffmanTable *_tp;
quint32 _offset, _size, _linksOffset, _linksSize; quint32 _offset, _size, _linksOffset, _linksSize;
quint8 _shift, _linksShift; quint8 _shift, _linksShift;
quint8 _tableId;
bool _init;
}; };
#endif // NETFILE_H #endif // NETFILE_H

View File

@ -81,14 +81,14 @@ static bool skipOptAdjData(BitStream1 &bs)
} }
bool NODFile::init(Handle &hdl) bool NODFile::load(Handle &hdl)
{ {
quint16 hdrLen; quint16 hdrLen;
if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen))) if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen)))
return false; return false;
if (hdrLen < 0x7b) if (hdrLen < 0x7b)
return false; return true;
if (!(seek(hdl, _gmpOffset + 0x1d) && readUInt32(hdl, _flags) if (!(seek(hdl, _gmpOffset + 0x1d) && readUInt32(hdl, _flags)
&& readUInt8(hdl, _blockShift) && readUInt8(hdl, _nodeShift))) && readUInt8(hdl, _blockShift) && readUInt8(hdl, _nodeShift)))
@ -113,14 +113,6 @@ bool NODFile::init(Handle &hdl)
return (_indexIdSize > 0); return (_indexIdSize > 0);
} }
quint32 NODFile::indexIdSize(Handle &hdl)
{
if (!_indexIdSize && !init(hdl))
return 0;
return _indexIdSize;
}
bool NODFile::readBlock(Handle &hdl, quint32 blockOffset, bool NODFile::readBlock(Handle &hdl, quint32 blockOffset,
BlockInfo &blockInfo) const BlockInfo &blockInfo) const
{ {
@ -494,7 +486,7 @@ bool NODFile::relAdjInfo(Handle &hdl, AdjacencyInfo &adj) const
return true; return true;
} }
int NODFile::nextNode(Handle &hdl, AdjacencyInfo &adjInfo) int NODFile::nextNode(Handle &hdl, AdjacencyInfo &adjInfo) const
{ {
if (adjInfo.nodeOffset == 0xFFFFFFFF) if (adjInfo.nodeOffset == 0xFFFFFFFF)
return 1; return 1;

View File

@ -1,7 +1,6 @@
#ifndef NODFILE_H #ifndef NODFILE_H
#define NODFILE_H #define NODFILE_H
#include "img.h"
#include "subfile.h" #include "subfile.h"
class NODFile : public SubFile class NODFile : public SubFile
@ -57,7 +56,7 @@ public:
NODFile(IMG *img) : SubFile(img), _indexOffset(0), _indexSize(0), NODFile(IMG *img) : SubFile(img), _indexOffset(0), _indexSize(0),
_indexFlags(0), _blockOffset(0), _blockSize(0), _indexRecordSize(0), _indexFlags(0), _blockOffset(0), _blockSize(0), _indexRecordSize(0),
_blockRecordSize(0), _blockShift(0), _nodeShift(0), _indexIdSize(0) {} _blockRecordSize(0), _blockShift(0), _nodeShift(0), _indexIdSize(0) {}
NODFile(const QString &path) : SubFile(path), _indexOffset(0), _indexSize(0), NODFile(const QString *path) : SubFile(path), _indexOffset(0), _indexSize(0),
_indexFlags(0), _blockOffset(0), _blockSize(0), _indexRecordSize(0), _indexFlags(0), _blockOffset(0), _blockSize(0), _indexRecordSize(0),
_blockRecordSize(0), _blockShift(0), _nodeShift(0), _indexIdSize(0) {} _blockRecordSize(0), _blockShift(0), _nodeShift(0), _indexIdSize(0) {}
NODFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset), NODFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset),
@ -65,16 +64,17 @@ public:
_blockSize(0), _indexRecordSize(0), _blockRecordSize(0), _blockShift(0), _blockSize(0), _indexRecordSize(0), _blockRecordSize(0), _blockShift(0),
_nodeShift(0), _indexIdSize(0) {} _nodeShift(0), _indexIdSize(0) {}
quint32 indexIdSize(Handle &hdl); bool load(Handle &hdl);
quint32 indexIdSize() const {return _indexIdSize;}
bool blockInfo(Handle &hdl, quint32 blockId, BlockInfo &blockInfo) const; bool blockInfo(Handle &hdl, quint32 blockId, BlockInfo &blockInfo) const;
bool linkInfo(Handle &hdl, const BlockInfo &blockInfo, quint32 linkId, bool linkInfo(Handle &hdl, const BlockInfo &blockInfo, quint32 linkId,
LinkInfo &linkInfo) const; LinkInfo &linkInfo) const;
bool linkType(Handle &hdl, const BlockInfo &blockInfo, quint8 linkId, bool linkType(Handle &hdl, const BlockInfo &blockInfo, quint8 linkId,
quint32 &type) const; quint32 &type) const;
int nextNode(Handle &hdl, AdjacencyInfo &adjInfo); int nextNode(Handle &hdl, AdjacencyInfo &adjInfo) const;
private: private:
bool init(Handle &hdl);
bool nodeInfo(Handle &hdl, const BlockInfo &blockInfo, quint32 nodeOffset, bool nodeInfo(Handle &hdl, const BlockInfo &blockInfo, quint32 nodeOffset,
NodeInfo &nodeInfo) const; NodeInfo &nodeInfo) const;
bool nodeOffset(Handle &hdl, const BlockInfo &blockInfo, quint8 nodeId, bool nodeOffset(Handle &hdl, const BlockInfo &blockInfo, quint8 nodeId,

View File

@ -24,6 +24,11 @@ static quint64 pointId(const QPoint &pos, quint32 type, quint32 labelPtr)
return id; return id;
} }
RGNFile::~RGNFile()
{
delete _huffmanTable;
}
bool RGNFile::skipClassFields(Handle &hdl) const bool RGNFile::skipClassFields(Handle &hdl) const
{ {
quint8 flags; quint8 flags;
@ -96,7 +101,7 @@ bool RGNFile::skipGblFields(Handle &hdl, quint32 flags) const
return seek(hdl, pos(hdl) + cnt); return seek(hdl, pos(hdl) + cnt);
} }
bool RGNFile::init(Handle &hdl) bool RGNFile::load(Handle &hdl)
{ {
quint16 hdrLen; quint16 hdrLen;
@ -125,24 +130,29 @@ bool RGNFile::init(Handle &hdl)
} }
if (hdrLen >= 0x7D) { if (hdrLen >= 0x7D) {
quint32 dictOffset, dictSize, info; quint32 info;
if (!(seek(hdl, _gmpOffset + 0x71) && readUInt32(hdl, dictOffset) if (!(seek(hdl, _gmpOffset + 0x71) && readUInt32(hdl, _dictOffset)
&& readUInt32(hdl, dictSize) && readUInt32(hdl, info))) && readUInt32(hdl, _dictSize) && readUInt32(hdl, info)))
return false; return false;
if (dictSize && dictOffset && (info & 0x1E)) if (_dictSize && _dictOffset && (info & 0x1E)) {
if (!_huffmanTable.load(*this, hdl, dictOffset, dictSize, _huffmanTable = new HuffmanTable(((info >> 1) & 0xF) - 1);
((info >> 1) & 0xF) - 1)) if (!_huffmanTable->load(this, hdl))
return false; return false;
}
} }
_init = true;
return true; return true;
} }
void RGNFile::clear()
{
delete _huffmanTable;
_huffmanTable = 0;
}
bool RGNFile::polyObjects(Handle &hdl, const SubDiv *subdiv, bool RGNFile::polyObjects(Handle &hdl, const SubDiv *subdiv,
SegmentType segmentType, LBLFile *lbl, Handle &lblHdl, NETFile *net, SegmentType segmentType, const LBLFile *lbl, Handle &lblHdl, NETFile *net,
Handle &netHdl, QList<IMG::Poly> *polys) const Handle &netHdl, QList<IMG::Poly> *polys) const
{ {
const SubDiv::Segment &segment = (segmentType == Line) const SubDiv::Segment &segment = (segmentType == Line)
@ -218,7 +228,7 @@ bool RGNFile::polyObjects(Handle &hdl, const SubDiv *subdiv,
} }
bool RGNFile::extPolyObjects(Handle &hdl, const SubDiv *subdiv, quint32 shift, bool RGNFile::extPolyObjects(Handle &hdl, const SubDiv *subdiv, quint32 shift,
SegmentType segmentType, LBLFile *lbl, Handle &lblHdl, SegmentType segmentType, const LBLFile *lbl, Handle &lblHdl,
QList<IMG::Poly> *polys) const QList<IMG::Poly> *polys) const
{ {
quint32 labelPtr, len; quint32 labelPtr, len;
@ -246,13 +256,13 @@ bool RGNFile::extPolyObjects(Handle &hdl, const SubDiv *subdiv, quint32 shift,
poly.type = 0x10000 | (quint16(type)<<8) | (subtype & 0x1F); poly.type = 0x10000 | (quint16(type)<<8) | (subtype & 0x1F);
labelPtr = 0; labelPtr = 0;
if (!_huffmanTable.isNull()) { if (_huffmanTable) {
pos = QPoint(LS(subdiv->lon(), 8) + LS(lon, 32-subdiv->bits()), pos = QPoint(LS(subdiv->lon(), 8) + LS(lon, 32-subdiv->bits()),
LS(subdiv->lat(), 8) + LS(lat, (32-subdiv->bits()))); LS(subdiv->lat(), 8) + LS(lat, (32-subdiv->bits())));
qint32 lonDelta, latDelta; qint32 lonDelta, latDelta;
BitStream4F bs(*this, hdl, len); BitStream4F bs(*this, hdl, len);
HuffmanStreamF stream(bs, _huffmanTable); HuffmanStreamF stream(bs, *_huffmanTable);
if (!stream.init(segmentType == Line)) if (!stream.init(segmentType == Line))
return false; return false;
@ -329,7 +339,7 @@ bool RGNFile::extPolyObjects(Handle &hdl, const SubDiv *subdiv, quint32 shift,
} }
bool RGNFile::pointObjects(Handle &hdl, const SubDiv *subdiv, bool RGNFile::pointObjects(Handle &hdl, const SubDiv *subdiv,
SegmentType segmentType, LBLFile *lbl, Handle &lblHdl, SegmentType segmentType, const LBLFile *lbl, Handle &lblHdl,
QList<IMG::Point> *points) const QList<IMG::Point> *points) const
{ {
const SubDiv::Segment &segment = (segmentType == IndexedPoint) const SubDiv::Segment &segment = (segmentType == IndexedPoint)
@ -363,9 +373,8 @@ bool RGNFile::pointObjects(Handle &hdl, const SubDiv *subdiv,
point.coordinates = Coordinates(toWGS24(pos.x()), toWGS24(pos.y())); point.coordinates = Coordinates(toWGS24(pos.x()), toWGS24(pos.y()));
point.id = pointId(pos, point.type, labelPtr & 0x3FFFFF); point.id = pointId(pos, point.type, labelPtr & 0x3FFFFF);
if (lbl && (labelPtr & 0x3FFFFF)) if (lbl && (labelPtr & 0x3FFFFF))
point.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF, point.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF, labelPtr & 0x400000,
labelPtr & 0x400000, !(point.type == 0x1400 || point.type == 0x1500 !(point.type == 0x1400 || point.type == 0x1500 || point.type == 0x1e00));
|| point.type == 0x1e00));
points->append(point); points->append(point);
} }
@ -373,11 +382,12 @@ bool RGNFile::pointObjects(Handle &hdl, const SubDiv *subdiv,
return true; return true;
} }
bool RGNFile::extPointObjects(Handle &hdl, const SubDiv *subdiv, LBLFile *lbl, bool RGNFile::extPointObjects(Handle &hdl, const SubDiv *subdiv,
Handle &lblHdl, QList<IMG::Point> *points) const const LBLFile *lbl, Handle &lblHdl, QList<IMG::Point> *points) const
{ {
const SubDiv::Segment &segment = subdiv->extPoints(); const SubDiv::Segment &segment = subdiv->extPoints();
if (!segment.isValid()) if (!segment.isValid())
return true; return true;
if (!seek(hdl, segment.offset())) if (!seek(hdl, segment.offset()))
@ -423,30 +433,27 @@ bool RGNFile::extPointObjects(Handle &hdl, const SubDiv *subdiv, LBLFile *lbl,
} }
bool RGNFile::links(Handle &hdl, const SubDiv *subdiv, quint32 shift, bool RGNFile::links(Handle &hdl, const SubDiv *subdiv, quint32 shift,
NETFile *net, Handle &netHdl, NODFile *nod, Handle &nodHdl, LBLFile *lbl, const NETFile *net, Handle &netHdl, const NODFile *nod, Handle &nodHdl,
Handle &lblHdl, QList<IMG::Poly> *lines) const const LBLFile *lbl, Handle &lblHdl, QList<IMG::Poly> *lines) const
{ {
quint32 size, blockIndexIdSize, blockIndexId; quint32 size, blockIndexId;
quint8 flags; quint8 flags;
const SubDiv::Segment &segment = subdiv->roadReferences(); const SubDiv::Segment &segment = subdiv->roadReferences();
if (!net || !nod)
return false;
if (!segment.isValid()) if (!segment.isValid())
return true; return true;
if (!seek(hdl, segment.offset())) if (!seek(hdl, segment.offset()))
return false; return false;
if (!net || !nod)
return false;
if (!(blockIndexIdSize = nod->indexIdSize(nodHdl)))
return false;
while (pos(hdl) < segment.end()) { while (pos(hdl) < segment.end()) {
if (!readVUInt32(hdl, size)) if (!readVUInt32(hdl, size))
return false; return false;
quint32 entryStart = pos(hdl); quint32 entryStart = pos(hdl);
if (!(readUInt8(hdl, flags) && readVUInt32(hdl, blockIndexIdSize, if (!(readUInt8(hdl, flags) && readVUInt32(hdl, nod->indexIdSize(),
blockIndexId))) blockIndexId)))
return false; return false;
@ -494,10 +501,11 @@ bool RGNFile::links(Handle &hdl, const SubDiv *subdiv, quint32 shift,
} }
net->link(subdiv, shift, netHdl, nod, nodHdl, lbl, lblHdl, net->link(subdiv, shift, netHdl, nod, nodHdl, lbl, lblHdl,
blockInfo, linkId, lineId, _huffmanTable, lines); blockInfo, linkId, lineId, lines);
} }
Q_ASSERT(entryStart + size == pos(hdl)); if (entryStart + size != pos(hdl))
return false;
} }
return true; return true;
@ -546,7 +554,7 @@ QMap<RGNFile::SegmentType, SubDiv::Segment> RGNFile::segments(Handle &hdl,
return ret; return ret;
} }
bool RGNFile::subdivInit(Handle &hdl, SubDiv *subdiv) const bool RGNFile::subdivInit(Handle &hdl, SubDiv *subdiv)
{ {
QMap<RGNFile::SegmentType, SubDiv::Segment> seg(segments(hdl, subdiv)); QMap<RGNFile::SegmentType, SubDiv::Segment> seg(segments(hdl, subdiv));
SubDiv::Segment extPoints, extLines, extPolygons; SubDiv::Segment extPoints, extLines, extPolygons;

View File

@ -1,14 +1,13 @@
#ifndef RGNFILE_H #ifndef RGNFILE_H
#define RGNFILE_H #define RGNFILE_H
#include "img.h"
#include "subfile.h" #include "subfile.h"
#include "subdiv.h" #include "subdiv.h"
#include "huffmantable.h"
class LBLFile; class LBLFile;
class NETFile; class NETFile;
class NODFile; class NODFile;
class HuffmanTable;
class RGNFile : public SubFile class RGNFile : public SubFile
{ {
@ -22,35 +21,41 @@ public:
}; };
RGNFile(IMG *img) RGNFile(IMG *img)
: SubFile(img), _offset(0), _size(0), _polygonsOffset(0), : SubFile(img), _huffmanTable(0), _offset(0), _size(0), _polygonsOffset(0),
_polygonsSize(0), _linesOffset(0), _linesSize(0), _pointsOffset(0), _polygonsSize(0), _linesOffset(0), _linesSize(0), _pointsOffset(0),
_pointsSize(0), _init(false) {} _pointsSize(0) {}
RGNFile(const QString &path) RGNFile(const QString *path)
: SubFile(path), _offset(0), _size(0), _polygonsOffset(0), : SubFile(path), _huffmanTable(0), _offset(0), _size(0), _polygonsOffset(0),
_polygonsSize(0), _linesOffset(0), _linesSize(0), _pointsOffset(0), _polygonsSize(0), _linesOffset(0), _linesSize(0), _pointsOffset(0),
_pointsSize(0), _init(false) {} _pointsSize(0) {}
RGNFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset), _offset(0), RGNFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset),
_size(0), _polygonsOffset(0), _polygonsSize(0), _linesOffset(0), _huffmanTable(0), _offset(0), _size(0), _polygonsOffset(0),
_linesSize(0), _pointsOffset(0), _pointsSize(0), _init(false) {} _polygonsSize(0), _linesOffset(0), _linesSize(0), _pointsOffset(0),
_pointsSize(0) {}
~RGNFile();
bool initialized() const {return _init;} void clear();
bool init(Handle &hdl); bool load(Handle &hdl);
bool polyObjects(Handle &hdl, const SubDiv *subdiv, SegmentType segmentType, bool polyObjects(Handle &hdl, const SubDiv *subdiv, SegmentType segmentType,
LBLFile *lbl, Handle &lblHdl, NETFile *net, Handle &netHdl, const LBLFile *lbl, Handle &lblHdl, NETFile *net, Handle &netHdl,
QList<IMG::Poly> *polys) const; QList<MapData::Poly> *polys) const;
bool pointObjects(Handle &hdl, const SubDiv *subdiv, SegmentType segmentType, bool pointObjects(Handle &hdl, const SubDiv *subdiv, SegmentType segmentType,
LBLFile *lbl, Handle &lblHdl, QList<IMG::Point> *points) const; const LBLFile *lbl, Handle &lblHdl, QList<MapData::Point> *points) const;
bool extPolyObjects(Handle &hdl, const SubDiv *subdiv, quint32 shift, bool extPolyObjects(Handle &hdl, const SubDiv *subdiv, quint32 shift,
SegmentType segmentType, LBLFile *lbl, Handle &lblHdl, SegmentType segmentType, const LBLFile *lbl, Handle &lblHdl,
QList<IMG::Poly> *polys) const; QList<MapData::Poly> *polys) const;
bool extPointObjects(Handle &hdl, const SubDiv *subdiv, LBLFile *lbl, bool extPointObjects(Handle &hdl, const SubDiv *subdiv, const LBLFile *lbl,
Handle &lblHdl, QList<IMG::Point> *points) const; Handle &lblHdl, QList<MapData::Point> *points) const;
bool links(Handle &hdl, const SubDiv *subdiv, quint32 shift, NETFile *net, bool links(Handle &hdl, const SubDiv *subdiv, quint32 shift,
Handle &netHdl, NODFile *nod, Handle &nodHdl, LBLFile *lbl, Handle &lblHdl, const NETFile *net, Handle &netHdl, const NODFile *nod, Handle &nodHdl,
QList<IMG::Poly> *lines) const; const LBLFile *lbl, Handle &lblHdl, QList<MapData::Poly> *lines) const;
bool subdivInit(Handle &hdl, SubDiv *subdiv) const; bool subdivInit(Handle &hdl, SubDiv *subdiv);
const HuffmanTable *huffmanTable() const {return _huffmanTable;}
quint32 dictOffset() const {return _dictOffset;}
quint32 dictSize() const {return _dictSize;}
private: private:
QMap<SegmentType, SubDiv::Segment> segments(Handle &hdl, SubDiv *subdiv) QMap<SegmentType, SubDiv::Segment> segments(Handle &hdl, SubDiv *subdiv)
@ -60,8 +65,12 @@ private:
const; const;
bool skipGblFields(Handle &hdl, quint32 flags) const; bool skipGblFields(Handle &hdl, quint32 flags) const;
HuffmanTable *_huffmanTable;
quint32 _offset; quint32 _offset;
quint32 _size; quint32 _size;
quint32 _dictOffset;
quint32 _dictSize;
quint32 _polygonsOffset; quint32 _polygonsOffset;
quint32 _polygonsSize; quint32 _polygonsSize;
@ -75,10 +84,6 @@ private:
quint32 _pointsSize; quint32 _pointsSize;
quint32 _pointsLclFlags[3]; quint32 _pointsLclFlags[3];
quint32 _pointsGblFlags; quint32 _pointsGblFlags;
HuffmanTable _huffmanTable;
bool _init;
}; };
#endif // RGNFILE_H #endif // RGNFILE_H

View File

@ -42,14 +42,12 @@ public:
: _gmpOffset(0), _img(img), _blocks(new QVector<quint16>()), _path(0) {} : _gmpOffset(0), _img(img), _blocks(new QVector<quint16>()), _path(0) {}
SubFile(SubFile *gmp, quint32 offset) : _gmpOffset(offset), _img(gmp->_img), SubFile(SubFile *gmp, quint32 offset) : _gmpOffset(offset), _img(gmp->_img),
_blocks(gmp->_blocks), _path(gmp->_path) {} _blocks(gmp->_blocks), _path(gmp->_path) {}
SubFile(const QString &path) SubFile(const QString *path)
: _gmpOffset(0), _img(0), _blocks(0), _path(new QString(path)) {} : _gmpOffset(0), _img(0), _blocks(0), _path(path) {}
~SubFile() ~SubFile()
{ {
if (!_gmpOffset) { if (!_gmpOffset)
delete _blocks; delete _blocks;
delete _path;
}
} }
void addBlock(quint16 block) {_blocks->append(block);} void addBlock(quint16 block) {_blocks->append(block);}
@ -151,7 +149,7 @@ private:
IMG *_img; IMG *_img;
QVector<quint16> *_blocks; QVector<quint16> *_blocks;
QString *_path; const QString *_path;
}; };
#endif // SUBFILE_H #endif // SUBFILE_H

View File

@ -14,7 +14,7 @@ class TREFile : public SubFile
{ {
public: public:
TREFile(IMG *img) : SubFile(img) {} TREFile(IMG *img) : SubFile(img) {}
TREFile(const QString &path) : SubFile(path) {} TREFile(const QString *path) : SubFile(path) {}
TREFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset) {} TREFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset) {}
~TREFile(); ~TREFile();

View File

@ -1,16 +1,16 @@
#include "vectortile.h" #include "vectortile.h"
static void copyPolys(const RectC &rect, QList<IMG::Poly> *src, static void copyPolys(const RectC &rect, QList<MapData::Poly> *src,
QList<IMG::Poly> *dst) QList<MapData::Poly> *dst)
{ {
for (int i = 0; i < src->size(); i++) for (int i = 0; i < src->size(); i++)
if (rect.intersects(src->at(i).boundingRect)) if (rect.intersects(src->at(i).boundingRect))
dst->append(src->at(i)); dst->append(src->at(i));
} }
static void copyPoints(const RectC &rect, QList<IMG::Point> *src, static void copyPoints(const RectC &rect, QList<MapData::Point> *src,
QList<IMG::Point> *dst) QList<MapData::Point> *dst)
{ {
for (int j = 0; j < src->size(); j++) for (int j = 0; j < src->size(); j++)
if (rect.contains(src->at(j).coordinates)) if (rect.contains(src->at(j).coordinates))
@ -38,58 +38,6 @@ SubFile *VectorTile::file(SubFile::Type type)
} }
} }
SubFile *VectorTile::addFile(IMG *img, SubFile::Type type)
{
switch (type) {
case SubFile::TRE:
_tre = new TREFile(img);
return _tre;
case SubFile::RGN:
_rgn = new RGNFile(img);
return _rgn;
case SubFile::LBL:
_lbl = new LBLFile(img);
return _lbl;
case SubFile::NET:
_net = new NETFile(img);
return _net;
case SubFile::NOD:
_nod = new NODFile(img);
return _nod;
case SubFile::GMP:
_gmp = new SubFile(img);
return _gmp;
default:
return 0;
}
}
SubFile *VectorTile::addFile(const QString &path, SubFile::Type type)
{
switch (type) {
case SubFile::TRE:
_tre = new TREFile(path);
return _tre;
case SubFile::RGN:
_rgn = new RGNFile(path);
return _rgn;
case SubFile::LBL:
_lbl = new LBLFile(path);
return _lbl;
case SubFile::NET:
_net = new NETFile(path);
return _net;
case SubFile::NOD:
_nod = new NODFile(path);
return _nod;
case SubFile::GMP:
_gmp = new SubFile(path);
return _gmp;
default:
return 0;
}
}
bool VectorTile::init() bool VectorTile::init()
{ {
if (_gmp && !initGMP()) if (_gmp && !initGMP())
@ -120,23 +68,54 @@ bool VectorTile::initGMP()
return true; return true;
} }
bool VectorTile::load(SubFile::Handle &rgnHdl, SubFile::Handle &lblHdl,
SubFile::Handle &netHdl, SubFile::Handle &nodHdl)
{
_loaded = -1;
if (!_rgn->load(rgnHdl))
return false;
if (_lbl && !_lbl->load(lblHdl, _rgn, rgnHdl))
return false;
if (_net && !_net->load(netHdl, _rgn, rgnHdl))
return false;
if (_nod && !_nod->load(nodHdl))
return false;
_loaded = 1;
return true;
}
void VectorTile::clear()
{
_tre->clear();
_rgn->clear();
if (_lbl)
_lbl->clear();
if (_net)
_net->clear();
_loaded = 0;
}
void VectorTile::polys(const RectC &rect, int bits, bool baseMap, void VectorTile::polys(const RectC &rect, int bits, bool baseMap,
QList<IMG::Poly> *polygons, QList<IMG::Poly> *lines, QList<MapData::Poly> *polygons, QList<MapData::Poly> *lines,
QCache<const SubDiv *, IMG::Polys> *polyCache) const QCache<const SubDiv *, MapData::Polys> *polyCache)
{ {
SubFile::Handle rgnHdl(_rgn), lblHdl(_lbl), netHdl(_net), nodHdl(_nod); SubFile::Handle rgnHdl(_rgn), lblHdl(_lbl), netHdl(_net), nodHdl(_nod);
if (!_rgn->initialized() && !_rgn->init(rgnHdl)) if (_loaded < 0 || (!_loaded && !load(rgnHdl, lblHdl, netHdl, nodHdl)))
return; return;
QList<SubDiv*> subdivs = _tre->subdivs(rect, bits, baseMap); QList<SubDiv*> subdivs = _tre->subdivs(rect, bits, baseMap);
for (int i = 0; i < subdivs.size(); i++) { for (int i = 0; i < subdivs.size(); i++) {
SubDiv *subdiv = subdivs.at(i); SubDiv *subdiv = subdivs.at(i);
IMG::Polys *polys = polyCache->object(subdiv); MapData::Polys *polys = polyCache->object(subdiv);
if (!polys) { if (!polys) {
quint32 shift = _tre->shift(subdiv->bits()); quint32 shift = _tre->shift(subdiv->bits());
QList<IMG::Poly> p, l; QList<MapData::Poly> p, l;
if (!subdiv->initialized() && !_rgn->subdivInit(rgnHdl, subdiv)) if (!subdiv->initialized() && !_rgn->subdivInit(rgnHdl, subdiv))
continue; continue;
@ -154,7 +133,7 @@ void VectorTile::polys(const RectC &rect, int bits, bool baseMap,
copyPolys(rect, &p, polygons); copyPolys(rect, &p, polygons);
copyPolys(rect, &l, lines); copyPolys(rect, &l, lines);
polyCache->insert(subdiv, new IMG::Polys(p, l)); polyCache->insert(subdiv, new MapData::Polys(p, l));
} else { } else {
copyPolys(rect, &(polys->polygons), polygons); copyPolys(rect, &(polys->polygons), polygons);
copyPolys(rect, &(polys->lines), lines); copyPolys(rect, &(polys->lines), lines);
@ -163,21 +142,21 @@ void VectorTile::polys(const RectC &rect, int bits, bool baseMap,
} }
void VectorTile::points(const RectC &rect, int bits, bool baseMap, void VectorTile::points(const RectC &rect, int bits, bool baseMap,
QList<IMG::Point> *points, QCache<const SubDiv *, QList<MapData::Point> *points, QCache<const SubDiv *,
QList<IMG::Point> > *pointCache) const QList<MapData::Point> > *pointCache)
{ {
SubFile::Handle rgnHdl(_rgn), lblHdl(_lbl); SubFile::Handle rgnHdl(_rgn), lblHdl(_lbl), netHdl(_net), nodHdl(_nod);
if (!_rgn->initialized() && !_rgn->init(rgnHdl)) if (_loaded < 0 || (!_loaded && !load(rgnHdl, lblHdl, netHdl, nodHdl)))
return; return;
QList<SubDiv*> subdivs = _tre->subdivs(rect, bits, baseMap); QList<SubDiv*> subdivs = _tre->subdivs(rect, bits, baseMap);
for (int i = 0; i < subdivs.size(); i++) { for (int i = 0; i < subdivs.size(); i++) {
SubDiv *subdiv = subdivs.at(i); SubDiv *subdiv = subdivs.at(i);
QList<IMG::Point> *pl = pointCache->object(subdiv); QList<MapData::Point> *pl = pointCache->object(subdiv);
if (!pl) { if (!pl) {
QList<IMG::Point> p; QList<MapData::Point> p;
if (!subdiv->initialized() && !_rgn->subdivInit(rgnHdl, subdiv)) if (!subdiv->initialized() && !_rgn->subdivInit(rgnHdl, subdiv))
continue; continue;
@ -189,7 +168,7 @@ void VectorTile::points(const RectC &rect, int bits, bool baseMap,
_rgn->extPointObjects(rgnHdl, subdiv, _lbl, lblHdl, &p); _rgn->extPointObjects(rgnHdl, subdiv, _lbl, lblHdl, &p);
copyPoints(rect, &p, points); copyPoints(rect, &p, points);
pointCache->insert(subdiv, new QList<IMG::Point>(p)); pointCache->insert(subdiv, new QList<MapData::Point>(p));
} else } else
copyPoints(rect, pl, points); copyPoints(rect, pl, points);
} }

View File

@ -1,7 +1,6 @@
#ifndef VECTORTILE_H #ifndef VECTORTILE_H
#define VECTORTILE_H #define VECTORTILE_H
#include "trefile.h"
#include "trefile.h" #include "trefile.h"
#include "rgnfile.h" #include "rgnfile.h"
#include "lblfile.h" #include "lblfile.h"
@ -10,7 +9,8 @@
class VectorTile { class VectorTile {
public: public:
VectorTile() : _tre(0), _rgn(0), _lbl(0), _net(0), _nod(0), _gmp(0) {} VectorTile()
: _tre(0), _rgn(0), _lbl(0), _net(0), _nod(0), _gmp(0), _loaded(0) {}
~VectorTile() ~VectorTile()
{ {
delete _tre; delete _rgn; delete _lbl; delete _net; delete _nod; delete _tre; delete _rgn; delete _lbl; delete _net; delete _nod;
@ -19,21 +19,19 @@ public:
bool init(); bool init();
void markAsBasemap() {_tre->markAsBasemap();} void markAsBasemap() {_tre->markAsBasemap();}
void clear() {_tre->clear();} void clear();
const RectC &bounds() const {return _tre->bounds();} const RectC &bounds() const {return _tre->bounds();}
Range zooms() const {return _tre->zooms();} Range zooms() const {return _tre->zooms();}
SubFile *file(SubFile::Type type); SubFile *file(SubFile::Type type);
SubFile *addFile(IMG *img, SubFile::Type type);
SubFile *addFile(const QString &path, SubFile::Type type);
void polys(const RectC &rect, int bits, bool baseMap, void polys(const RectC &rect, int bits, bool baseMap,
QList<IMG::Poly> *polygons, QList<IMG::Poly> *lines, QList<MapData::Poly> *polygons, QList<MapData::Poly> *lines,
QCache<const SubDiv *, IMG::Polys> *polyCache) const; QCache<const SubDiv *, MapData::Polys> *polyCache);
void points(const RectC &rect, int bits, bool baseMap, void points(const RectC &rect, int bits, bool baseMap,
QList<IMG::Point> *points, QCache<const SubDiv*, QList<MapData::Point> *points, QCache<const SubDiv*,
QList<IMG::Point> > *pointCache) const; QList<MapData::Point> > *pointCache);
static bool isTileFile(SubFile::Type type) static bool isTileFile(SubFile::Type type)
{ {
@ -42,8 +40,37 @@ public:
|| type == SubFile::NOD || type == SubFile::GMP); || type == SubFile::NOD || type == SubFile::GMP);
} }
template<typename T>
SubFile *addFile(T *container, SubFile::Type type)
{
switch (type) {
case SubFile::TRE:
_tre = new TREFile(container);
return _tre;
case SubFile::RGN:
_rgn = new RGNFile(container);
return _rgn;
case SubFile::LBL:
_lbl = new LBLFile(container);
return _lbl;
case SubFile::NET:
_net = new NETFile(container);
return _net;
case SubFile::NOD:
_nod = new NODFile(container);
return _nod;
case SubFile::GMP:
_gmp = new SubFile(container);
return _gmp;
default:
return 0;
}
}
private: private:
bool initGMP(); bool initGMP();
bool load(SubFile::Handle &rgnHdl, SubFile::Handle &lblHdl,
SubFile::Handle &netHdl, SubFile::Handle &nodHdl);
TREFile *_tre; TREFile *_tre;
RGNFile *_rgn; RGNFile *_rgn;
@ -51,6 +78,8 @@ private:
NETFile *_net; NETFile *_net;
NODFile *_nod; NODFile *_nod;
SubFile *_gmp; SubFile *_gmp;
int _loaded;
}; };
#ifndef QT_NO_DEBUG #ifndef QT_NO_DEBUG