1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2025-07-14 19:04:23 +02:00

Compare commits

..

19 Commits
7.30 ... 7.31

Author SHA1 Message Date
14f4dead76 Merge branch 'origin/master' into Weblate. 2020-06-29 23:46:00 +02:00
96bb3bbdbb Removed obsolete stuff 2020-06-29 23:46:06 +02:00
22d18b6d4e Merge branch 'origin/master' into Weblate. 2020-06-28 21:02:09 +02:00
c1b79217a9 Update gpxsee_en.ts (#296) 2020-06-28 21:02:05 +02:00
e67a14b072 Merge branch 'origin/master' into Weblate. 2020-06-28 19:52:37 +02:00
473d03cf1f Fixed broken extended objects segment fetching 2020-06-28 19:51:59 +02:00
a339706293 Version++ 2020-06-27 22:51:53 +02:00
39c414ca73 Merge branch 'origin/master' into Weblate. 2020-06-27 22:51:44 +02:00
c59d60faed Merge branch 'origin/master' into Weblate. 2020-06-27 22:50:15 +02:00
32d3eab10e Initial (and partial) IMG links support
+ various IMG fixes (RGN parsing, IMG parsing)
2020-06-27 22:46:26 +02:00
e7729e8745 Added missing Italian localization stuff 2020-06-27 18:05:50 +02:00
bf145c9eb5 Merge branch 'origin/master' into Weblate. 2020-06-27 18:05:48 +02:00
de0a6b0397 Merge branch 'origin/master' into Weblate. 2020-06-27 18:00:07 +02:00
8cf89a580f Removed Arabic translation stub as noone is evidently gona use it despite
the Weblate request...
2020-06-27 17:59:15 +02:00
152e2a8a09 Merge branch 'origin/master' into Weblate. 2020-06-27 17:57:23 +02:00
6b860fe18c added italian translation (#295)
Added italian translation
2020-06-27 17:57:18 +02:00
95f138f5f0 Translated using Weblate (German)
Currently translated at 100.0% (359 of 359 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/de/
2020-06-11 13:41:42 +02:00
1fc4dbbb73 Cosmetics 2020-05-30 17:10:13 +02:00
0999cdcba2 Fixed Qt version with time zones support
+ reverted broken Qt version check for opengl
2020-05-30 17:06:06 +02:00
30 changed files with 1560 additions and 740 deletions

View File

@ -1,4 +1,4 @@
version: 7.30.{build} version: 7.31.{build}
configuration: configuration:
- Release - Release

View File

@ -3,7 +3,7 @@ unix:!macx {
} else { } else {
TARGET = GPXSee TARGET = GPXSee
} }
VERSION = 7.30 VERSION = 7.31
QT += core \ QT += core \
gui \ gui \
@ -14,7 +14,8 @@ greaterThan(QT_MAJOR_VERSION, 4) {
QT += widgets QT += widgets
QT += printsupport QT += printsupport
} }
lessThan(QT_VERSION, 5.4.0) {QT += opengl} lessThan(QT_MAJOR_VERSION, 5) {QT += opengl}
equals(QT_MAJOR_VERSION, 5) : lessThan(QT_MINOR_VERSION, 4) {QT += opengl}
INCLUDEPATH += ./src INCLUDEPATH += ./src
HEADERS += src/common/config.h \ HEADERS += src/common/config.h \
@ -94,6 +95,7 @@ HEADERS += src/common/config.h \
src/map/IMG/gmap.h \ src/map/IMG/gmap.h \
src/map/IMG/huffmanstream.h \ src/map/IMG/huffmanstream.h \
src/map/IMG/huffmantable.h \ src/map/IMG/huffmantable.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 \
src/map/IMG/textpathitem.h \ src/map/IMG/textpathitem.h \
@ -256,6 +258,7 @@ SOURCES += src/main.cpp \
src/map/IMG/gmap.cpp \ src/map/IMG/gmap.cpp \
src/map/IMG/huffmanstream.cpp \ src/map/IMG/huffmanstream.cpp \
src/map/IMG/huffmantable.cpp \ src/map/IMG/huffmantable.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 \
src/map/IMG/textpathitem.cpp \ src/map/IMG/textpathitem.cpp \
@ -347,7 +350,7 @@ greaterThan(QT_MAJOR_VERSION, 4) {
HEADERS += src/data/geojsonparser.h HEADERS += src/data/geojsonparser.h
SOURCES += src/data/geojsonparser.cpp SOURCES += src/data/geojsonparser.cpp
} }
greaterThan(QT_VERSION, 5.1.0) { equals(QT_MAJOR_VERSION, 5):greaterThan(QT_MINOR_VERSION, 4) {
HEADERS += src/GUI/timezoneinfo.h HEADERS += src/GUI/timezoneinfo.h
} }
@ -370,7 +373,8 @@ TRANSLATIONS = lang/gpxsee_en.ts \
lang/gpxsee_es.ts \ lang/gpxsee_es.ts \
lang/gpxsee_pt_BR.ts \ lang/gpxsee_pt_BR.ts \
lang/gpxsee_uk.ts \ lang/gpxsee_uk.ts \
lang/gpxsee_hu.ts lang/gpxsee_hu.ts \
lang/gpxsee_it.ts
macx { macx {
ICON = icons/gpxsee.icns ICON = icons/gpxsee.icns
@ -390,7 +394,8 @@ macx {
lang/gpxsee_es.qm \ lang/gpxsee_es.qm \
lang/gpxsee_pt_BR.qm \ lang/gpxsee_pt_BR.qm \
lang/gpxsee_uk.qm \ lang/gpxsee_uk.qm \
lang/gpxsee_hu.qm lang/gpxsee_hu.qm \
lang/gpxsee_it.qm
csv.path = Contents/Resources csv.path = Contents/Resources
csv.files = pkg/csv csv.files = pkg/csv
maps.path = Contents/Resources maps.path = Contents/Resources

View File

@ -1347,12 +1347,12 @@
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="420"/> <location filename="../src/GUI/optionsdialog.cpp" line="420"/>
<source>UTC</source> <source>UTC</source>
<translation type="unfinished"></translation> <translation>UTC</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="478"/> <location filename="../src/GUI/optionsdialog.cpp" line="478"/>
<source>Time zone:</source> <source>Time zone:</source>
<translation type="unfinished"></translation> <translation>Zeitzone:</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="500"/> <location filename="../src/GUI/optionsdialog.cpp" line="500"/>
@ -1362,7 +1362,7 @@
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="509"/> <location filename="../src/GUI/optionsdialog.cpp" line="509"/>
<source>Time zone</source> <source>Time zone</source>
<translation type="unfinished"></translation> <translation>Zeitzone</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="524"/> <location filename="../src/GUI/optionsdialog.cpp" line="524"/>

View File

@ -1,4 +1,15 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS> <!DOCTYPE TS>
<TS version="2.1" language="en_US"> <TS version="2.1" language="en_US">
<context>
<name>GUI</name>
<message numerus="yes">
<location filename="../src/GUI/gui.cpp" line="1392"/>
<source>%n files</source>
<translation>
<numerusform>%n file</numerusform>
<numerusform>%n files</numerusform>
</translation>
</message>
</context>
</TS> </TS>

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@
; The name of the installer ; The name of the installer
Name "GPXSee" Name "GPXSee"
; Program version ; Program version
!define VERSION "7.30" !define VERSION "7.31"
; The file to write ; The file to write
OutFile "GPXSee-${VERSION}.exe" OutFile "GPXSee-${VERSION}.exe"
@ -177,6 +177,7 @@ SectionGroup "Localization" SEC_LOCALIZATION
!insertmacro LOCALIZATION "French" "fr" !insertmacro LOCALIZATION "French" "fr"
!insertmacro LOCALIZATION "German" "de" !insertmacro LOCALIZATION "German" "de"
!insertmacro LOCALIZATION "Hungarian" "hu" !insertmacro LOCALIZATION "Hungarian" "hu"
!insertmacro LOCALIZATION "Italian" "it"
!insertmacro LOCALIZATION "Norwegian" "nb" !insertmacro LOCALIZATION "Norwegian" "nb"
!insertmacro LOCALIZATION "Polish" "pl" !insertmacro LOCALIZATION "Polish" "pl"
!insertmacro LOCALIZATION "Portuguese (Brazil)" "pt_BR" !insertmacro LOCALIZATION "Portuguese (Brazil)" "pt_BR"

View File

@ -7,7 +7,7 @@
; The name of the installer ; The name of the installer
Name "GPXSee" Name "GPXSee"
; Program version ; Program version
!define VERSION "7.30" !define VERSION "7.31"
; The file to write ; The file to write
OutFile "GPXSee-${VERSION}_x64.exe" OutFile "GPXSee-${VERSION}_x64.exe"
@ -184,6 +184,7 @@ SectionGroup "Localization" SEC_LOCALIZATION
!insertmacro LOCALIZATION "French" "fr" !insertmacro LOCALIZATION "French" "fr"
!insertmacro LOCALIZATION "German" "de" !insertmacro LOCALIZATION "German" "de"
!insertmacro LOCALIZATION "Hungarian" "hu" !insertmacro LOCALIZATION "Hungarian" "hu"
!insertmacro LOCALIZATION "Italian" "it"
!insertmacro LOCALIZATION "Norwegian" "nb" !insertmacro LOCALIZATION "Norwegian" "nb"
!insertmacro LOCALIZATION "Polish" "pl" !insertmacro LOCALIZATION "Polish" "pl"
!insertmacro LOCALIZATION "Portuguese (Brazil)" "pt_BR" !insertmacro LOCALIZATION "Portuguese (Brazil)" "pt_BR"

View File

@ -18,8 +18,8 @@
#define ENABLE_GEOJSON #define ENABLE_GEOJSON
#endif // QT >= 5.0 #endif // QT >= 5.0
#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) #if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
#define ENABLE_TIMEZONES #define ENABLE_TIMEZONES
#endif // QT >= 5.2 #endif // QT >= 5.5
#endif /* CONFIG_H */ #endif /* CONFIG_H */

View File

@ -41,8 +41,19 @@ bool BitStream1::flush()
return true; return true;
} }
bool BitStream4::flush()
{
if (_length && !_file.seek(_hdl, _hdl.pos() + _length))
return false;
bool BitStream4::read(int bits, quint32 &val) _length = 0;
_used = 32;
_unused = 0;
return true;
}
bool BitStream4F::read(int bits, quint32 &val)
{ {
if (bits <= 32 - (int)(_used + _unused)) { if (bits <= 32 - (int)(_used + _unused)) {
val = bits ? (_data << _used) >> (32 - bits) : 0; val = bits ? (_data << _used) >> (32 - bits) : 0;
@ -50,6 +61,8 @@ bool BitStream4::read(int bits, quint32 &val)
return true; return true;
} }
if (_unused)
return false;
quint32 old = (_used < 32) ? (_data << _used) >> (32 - bits) : 0; quint32 old = (_used < 32) ? (_data << _used) >> (32 - bits) : 0;
quint32 bytes = qMin(_length, 4U); quint32 bytes = qMin(_length, 4U);
@ -66,14 +79,123 @@ bool BitStream4::read(int bits, quint32 &val)
return true; return true;
} }
bool BitStream4::flush() BitStream4R::BitStream4R(const SubFile &file, SubFile::Handle &hdl,
quint32 length) : BitStream4(file, hdl, length)
{ {
if (_length && !_file.seek(_hdl, _hdl.pos() + _length)) _file.seek(_hdl, _hdl.pos() - 4);
}
bool BitStream4R::readBytes(int bytes, quint32 &val)
{
quint32 bits = _used % 8;
quint32 b;
if (bits) {
if (!read(8 - bits, b))
return false;
Q_ASSERT(!b);
}
return read(bytes * 8, val);
}
bool BitStream4R::readVUInt32(quint32 &val)
{
quint32 b;
quint8 bytes, shift;
if (!readBytes(1, b))
return false; return false;
_length = 0; if ((b & 1) == 0) {
_used = 32; if ((b & 2) == 0) {
_unused = 0; bytes = ((b >> 2) & 1) ^ 3;
shift = 5;
} else {
shift = 6;
bytes = 1;
}
} else {
shift = 7;
bytes = 0;
}
val = b >> (8 - shift);
if (bytes) {
if (!readBytes(bytes, b))
return false;
val = val | (b << shift);
}
return true; return true;
} }
bool BitStream4R::readVuint32SM(quint32 &val1, quint32 &val2, quint32 &val2Bits)
{
quint32 b, eb;
if (!readBytes(1, b))
return false;
if (!(b & 1)) {
val1 = b >> 3 & 0x1f;
val2 = b >> 1 & 3;
val2Bits = 2;
} else {
eb = b & 2;
val2 = b >> 2 & 0x3f;
val2Bits = eb * 2 + 6;
if (!readBytes((eb >> 1 | 2) - 1, b))
return false;
if (eb) {
val2 = val2 | (b & 0xf) << 6;
b = b >> 4 & 0xfff;
}
val1 = b;
}
return true;
}
bool BitStream4R::skip(quint32 bytes)
{
if (bytes * 8 > bitsAvailable())
return false;
quint32 ab = (32 - (_used + _unused))/8;
if (bytes <= ab)
_used += bytes * 8;
else {
quint32 seek = ((bytes - ab)/4)*4;
quint32 read = (bytes - ab)%4;
if (seek && !_file.seek(_hdl, _hdl.pos() - seek))
return false;
_length -= seek;
if (read) {
quint32 rb = qMin(_length, 4U);
if (!_file.readUInt32(_hdl, _data))
return false;
if (!_file.seek(_hdl, _hdl.pos() - 8))
return false;
_length -= rb;
_unused = (4 - rb) * 8;
_used = read * 8;
} else
_used = 32;
}
return true;
}
void BitStream4R::resize(quint32 length)
{
quint32 ab = (32 - _used)/8;
if (ab < length)
_length = length - ab;
else {
_length = 0;
_used += length * 8;
}
}

View File

@ -10,7 +10,7 @@ public:
bool read(int bits, quint32 &val); bool read(int bits, quint32 &val);
bool flush(); bool flush();
quint32 bitsAvailable() const {return _length * 8 + _remaining;} quint64 bitsAvailable() const {return (quint64)_length * 8 + _remaining;}
private: private:
const SubFile &_file; const SubFile &_file;
@ -25,15 +25,64 @@ public:
: _file(file), _hdl(hdl), _length(length), _used(32), _unused(0), : _file(file), _hdl(hdl), _length(length), _used(32), _unused(0),
_data(0) {} _data(0) {}
bool read(int bits, quint32 &val);
bool flush(); bool flush();
quint32 bitsAvailable() const {return _length * 8 + (32 - _used) - _unused;} quint64 bitsAvailable() const
{return (quint64)_length * 8 + (32 - _used) - _unused;}
private: protected:
const SubFile &_file; const SubFile &_file;
SubFile::Handle &_hdl; SubFile::Handle &_hdl;
quint32 _length, _used, _unused; quint32 _length, _used, _unused;
quint32 _data; quint32 _data;
}; };
class BitStream4F : public BitStream4 {
public:
BitStream4F(const SubFile &file, SubFile::Handle &hdl, quint32 length)
: BitStream4(file, hdl, length) {}
bool read(int bits, quint32 &val);
};
class BitStream4R : public BitStream4 {
public:
BitStream4R(const SubFile &file, SubFile::Handle &hdl, quint32 length);
template<typename T> bool read(int bits, T &val);
bool readBytes(int bytes, quint32 &val);
bool readVUInt32(quint32 &val);
bool readVuint32SM(quint32 &val1, quint32 &val2, quint32 &val2Bits);
bool skip(quint32 bytes);
void resize(quint32 length);
};
template<typename T>
bool BitStream4R::read(int bits, T &val)
{
if (bits <= 32 - (int)(_used + _unused)) {
val = bits ? (_data << _used) >> (32 - bits) : 0;
_used += bits;
return true;
}
if (_unused)
return false;
quint32 old = (_used < 32) ? (_data << _used) >> (32 - bits) : 0;
quint32 bytes = qMin(_length, 4U);
if (!_file.readUInt32(_hdl, _data))
return false;
if (!_file.seek(_hdl, _hdl.pos() - 8))
return false;
_length -= bytes;
_used -= 32 - bits;
_unused = (4 - bytes) * 8;
val = _data >> (32 - _used) | old;
return true;
}
#endif // BITSTREAM_H #endif // BITSTREAM_H

View File

@ -1,74 +1,30 @@
#include "huffmanstream.h" #include "huffmanstream.h"
bool HuffmanStreamF::init(bool line)
HuffmanStream::HuffmanStream(const SubFile &file, SubFile::Handle &hdl,
quint32 length, const HuffmanTable &table, bool line)
: BitStream4(file, hdl, length), _table(table), _symbolDataSize(0),
_symbolData(0)
{ {
if (line) { if (line) {
if (!(sign(_lonSign) && sign(_latSign))) if (!(sign(_lonSign) && sign(_latSign)))
return; return false;
} else { } else {
_lonSign = 0; _lonSign = 0;
_latSign = 0; _latSign = 0;
} }
quint32 eb; quint32 eb;
if (!read(1, eb)) if (!_bs.read(1, eb))
return; return false;
if (eb) { if (eb) {
qWarning("Extended polygon/lines not supported"); qWarning() << "Extended lines/polygons not supported";
flush();
}
}
bool HuffmanStream::sign(int &val)
{
quint32 bit;
val = 0;
if (!read(1, bit))
return false; return false;
if (bit) {
if (!read(1, bit))
return false;
val = bit ? -1 : 1;
} }
return true; return true;
} }
bool HuffmanStream::readDelta(int sign, qint32 &symbol) bool HuffmanStreamR::init()
{ {
quint8 size; if (!(sign(_lonSign) && sign(_latSign)))
quint32 next;
quint8 nextSize = qMin((quint32)(32 - _symbolDataSize), bitsAvailable());
if (!read(nextSize, next))
return false; return false;
_symbolData = (_symbolData << nextSize) | next;
_symbolDataSize += nextSize;
symbol = _table.symbol(_symbolData << (32 - _symbolDataSize), size);
if (size <= _symbolDataSize)
_symbolDataSize -= size;
else
return false;
if (symbol && !sign) {
if (!_symbolDataSize)
return false;
else {
sign = ((1U << (_symbolDataSize - 1)) & _symbolData) ? -1 : 1;
_symbolDataSize--;
}
}
symbol = sign * symbol;
return true; return true;
} }

View File

@ -4,10 +4,12 @@
#include "bitstream.h" #include "bitstream.h"
#include "huffmantable.h" #include "huffmantable.h"
class HuffmanStream : public BitStream4 { template <class BitStream>
class HuffmanStream {
public: public:
HuffmanStream(const SubFile &file, SubFile::Handle &hdl, quint32 length, HuffmanStream(BitStream &bitstream, const HuffmanTable &table)
const HuffmanTable &table, bool line); : _bs(bitstream), _table(table), _symbolDataSize(0), _symbolData(0),
_lonSign(0), _latSign(0) {}
bool readNext(qint32 &lonDelta, qint32 &latDelta) bool readNext(qint32 &lonDelta, qint32 &latDelta)
{ {
@ -17,19 +19,87 @@ public:
return (lonDelta || latDelta); return (lonDelta || latDelta);
} }
bool readOffset(qint32 &lonDelta, qint32 &latDelta)
{return (readDelta(1, lonDelta) && readDelta(1, latDelta));}
bool atEnd() const bool atEnd() const
{return _symbolDataSize + bitsAvailable() < _table.maxSymbolSize();} {return _symbolDataSize + _bs.bitsAvailable() < _table.maxSymbolSize();}
bool flush() {return _bs.flush();}
private: protected:
bool sign(int &val); bool sign(int &val);
bool readDelta(int sign, qint32 &delta); bool readDelta(int sign, qint32 &delta);
BitStream &_bs;
const HuffmanTable &_table; const HuffmanTable &_table;
quint32 _symbolDataSize; quint32 _symbolDataSize;
quint32 _symbolData; quint32 _symbolData;
int _lonSign, _latSign; int _lonSign, _latSign;
}; };
template <class BitStream>
bool HuffmanStream<BitStream>::sign(int &val)
{
quint32 bit;
val = 0;
if (!_bs.read(1, bit))
return false;
if (bit) {
if (!_bs.read(1, bit))
return false;
val = bit ? -1 : 1;
}
return true;
}
template <class BitStream>
bool HuffmanStream<BitStream>::readDelta(int sign, qint32 &symbol)
{
quint8 size;
quint32 next;
quint8 nextSize = qMin((quint64)(32 - _symbolDataSize), _bs.bitsAvailable());
if (!_bs.read(nextSize, next))
return false;
_symbolData = (_symbolData << nextSize) | next;
_symbolDataSize += nextSize;
symbol = _table.symbol(_symbolData << (32 - _symbolDataSize), size);
if (size <= _symbolDataSize)
_symbolDataSize -= size;
else
return false;
if (symbol && !sign) {
if (!_symbolDataSize)
return false;
else {
sign = ((1U << (_symbolDataSize - 1)) & _symbolData) ? -1 : 1;
_symbolDataSize--;
}
}
symbol = sign * symbol;
return true;
}
class HuffmanStreamF : public HuffmanStream<BitStream4F> {
public:
HuffmanStreamF(BitStream4F &bitstream, const HuffmanTable &table)
: HuffmanStream(bitstream, table) {}
bool init(bool line);
bool readOffset(qint32 &lonDelta, qint32 &latDelta)
{return (readDelta(1, lonDelta) && readDelta(1, latDelta));}
};
class HuffmanStreamR : public HuffmanStream<BitStream4R> {
public:
HuffmanStreamR(BitStream4R &bitstream, const HuffmanTable &table)
: HuffmanStream(bitstream, table) {}
bool init();
};
#endif // HUFFMANSTREAM_H #endif // HUFFMANSTREAM_H

View File

@ -42,6 +42,8 @@ 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; return true;
} }

View File

@ -13,6 +13,8 @@ public:
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;}
private: private:
bool getBuffer(const SubFile &file, SubFile::Handle &hdl, quint32 offset, bool getBuffer(const SubFile &file, SubFile::Handle &hdl, quint32 offset,
quint32 size, quint8 id); quint32 size, quint8 id);
@ -22,6 +24,8 @@ private:
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

View File

@ -59,7 +59,7 @@ IMG::IMG(const QString &fileName) : _file(fileName)
QByteArray nba(QByteArray(d1, sizeof(d1)) + QByteArray(d2, sizeof(d2))); QByteArray nba(QByteArray(d1, sizeof(d1)) + QByteArray(d2, sizeof(d2)));
_name = QString::fromLatin1(nba.constData(), nba.size()-1).trimmed(); _name = QString::fromLatin1(nba.constData(), nba.size()-1).trimmed();
_blockSize = 1 << (e1 + e2); _blockBits = e1 + e2;
// Read the FAT table // Read the FAT table
quint8 flag; quint8 flag;
@ -132,7 +132,6 @@ IMG::IMG(const QString &fileName) : _file(fileName)
} }
// Create tile tree // Create tile tree
int minMapZoom = 24; int minMapZoom = 24;
for (TileMap::const_iterator it = tileMap.constBegin(); for (TileMap::const_iterator it = tileMap.constBegin();
it != tileMap.constEnd(); ++it) { it != tileMap.constEnd(); ++it) {
@ -159,14 +158,19 @@ IMG::IMG(const QString &fileName) : _file(fileName)
minMapZoom = tile->zooms().min(); minMapZoom = tile->zooms().min();
} }
for (TileMap::const_iterator it = tileMap.constBegin(); // Detect and mark basemap
it != tileMap.constEnd(); ++it) { TileTree::Iterator it;
VectorTile *tile = it.value(); for (_tileTree.GetFirst(it); !_tileTree.IsNull(it); _tileTree.GetNext(it)) {
VectorTile *tile = _tileTree.GetAt(it);
if (tile->zooms().min() > minMapZoom) if (tile->zooms().min() > minMapZoom)
_baseMap = true; _baseMap = true;
if (tile->zooms().min() == minMapZoom) if (tile->zooms().min() == minMapZoom)
tile->markAsBasemap(); tile->markAsBasemap();
} }
// Allow some extra zoom out on maps without basemaps, but not too much as
// this would kill the rendering performance
if (!_baseMap)
_zooms.setMin(_zooms.min() - 2);
if (!_tileTree.Count()) if (!_tileTree.Count())
_errorString = "No usable map tile found"; _errorString = "No usable map tile found";
@ -197,9 +201,9 @@ template<class T> bool IMG::readValue(T &val)
bool IMG::readBlock(int blockNum, char *data) bool IMG::readBlock(int blockNum, char *data)
{ {
if (!_file.seek((qint64)blockNum * (qint64)_blockSize)) if (!_file.seek((quint64)blockNum << _blockBits))
return false; return false;
if (read(data, _blockSize) < _blockSize) if (read(data, 1U<<_blockBits) < 1U<<_blockBits)
return false; return false;
return true; return true;

View File

@ -14,14 +14,14 @@ public:
private: private:
friend class SubFile; friend class SubFile;
int blockSize() const {return _blockSize;} unsigned blockBits() const {return _blockBits;}
bool readBlock(int blockNum, char *data); bool readBlock(int blockNum, char *data);
qint64 read(char *data, qint64 maxSize); qint64 read(char *data, qint64 maxSize);
template<class T> bool readValue(T &val); template<class T> bool readValue(T &val);
QFile _file; QFile _file;
quint8 _key; quint8 _key;
int _blockSize; unsigned _blockBits;
}; };
#endif // IMG_H #endif // IMG_H

View File

@ -54,7 +54,7 @@ inline bool pointCb(VectorTile *tile, void *context)
} }
MapData::MapData() : _typ(0), _style(0), _zooms(15, 28), _baseMap(false), MapData::MapData() : _typ(0), _style(0), _zooms(24, 28), _baseMap(false),
_valid(false) _valid(false)
{ {
_polyCache.setMaxCost(CACHED_SUBDIVS_COUNT); _polyCache.setMaxCost(CACHED_SUBDIVS_COUNT);

View File

@ -1,5 +1,89 @@
#include "bitstream.h"
#include "huffmanstream.h"
#include "subdiv.h"
#include "nodfile.h"
#include "netfile.h" #include "netfile.h"
bool adjCnts(BitStream4R &bs, QVector<quint16> &cnts, quint16 &mask)
{
quint32 val, cnt, bits;
if (!bs.read(4, val))
return false;
cnt = ((val >> 2) & 3) + 2;
bits = ((val * 2) & 6) + 4;
mask = 1<<(3 + ((val * 2) & 6));
if (cnt == 5) {
if (!bs.read(8, cnt))
return false;
Q_ASSERT(cnt > 4);
}
if (cnt < 2)
return false;
cnts.resize(cnt - 1);
for (int i = 0; i < cnts.size(); i++)
if (!bs.read(bits, cnts[i]))
return false;
return true;
}
bool skipNodes(BitStream4R &bs, const QVector<quint16> &cnts, quint16 mask)
{
for (int i = 0; i < cnts.size(); i++) {
if (cnts.at(i) & mask) {
quint32 v1, v2, v2b;
if (!bs.readVuint32SM(v1, v2, v2b))
return false;
if (!bs.skip(v1))
return false;
}
}
return true;
}
bool seekToLevel(BitStream4R &bs, quint8 level)
{
quint32 v1, v2, v2b;
for (quint8 i = 1; i < level; ) {
if (!bs.readVuint32SM(v1, v2, v2b))
return false;
if (!bs.skip(v1))
return false;
Q_ASSERT(!(v2 & 2));
if (v2 & 2)
return false;
if (v2 & 1)
i++;
};
return true;
}
bool seekToLine(BitStream4R &bs, quint8 line)
{
quint32 v1, v2, v2b;
for (quint8 i = 0; i < line; i++) {
if (!bs.readVuint32SM(v1, v2, v2b))
return false;
if (!bs.skip(v1))
return false;
Q_ASSERT(!(v2 & 2));
if (v2 & 2)
return false;
}
return true;
}
bool NETFile::init(Handle &hdl) bool NETFile::init(Handle &hdl)
{ {
quint8 multiplier; quint8 multiplier;
@ -10,11 +94,121 @@ bool NETFile::init(Handle &hdl)
&& readUInt32(hdl, _size) && readUInt8(hdl, multiplier))) && readUInt32(hdl, _size) && readUInt8(hdl, multiplier)))
return false; return false;
if (hdrLen >= 0x47) {
quint32 info;
if (!(seek(hdl, _gmpOffset + 0x37) && readUInt32(hdl, info)))
return false;
_tableId = ((info >> 2) & 0xF);
if (!(seek(hdl, _gmpOffset + 0x43) && readUInt32(hdl, _linksOffset)
&& readUInt32(hdl, _linksSize) && readUInt8(hdl, _linksShift)))
return false;
}
_multiplier = 1<<multiplier; _multiplier = 1<<multiplier;
return true; return true;
} }
bool NETFile::link(const SubDiv *subdiv, Handle &hdl, NODFile *nod,
Handle &nodHdl, const NODFile::BlockInfo blockInfo, quint8 linkId,
quint8 lineId, const HuffmanTable &table, QList<IMG::Poly> *lines)
{
if (!_multiplier && !init(hdl))
return false;
// TODO
if (!subdiv->level())
return false;
NODFile::LinkInfo linkInfo;
if (!nod->linkInfo(nodHdl, blockInfo, linkId, linkInfo))
return false;
quint32 linkOffset = _linksOffset + (linkInfo.linkOffset << _linksShift);
Q_ASSERT(linkOffset <= _linksOffset + _linksSize);
quint8 s68 = (linkInfo.flags >> 0x12) & 1;
quint8 s69 = (linkInfo.flags >> 0x11) & 1;
quint8 s6a = (linkInfo.flags >> 0x13) & 1;
if (s6a == 1) {
QVector<quint16> ca;
quint16 mask;
if (!seek(hdl, linkOffset))
return false;
BitStream4R bs(*this, hdl, linkOffset - _linksOffset);
quint32 size;
if (!bs.readVUInt32(size))
return false;
if (s69 == 0) {
if (!adjCnts(bs, ca, mask))
return false;
}
if (s68 == 1) {
quint32 v1, v2, v2b;
if (!bs.readVuint32SM(v1, v2, v2b))
return false;
Q_ASSERT(v1);
if (!bs.skip(v1))
return false;
}
if (!skipNodes(bs, ca, mask))
return false;
if (!seekToLevel(bs, subdiv->level()))
return false;
if (!seekToLine(bs, lineId))
return false;
quint32 v1, v2, v2b;
if (!bs.readVuint32SM(v1, v2, v2b))
return false;
bs.resize(v1);
quint32 lon, lat;
if (!(bs.read(0x12 - v2b, lon) && bs.read(16, lat)))
return false;
if (2 < v2b)
lon |= (v2 >> 2) << (0x12U - v2b);
QPoint pos = QPoint(LS(subdiv->lon(), 8) + LS((qint16)lon,
32-subdiv->bits()), LS(subdiv->lat(), 8) + LS((qint16)lat,
32-subdiv->bits()));
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
IMG::Poly poly;
if (!nod->linkType(nodHdl, blockInfo, linkId, poly.type))
return false;
poly.boundingRect = RectC(c, c);
poly.points.append(QPointF(c.lon(), c.lat()));
Q_ASSERT(_tableId == table.id());
HuffmanStreamR stream(bs, table);
if (!stream.init())
return false;
qint32 lonDelta, latDelta;
while (stream.readNext(lonDelta, latDelta)) {
pos.rx() += LS(lonDelta, 32-subdiv->bits());
if (pos.rx() < 0 && subdiv->lon() >= 0)
pos.rx() = 0x7fffffff;
pos.ry() += LS(latDelta, 32-subdiv->bits());
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
poly.points.append(QPointF(c.lon(), c.lat()));
poly.boundingRect = poly.boundingRect.united(c);
}
lines->append(poly);
}
return true;
}
bool NETFile::lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset) bool NETFile::lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset)
{ {
if (!_multiplier && !init(hdl)) if (!_multiplier && !init(hdl))

View File

@ -1,25 +1,37 @@
#ifndef NETFILE_H #ifndef NETFILE_H
#define NETFILE_H #define NETFILE_H
#include "img.h"
#include "subfile.h" #include "subfile.h"
#include "nodfile.h"
class NODFile;
class LBLFile;
class SubDiv;
class HuffmanTable;
class NETFile : public SubFile class NETFile : public SubFile
{ {
public: public:
NETFile(IMG *img) NETFile(IMG *img) : SubFile(img), _offset(0), _size(0), _linksOffset(0),
: SubFile(img), _offset(0), _size(0), _multiplier(0) {} _linksSize(0), _multiplier(0), _linksShift(0) {}
NETFile(const QString &path) NETFile(const QString &path) : SubFile(path), _offset(0), _size(0),
: SubFile(path), _offset(0), _size(0), _multiplier(0) {} _linksOffset(0), _linksSize(0), _multiplier(0), _linksShift(0) {}
NETFile(SubFile *gmp, quint32 offset) NETFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset),
: SubFile(gmp, offset), _offset(0), _size(0), _multiplier(0) {} _offset(0), _size(0), _linksOffset(0), _linksSize(0), _multiplier(0),
_linksShift(0) {}
bool lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset); bool lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset);
bool link(const SubDiv *subdiv, Handle &hdl, NODFile *nod, Handle &nodHdl,
const NODFile::BlockInfo blockInfo, quint8 linkId, quint8 lineId,
const HuffmanTable &table, QList<IMG::Poly> *lines);
private: private:
bool init(Handle &hdl); bool init(Handle &hdl);
quint32 _offset, _size; quint32 _offset, _size, _linksOffset, _linksSize;
quint8 _multiplier; quint8 _multiplier, _linksShift;
quint8 _tableId;
}; };
#endif // NETFILE_H #endif // NETFILE_H

148
src/map/IMG/nodfile.cpp Normal file
View File

@ -0,0 +1,148 @@
#include "bitstream.h"
#include "nodfile.h"
bool NODFile::init(Handle &hdl)
{
quint16 hdrLen;
if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen)))
return false;
if (hdrLen >= 0x7b) {
if (!(seek(hdl, _gmpOffset + 0x21) && readUInt8(hdl, _blockShift)
&& readUInt8(hdl, _nodeShift)))
return false;
if (!(seek(hdl, _gmpOffset + 0x67) && readUInt32(hdl, _blockOffset)
&& readUInt32(hdl, _blockSize) && readUInt16(hdl, _blockRecordSize)
&& readUInt32(hdl, _indexOffset) && readUInt32(hdl, _indexSize)
&& readUInt16(hdl, _indexRecordSize) && readUInt32(hdl, _indexFlags)))
return false;
}
return true;
}
quint32 NODFile::indexIdSize(Handle &hdl)
{
if (!_indexRecordSize && !init(hdl))
return 0;
quint32 indexCount = _indexSize / _indexRecordSize;
if (indexCount <= 0x100)
return 1;
else if (indexCount <= 0x1000)
return 2;
else if (indexCount <= 0x1000000)
return 3;
else
return 0;
}
bool NODFile::blockInfo(Handle &hdl, quint32 blockIndexId,
BlockInfo &blockInfo) const
{
quint32 blockOffset;
quint32 offset = _indexRecordSize * blockIndexId + _indexOffset;
quint32 offsetSize = (_indexFlags & 3) + 1;
Q_ASSERT(offset <= _indexOffset + _indexSize);
if (!(seek(hdl, offset) && readVUInt32(hdl, offsetSize, blockOffset)))
return false;
blockInfo.offset = (blockOffset << _blockShift) + _blockOffset;
if (!(seek(hdl, blockInfo.offset) && readUInt16(hdl, blockInfo.h0)
&& readUInt32(hdl, blockInfo.h2) && readUInt32(hdl, blockInfo.h6)
&& readUInt32(hdl, blockInfo.ha) && readUInt16(hdl, blockInfo.he)
&& readUInt8(hdl, blockInfo.h10) && readUInt8(hdl, blockInfo.h11)
&& readUInt8(hdl, blockInfo.h12)))
return false;
return true;
}
bool NODFile::linkInfo(Handle &hdl, const BlockInfo &blockInfo, quint32 linkId,
LinkInfo &linkInfo) const
{
Q_ASSERT(linkId < blockInfo.h10);
quint32 infoOffset = ((blockInfo.he * linkId) >> 3) + 0x13
+ ((blockInfo.h0 >> 0xb) & 1) + blockInfo.offset;
quint32 s1 = ((blockInfo.h0 >> 2) & 0x1f) + 8;
quint32 s2 = (blockInfo.h0 >> 7) & 0xf;
quint32 skip = (blockInfo.he * linkId) & 7;
Q_ASSERT(infoOffset <= _blockOffset + _blockSize);
if (!seek(hdl, infoOffset))
return false;
quint32 unused, flags;
BitStream1 bs(*this, hdl, _blockOffset + _blockSize - infoOffset);
if (!(bs.read(skip, unused) && bs.read(0xc, flags)))
return false;
linkInfo.flags = ((flags << 8) & 0xf0000) | (flags & 0xff);
if (!(flags << 8 & 0x10000)) {
if (!bs.read(s1, linkInfo.linkOffset))
return false;
} else {
if (!bs.read(s1 - s2, linkInfo.linkOffset))
return false;
linkInfo.linkOffset += blockInfo.ha;
}
return true;
}
bool NODFile::linkType(Handle &hdl, const BlockInfo &blockInfo, quint8 linkId,
quint32 &type) const
{
quint32 offset = ((blockInfo.h10 * blockInfo.he + 7) >> 3) + 0x13 +
blockInfo.offset + ((blockInfo.h0 >> 0xb) & 1) + (quint32)blockInfo.h11
* 3;
quint32 low = 0;
quint32 high = blockInfo.h12 - 1;
quint32 pos;
quint16 val;
if (high > 1) {
do {
pos = (low + high) / 2;
if (!seek(hdl, offset + _blockRecordSize * pos))
return false;
if (!readUInt16(hdl, val))
return false;
quint32 tmp = pos;
if ((val >> 8) <= linkId) {
low = pos;
tmp = high;
}
high = tmp;
} while (low + 1 < high);
}
if (!seek(hdl, offset + _blockRecordSize * low))
return false;
if (!readUInt16(hdl, val))
return false;
type = val & 0x3f;
if ((low < high) && (pos != high)) {
if (!seek(hdl, offset + _blockRecordSize * high))
return false;
if (!readUInt16(hdl, val))
return false;
if ((val >> 8) <= linkId) {
type = (val & 0x3f);
}
}
type *= 256;
return true;
}

54
src/map/IMG/nodfile.h Normal file
View File

@ -0,0 +1,54 @@
#ifndef NODFILE_H
#define NODFILE_H
#include "img.h"
#include "subfile.h"
class NODFile : public SubFile
{
public:
struct BlockInfo {
quint32 offset;
quint16 h0;
quint32 h2;
quint32 h6;
quint32 ha;
quint16 he;
quint8 h10; // links count
quint8 h11;
quint8 h12;
};
struct LinkInfo {
quint32 linkOffset;
quint32 flags;
};
NODFile(IMG *img) : SubFile(img), _indexOffset(0), _indexSize(0),
_indexFlags(0), _blockOffset(0), _blockSize(0), _indexRecordSize(0),
_blockRecordSize(0), _blockShift(0), _nodeShift(0) {}
NODFile(const QString &path) : SubFile(path), _indexOffset(0), _indexSize(0),
_indexFlags(0), _blockOffset(0), _blockSize(0), _indexRecordSize(0),
_blockRecordSize(0), _blockShift(0), _nodeShift(0) {}
NODFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset),
_indexOffset(0), _indexSize(0),_indexFlags(0), _blockOffset(0),
_blockSize(0), _indexRecordSize(0), _blockRecordSize(0), _blockShift(0),
_nodeShift(0) {}
quint32 indexIdSize(Handle &hdl);
bool blockInfo(Handle &hdl, quint32 blockIndexId,
BlockInfo &blockInfo) const;
bool linkInfo(Handle &hdl, const BlockInfo &blockInfo, quint32 linkId,
LinkInfo &linkInfo) const;
bool linkType(Handle &hdl, const BlockInfo &blockInfo, quint8 linkId,
quint32 &type) const;
private:
bool init(Handle &hdl);
quint32 _indexOffset, _indexSize, _indexFlags, _blockOffset, _blockSize;
quint16 _indexRecordSize, _blockRecordSize;
quint8 _blockShift, _nodeShift;
};
#endif // NETFILE_H

View File

@ -5,9 +5,12 @@
#include "huffmanstream.h" #include "huffmanstream.h"
#include "lblfile.h" #include "lblfile.h"
#include "netfile.h" #include "netfile.h"
#include "nodfile.h"
#include "rgnfile.h" #include "rgnfile.h"
#define MASK(bits) ((2U << ((bits) - 1U)) - 1U)
static quint64 pointId(const QPoint &pos, quint32 type, quint32 labelPtr) static quint64 pointId(const QPoint &pos, quint32 type, quint32 labelPtr)
{ {
quint64 id; quint64 id;
@ -52,8 +55,7 @@ bool RGNFile::skipClassFields(Handle &hdl) const
return seek(hdl, hdl.pos() + rs); return seek(hdl, hdl.pos() + rs);
} }
bool RGNFile::skipLclFields(Handle &hdl, const quint32 flags[3], bool RGNFile::skipLclFields(Handle &hdl, const quint32 flags[3]) const
SegmentType type) const
{ {
quint32 bitfield = 0xFFFFFFFF; quint32 bitfield = 0xFFFFFFFF;
@ -61,29 +63,40 @@ bool RGNFile::skipLclFields(Handle &hdl, const quint32 flags[3],
if (!readVBitfield32(hdl, bitfield)) if (!readVBitfield32(hdl, bitfield))
return false; return false;
for (int i = 0; i < 29; i++) { for (int i = 0, j = 0; i < 29; i++) {
if ((flags[0] >> i) & 1) { if ((flags[0] >> i) & 1) {
if (bitfield & 1) { if (bitfield & 1) {
quint32 m = flags[(i >> 4) + 1] >> ((i * 2) & 0x1e) & 3; quint32 m = flags[(j >> 4) + 1] >> ((j * 2) & 0x1e) & 3;
switch (i) {
case 5: quint32 skip = 0;
if (m == 1 && type == Point) { if (m == 3) {
quint16 u16; if (!readVUInt32(hdl, skip))
if (!readUInt16(hdl, u16)) return false;
} else
skip = m + 1;
if (!seek(hdl, hdl.pos() + skip))
return false; return false;
} }
break;
default:
break;
}
}
bitfield >>= 1; bitfield >>= 1;
j++;
} }
} }
return true; return true;
} }
bool RGNFile::skipGblFields(Handle &hdl, quint32 flags) const
{
int cnt = 0;
do {
cnt = cnt + (flags & 3);
flags = flags >> 2;
} while (flags != 0);
return seek(hdl, hdl.pos() + cnt);
}
void RGNFile::clearFlags() void RGNFile::clearFlags()
{ {
memset(_polygonsFlags, 0, sizeof(_polygonsFlags)); memset(_polygonsFlags, 0, sizeof(_polygonsFlags));
@ -102,14 +115,17 @@ bool RGNFile::init(Handle &hdl)
if (hdrLen >= 0x68) { if (hdrLen >= 0x68) {
if (!(readUInt32(hdl, _polygonsOffset) && readUInt32(hdl, _polygonsSize) if (!(readUInt32(hdl, _polygonsOffset) && readUInt32(hdl, _polygonsSize)
&& seek(hdl, _gmpOffset + 0x2D) && readUInt32(hdl, _polygonsFlags[0]) && seek(hdl, _gmpOffset + 0x29) && readUInt32(hdl, _polygonGblFlags)
&& readUInt32(hdl, _polygonsFlags[1]) && readUInt32(hdl, _polygonsFlags[2]) && readUInt32(hdl, _polygonsFlags[0]) && readUInt32(hdl, _polygonsFlags[1])
&& readUInt32(hdl, _polygonsFlags[2])
&& readUInt32(hdl, _linesOffset) && readUInt32(hdl, _linesSize) && readUInt32(hdl, _linesOffset) && readUInt32(hdl, _linesSize)
&& seek(hdl, _gmpOffset + 0x49) && readUInt32(hdl, _linesFlags[0]) && seek(hdl, _gmpOffset + 0x45) && readUInt32(hdl, _linesGblFlags)
&& readUInt32(hdl, _linesFlags[1]) && readUInt32(hdl, _linesFlags[2]) && readUInt32(hdl, _linesFlags[0]) && readUInt32(hdl, _linesFlags[1])
&& readUInt32(hdl, _linesFlags[2])
&& readUInt32(hdl, _pointsOffset) && readUInt32(hdl, _pointsSize) && readUInt32(hdl, _pointsOffset) && readUInt32(hdl, _pointsSize)
&& seek(hdl, _gmpOffset + 0x65) && readUInt32(hdl, _pointsFlags[0]) && seek(hdl, _gmpOffset + 0x61) && readUInt32(hdl, _pointsGblFlags)
&& readUInt32(hdl, _pointsFlags[1]) && readUInt32(hdl, _pointsFlags[2]))) && readUInt32(hdl, _pointsFlags[0]) && readUInt32(hdl, _pointsFlags[1])
&& readUInt32(hdl, _pointsFlags[2])))
return false; return false;
} }
@ -230,6 +246,7 @@ bool RGNFile::extPolyObjects(Handle &hdl, const SubDiv *subdiv, quint32 shift,
&& readInt16(hdl, lon) && readInt16(hdl, lat) && readInt16(hdl, lon) && readInt16(hdl, lat)
&& readVUInt32(hdl, len))) && readVUInt32(hdl, len)))
return false; return false;
Q_ASSERT(hdl.pos() + len <= segment.end());
poly.type = 0x10000 | (quint16(type)<<8) | (subtype & 0x1F); poly.type = 0x10000 | (quint16(type)<<8) | (subtype & 0x1F);
labelPtr = 0; labelPtr = 0;
@ -239,8 +256,10 @@ bool RGNFile::extPolyObjects(Handle &hdl, const SubDiv *subdiv, quint32 shift,
LS(subdiv->lat(), 8) + LS(lat, (32-subdiv->bits()))); LS(subdiv->lat(), 8) + LS(lat, (32-subdiv->bits())));
qint32 lonDelta, latDelta; qint32 lonDelta, latDelta;
HuffmanStream stream(*this, hdl, len, _huffmanTable, BitStream4F bs(*this, hdl, len);
segmentType == Line); HuffmanStreamF stream(bs, _huffmanTable);
if (!stream.init(segmentType == Line))
return false;
if (shift) { if (shift) {
if (!stream.readOffset(lonDelta, latDelta)) if (!stream.readOffset(lonDelta, latDelta))
@ -298,7 +317,11 @@ bool RGNFile::extPolyObjects(Handle &hdl, const SubDiv *subdiv, quint32 shift,
if (subtype & 0x80 && !skipClassFields(hdl)) if (subtype & 0x80 && !skipClassFields(hdl))
return false; return false;
if (subtype & 0x40 && !skipLclFields(hdl, segmentType == Line if (subtype & 0x40 && !skipLclFields(hdl, segmentType == Line
? _linesFlags : _polygonsFlags, segmentType)) ? _linesFlags : _polygonsFlags))
return false;
quint32 gblFlags = (segmentType == Line)
? _linesGblFlags : _polygonGblFlags;
if (gblFlags && !skipGblFields(hdl, gblFlags))
return false; return false;
if (lbl && (labelPtr & 0x3FFFFF)) if (lbl && (labelPtr & 0x3FFFFF))
@ -317,6 +340,7 @@ bool RGNFile::pointObjects(Handle &hdl, const SubDiv *subdiv,
const SubDiv::Segment &segment = (segmentType == IndexedPoint) const SubDiv::Segment &segment = (segmentType == IndexedPoint)
? subdiv->idxPoints() : subdiv->points(); ? subdiv->idxPoints() : subdiv->points();
if (!segment.isValid()) if (!segment.isValid())
return true; return true;
if (!seek(hdl, segment.offset())) if (!seek(hdl, segment.offset()))
@ -379,7 +403,9 @@ bool RGNFile::extPointObjects(Handle &hdl, const SubDiv *subdiv, LBLFile *lbl,
return false; return false;
if (subtype & 0x80 && !skipClassFields(hdl)) if (subtype & 0x80 && !skipClassFields(hdl))
return false; return false;
if (subtype & 0x40 && !skipLclFields(hdl, _pointsFlags, Point)) if (subtype & 0x40 && !skipLclFields(hdl, _pointsFlags))
return false;
if (_pointsGblFlags && !skipGblFields(hdl, _pointsGblFlags))
return false; return false;
QPoint pos(subdiv->lon() + LS(lon, 24-subdiv->bits()), QPoint pos(subdiv->lon() + LS(lon, 24-subdiv->bits()),
@ -403,6 +429,86 @@ bool RGNFile::extPointObjects(Handle &hdl, const SubDiv *subdiv, LBLFile *lbl,
return true; return true;
} }
bool RGNFile::links(Handle &hdl, const SubDiv *subdiv, NETFile *net,
Handle &netHdl, NODFile *nod, Handle &nodHdl, QList<IMG::Poly> *lines) const
{
quint32 size, blockIndexIdSize, blockIndexId;
quint8 flags;
const SubDiv::Segment &segment = subdiv->roadReferences();
if (!segment.isValid())
return true;
if (!seek(hdl, segment.offset()))
return false;
if (!net || !nod)
return false;
if (!(blockIndexIdSize = nod->indexIdSize(nodHdl)))
return false;
while (hdl.pos() < (int)segment.end()) {
if (!readVUInt32(hdl, size))
return false;
int pos = hdl.pos();
if (!(readUInt8(hdl, flags) && readVUInt32(hdl, blockIndexIdSize,
blockIndexId)))
return false;
quint8 bits[3];
for (int i = 0; i < 3; i++)
bits[i] = 0x4000a08 >> (((flags >> (2*i) & 3) << 3) ^ 0x10);
quint8 byteSize = ((bits[0] + bits[1] + bits[2]) + 7) >> 3;
quint32 counts;
if (!readVUInt32(hdl, byteSize, counts))
return false;
quint16 b8 = bits[0] ? (MASK(bits[0]) & counts) + 1 : 0;
quint16 b10 = bits[1] ? (MASK(bits[1]) & (counts >> bits[0])) + 1 : 0;
quint16 b16 = bits[2] ? (MASK(bits[2]) & (counts >> (bits[0] + bits[1])))
+ 1 : 0;
NODFile::BlockInfo blockInfo;
if (!nod->blockInfo(nodHdl, blockIndexId, blockInfo))
return false;
quint8 linkId, lineId;
for (int i = 0; i < b8 + b10 + b16; i++) {
if (!b8 || b8 <= i) {
quint16 v16;
if (!readUInt16(hdl, v16))
return false;
if (!b16 || b8 + b16 <= i) {
int shift = ((i - (b8 + b16)) * 10) % 8;
linkId = (quint8)(v16 >> shift);
lineId = (((v16 >> shift) >> 8) & 3) + 1;
if (shift < 6 && i < b8 + b10 + b16 - 1)
seek(hdl, hdl.pos() - 1);
} else {
linkId = (quint8)v16;
lineId = v16 >> 8;
Q_ASSERT(lineId > 4);
}
} else {
if (!readUInt8(hdl, linkId))
return false;
lineId = 0;
}
net->link(subdiv, netHdl, nod, nodHdl, blockInfo, linkId, lineId,
_huffmanTable, lines);
}
Q_ASSERT(pos + (int)size == hdl.pos());
}
return true;
}
QMap<RGNFile::SegmentType, SubDiv::Segment> RGNFile::segments(Handle &hdl, QMap<RGNFile::SegmentType, SubDiv::Segment> RGNFile::segments(Handle &hdl,
SubDiv *subdiv) const SubDiv *subdiv) const
{ {

View File

@ -8,6 +8,7 @@
class LBLFile; class LBLFile;
class NETFile; class NETFile;
class NODFile;
class RGNFile : public SubFile class RGNFile : public SubFile
{ {
@ -46,6 +47,8 @@ public:
QList<IMG::Poly> *polys) const; QList<IMG::Poly> *polys) const;
bool extPointObjects(Handle &hdl, const SubDiv *subdiv, LBLFile *lbl, bool extPointObjects(Handle &hdl, const SubDiv *subdiv, LBLFile *lbl,
Handle &lblHdl, QList<IMG::Point> *points) const; Handle &lblHdl, QList<IMG::Point> *points) const;
bool links(Handle &hdl, const SubDiv *subdiv, NETFile *net, Handle &netHdl,
NODFile *nod, Handle &nodHdl, QList<IMG::Poly> *lines) const;
bool subdivInit(Handle &hdl, SubDiv *subdiv) const; bool subdivInit(Handle &hdl, SubDiv *subdiv) const;
@ -54,8 +57,9 @@ private:
const; const;
void clearFlags(); void clearFlags();
bool skipClassFields(Handle &hdl) const; bool skipClassFields(Handle &hdl) const;
bool skipLclFields(Handle &hdl, const quint32 flags[3], SegmentType type) bool skipLclFields(Handle &hdl, const quint32 flags[3])
const; const;
bool skipGblFields(Handle &hdl, quint32 flags) const;
quint32 _offset; quint32 _offset;
quint32 _size; quint32 _size;
@ -69,6 +73,9 @@ private:
quint32 _pointsOffset; quint32 _pointsOffset;
quint32 _pointsSize; quint32 _pointsSize;
quint32 _pointsFlags[3]; quint32 _pointsFlags[3];
quint32 _polygonGblFlags;
quint32 _linesGblFlags;
quint32 _pointsGblFlags;
HuffmanTable _huffmanTable; HuffmanTable _huffmanTable;

View File

@ -21,8 +21,9 @@ public:
quint32 _offset, _end; quint32 _offset, _end;
}; };
SubDiv(quint32 offset, qint32 lon, qint32 lat, int bits, quint8 objects) SubDiv(quint32 offset, qint32 lon, qint32 lat, quint8 level, quint8 bits,
: _lon(lon), _lat(lat), _bits(bits), _init(false) quint8 objects) : _lon(lon), _lat(lat), _level(level), _bits(bits),
_init(false)
{ {
_tre.objects = objects; _tre.objects = objects;
_tre.offset = offset; _tre.offset = offset;
@ -78,6 +79,7 @@ public:
qint32 lon() const {return _lon;} qint32 lon() const {return _lon;}
qint32 lat() const {return _lat;} qint32 lat() const {return _lat;}
quint8 bits() const {return _bits;} quint8 bits() const {return _bits;}
quint8 level() const {return _level;}
// Valid only after initialization // Valid only after initialization
Segment points() const Segment points() const
@ -94,6 +96,8 @@ public:
{return Segment(_rgn.extLinesOffset, _rgn.extLinesEnd);} {return Segment(_rgn.extLinesOffset, _rgn.extLinesEnd);}
Segment extPolygons() const Segment extPolygons() const
{return Segment(_rgn.extPolygonsOffset, _rgn.extPolygonsEnd);} {return Segment(_rgn.extPolygonsOffset, _rgn.extPolygonsEnd);}
Segment roadReferences() const
{return Segment(_rgn.roadReferencesOffset, _rgn.roadReferencesEnd);}
// Valid only until initialization // Valid only until initialization
quint8 objects() const {return _tre.objects;} quint8 objects() const {return _tre.objects;}
@ -142,6 +146,7 @@ private:
}; };
qint32 _lon, _lat; qint32 _lon, _lat;
quint8 _level;
quint8 _bits; quint8 _bits;
bool _init; bool _init;
union { union {

View File

@ -3,26 +3,28 @@
#include "subfile.h" #include "subfile.h"
#define mod2n(x, m) ((x) & ((m) - 1));
bool SubFile::seek(Handle &handle, quint32 pos) const bool SubFile::seek(Handle &handle, quint32 pos) const
{ {
if (handle._file) { if (handle._file) {
int blockNum = pos / BLOCK_SIZE; int blockNum = pos >> BLOCK_BITS;
if (handle._blockNum != blockNum) { if (handle._blockNum != blockNum) {
if (!handle._file->seek((qint64)blockNum * BLOCK_SIZE)) if (!handle._file->seek((quint64)blockNum << BLOCK_BITS))
return false; return false;
if (handle._file->read(handle._data.data(), BLOCK_SIZE) < 0) if (handle._file->read(handle._data.data(), (1<<BLOCK_BITS)) < 0)
return false; return false;
handle._blockNum = blockNum; handle._blockNum = blockNum;
} }
handle._blockPos = pos % BLOCK_SIZE; handle._blockPos = mod2n(pos, 1U<<BLOCK_BITS);
handle._pos = pos; handle._pos = pos;
return true; return true;
} else { } else {
quint32 blockSize = _img->blockSize(); quint32 blockBits = _img->blockBits();
int blockNum = pos / blockSize; int blockNum = pos >> blockBits;
if (handle._blockNum != blockNum) { if (handle._blockNum != blockNum) {
if (blockNum >= _blocks->size()) if (blockNum >= _blocks->size())
@ -32,7 +34,7 @@ bool SubFile::seek(Handle &handle, quint32 pos) const
handle._blockNum = blockNum; handle._blockNum = blockNum;
} }
handle._blockPos = pos % blockSize; handle._blockPos = mod2n(pos, 1U<<blockBits);
handle._pos = pos; handle._pos = pos;
return true; return true;
@ -70,6 +72,22 @@ bool SubFile::readVUInt32(Handle &hdl, quint32 &val) const
return true; return true;
} }
bool SubFile::readVUInt32(Handle &hdl, quint32 bytes, quint32 &val) const
{
switch (bytes) {
case 1:
return readUInt8(hdl, val);
case 2:
return readUInt16(hdl, val);
case 3:
return readUInt24(hdl, val);
case 4:
return readUInt32(hdl, val);
default:
return false;
}
}
bool SubFile::readVBitfield32(Handle &hdl, quint32 &bitfield) const bool SubFile::readVBitfield32(Handle &hdl, quint32 &bitfield) const
{ {
quint8 bits; quint8 bits;

View File

@ -6,12 +6,12 @@
#include "img.h" #include "img.h"
#define BLOCK_SIZE 4096 #define BLOCK_BITS 12 /* 4096 bytes */
class SubFile class SubFile
{ {
public: public:
enum Type {Unknown, TRE, RGN, LBL, NET, TYP, GMP}; enum Type {Unknown, TRE, RGN, LBL, NET, NOD, TYP, GMP};
class Handle class Handle
{ {
@ -22,9 +22,9 @@ public:
if (subFile && subFile->_path) { if (subFile && subFile->_path) {
_file = new QFile(*(subFile->_path)); _file = new QFile(*(subFile->_path));
_file->open(QIODevice::ReadOnly); _file->open(QIODevice::ReadOnly);
_data.resize(BLOCK_SIZE); _data.resize(1U<<BLOCK_BITS);
} else if (subFile) } else if (subFile)
_data.resize(subFile->_img->blockSize()); _data.resize(1U<<subFile->_img->blockBits());
} }
~Handle() {delete _file;} ~Handle() {delete _file;}
@ -132,6 +132,7 @@ public:
} }
bool readVUInt32(Handle &hdl, quint32 &val) const; bool readVUInt32(Handle &hdl, quint32 &val) const;
bool readVUInt32(Handle &hdl, quint32 bytes, quint32 &val) const;
bool readVBitfield32(Handle &hdl, quint32 &bitfield) const; bool readVBitfield32(Handle &hdl, quint32 &bitfield) const;
QString fileName() const {return _path ? *_path : _img->fileName();} QString fileName() const {return _path ? *_path : _img->fileName();}
@ -142,7 +143,7 @@ protected:
private: private:
bool readByte(Handle &handle, quint8 &val) const bool readByte(Handle &handle, quint8 &val) const
{ {
int blockSize = _img ? _img->blockSize() : BLOCK_SIZE; int blockSize = _img ? 1U<<_img->blockBits() : 1U<<BLOCK_BITS;
val = handle._data.at(handle._blockPos++); val = handle._data.at(handle._blockPos++);
handle._pos++; handle._pos++;
return (handle._blockPos >= blockSize) return (handle._blockPos >= blockSize)

View File

@ -70,14 +70,16 @@ bool TREFile::init()
return false; return false;
if (hdrLen > 0x9A) { if (hdrLen > 0x9A) {
// TRE7 info // TRE7 info + flags
if (!(seek(hdl, _gmpOffset + 0x7C) && readUInt32(hdl, _extended.offset) if (!(seek(hdl, _gmpOffset + 0x7C) && readUInt32(hdl, _extended.offset)
&& readUInt32(hdl, _extended.size) && readUInt32(hdl, _extended.size)
&& readUInt16(hdl, _extended.itemSize))) && readUInt16(hdl, _extended.itemSize) && readUInt32(hdl, _flags)))
return false;
// flags
if (!(seek(hdl, _gmpOffset + 0x86) && readUInt32(hdl, _flags)))
return false; return false;
} else {
_extended.offset = 0;
_extended.size = 0;
_extended.itemSize = 0;
_flags = 0;
} }
// Tile levels // Tile levels
@ -120,15 +122,43 @@ bool TREFile::init()
return (_firstLevel >= 0); return (_firstLevel >= 0);
} }
int TREFile::readExtEntry(Handle &hdl, quint32 &polygons, quint32 &lines,
quint32 &points)
{
int rb = 0;
if (_flags & 1) {
if (!readUInt32(hdl, polygons))
return -1;
rb += 4;
} else
polygons = 0;
if (_flags & 2) {
if (!readUInt32(hdl, lines))
return -1;
rb += 4;
} else
lines = 0;
if (_flags & 4) {
if (!readUInt32(hdl, points))
return -1;
rb += 4;
} else
points = 0;
return rb;
}
bool TREFile::load(int idx) bool TREFile::load(int idx)
{ {
Handle hdl(this); Handle hdl(this);
QList<SubDiv*> sl; QList<SubDiv*> sl;
SubDiv *s = 0; SubDiv *s = 0;
SubDivTree *tree = new SubDivTree(); SubDivTree *tree = new SubDivTree();
const MapLevel &level = _levels.at(idx);
_subdivs.insert(_levels.at(idx).bits, tree); _subdivs.insert(level.bits, tree);
quint32 skip = 0; quint32 skip = 0;
for (int i = 0; i < idx; i++) for (int i = 0; i < idx; i++)
@ -137,7 +167,7 @@ bool TREFile::load(int idx)
if (!seek(hdl, _subdivOffset + skip * 16)) if (!seek(hdl, _subdivOffset + skip * 16))
return false; return false;
for (int j = 0; j < _levels.at(idx).subdivs; j++) { for (int j = 0; j < level.subdivs; j++) {
quint32 oo; quint32 oo;
qint32 lon, lat, width, height; qint32 lon, lat, width, height;
quint16 nextLevel; quint16 nextLevel;
@ -156,10 +186,10 @@ bool TREFile::load(int idx)
s->setEnd(offset); s->setEnd(offset);
width &= 0x7FFF; width &= 0x7FFF;
width = LS(width, 24 - _levels.at(idx).bits); width = LS(width, 24 - level.bits);
height = LS(height, 24 - _levels.at(idx).bits); height = LS(height, 24 - level.bits);
s = new SubDiv(offset, lon, lat, _levels.at(idx).bits, objects); s = new SubDiv(offset, lon, lat, level.level, level.bits, objects);
sl.append(s); sl.append(s);
double min[2], max[2]; double min[2], max[2];
@ -184,36 +214,31 @@ bool TREFile::load(int idx)
// Objects with extended types (TRE7) // Objects with extended types (TRE7)
if (_extended.size && _extended.itemSize >= 12) { if (_extended.size && _extended.itemSize) {
/* Some maps skip entries for the inherited levels, some don't. Our
decision is based on the difference between the extended subdivs
count and the total subdivs count. */
quint32 totalSubdivs = 0; quint32 totalSubdivs = 0;
for (int i = 0; i < _levels.size(); i++) for (int i = 0; i < _levels.size(); i++)
totalSubdivs += _levels.at(i).subdivs; totalSubdivs += _levels.at(i).subdivs;
quint32 extendedSubdivs = _extended.size / _extended.itemSize; quint32 extendedSubdivs = _extended.size / _extended.itemSize;
quint32 diff = totalSubdivs - extendedSubdivs + 1; quint32 diff = totalSubdivs - extendedSubdivs + 1;
quint32 polygons, lines, points;
if (!seek(hdl, _extended.offset + (skip - diff) * _extended.itemSize)) if (!seek(hdl, _extended.offset + (skip - diff) * _extended.itemSize))
goto error; goto error;
quint32 polygons, lines, points;
int rb;
for (int i = 0; i < sl.size(); i++) { for (int i = 0; i < sl.size(); i++) {
if (!(readUInt32(hdl, polygons) && readUInt32(hdl, lines) if ((rb = readExtEntry(hdl, polygons, lines, points)) < 0)
&& readUInt32(hdl, points)))
goto error; goto error;
sl.at(i)->setExtOffsets(polygons, lines, points); sl.at(i)->setExtOffsets(polygons, lines, points);
if (i) if (i)
sl.at(i-1)->setExtEnds(polygons, lines, points); sl.at(i-1)->setExtEnds(polygons, lines, points);
if (!seek(hdl, hdl.pos() + _extended.itemSize - 12)) if (!seek(hdl, hdl.pos() + _extended.itemSize - rb))
goto error; goto error;
} }
if (idx != _levels.size() - 1) { if (idx != _levels.size() - 1) {
if (!(readUInt32(hdl, polygons) && readUInt32(hdl, lines) if (readExtEntry(hdl, polygons, lines, points) < 0)
&& readUInt32(hdl, points)))
goto error; goto error;
sl.last()->setExtEnds(polygons, lines, points); sl.last()->setExtEnds(polygons, lines, points);
} }

View File

@ -46,9 +46,8 @@ private:
bool load(int idx); bool load(int idx);
int level(int bits, bool baseMap); int level(int bits, bool baseMap);
bool parsePoly(Handle hdl, quint32 pos, const QMap<int, int> &level2bits, int readExtEntry(Handle &hdl, quint32 &polygons, quint32 &lines,
QMap<quint32, int> &map); quint32 &points);
bool parsePoints(Handle hdl, quint32 pos, const QMap<int, int> &level2bits);
friend QDebug operator<<(QDebug dbg, const MapLevel &level); friend QDebug operator<<(QDebug dbg, const MapLevel &level);

View File

@ -29,6 +29,8 @@ SubFile *VectorTile::file(SubFile::Type type)
return _lbl; return _lbl;
case SubFile::NET: case SubFile::NET:
return _net; return _net;
case SubFile::NOD:
return _nod;
case SubFile::GMP: case SubFile::GMP:
return _gmp; return _gmp;
default: default:
@ -51,6 +53,9 @@ SubFile *VectorTile::addFile(IMG *img, SubFile::Type type)
case SubFile::NET: case SubFile::NET:
_net = new NETFile(img); _net = new NETFile(img);
return _net; return _net;
case SubFile::NOD:
_nod = new NODFile(img);
return _nod;
case SubFile::GMP: case SubFile::GMP:
_gmp = new SubFile(img); _gmp = new SubFile(img);
return _gmp; return _gmp;
@ -74,6 +79,9 @@ SubFile *VectorTile::addFile(const QString &path, SubFile::Type type)
case SubFile::NET: case SubFile::NET:
_net = new NETFile(path); _net = new NETFile(path);
return _net; return _net;
case SubFile::NOD:
_nod = new NODFile(path);
return _nod;
case SubFile::GMP: case SubFile::GMP:
_gmp = new SubFile(path); _gmp = new SubFile(path);
return _gmp; return _gmp;
@ -96,17 +104,18 @@ bool VectorTile::init()
bool VectorTile::initGMP() bool VectorTile::initGMP()
{ {
SubFile::Handle hdl(_gmp); SubFile::Handle hdl(_gmp);
quint32 tre, rgn, lbl, net; quint32 tre, rgn, lbl, net, nod;
if (!(_gmp->seek(hdl, 0x19) && _gmp->readUInt32(hdl, tre) if (!(_gmp->seek(hdl, 0x19) && _gmp->readUInt32(hdl, tre)
&& _gmp->readUInt32(hdl, rgn) && _gmp->readUInt32(hdl, lbl) && _gmp->readUInt32(hdl, rgn) && _gmp->readUInt32(hdl, lbl)
&& _gmp->readUInt32(hdl, net))) && _gmp->readUInt32(hdl, net) && _gmp->readUInt32(hdl, nod)))
return false; return false;
_tre = tre ? new TREFile(_gmp, tre) : 0; _tre = tre ? new TREFile(_gmp, tre) : 0;
_rgn = rgn ? new RGNFile(_gmp, rgn) : 0; _rgn = rgn ? new RGNFile(_gmp, rgn) : 0;
_lbl = lbl ? new LBLFile(_gmp, lbl) : 0; _lbl = lbl ? new LBLFile(_gmp, lbl) : 0;
_net = net ? new NETFile(_gmp, net) : 0; _net = net ? new NETFile(_gmp, net) : 0;
_nod = nod ? new NODFile(_gmp, nod) : 0;
return true; return true;
} }
@ -115,7 +124,7 @@ void VectorTile::polys(const RectC &rect, int bits, bool baseMap,
QList<IMG::Poly> *polygons, QList<IMG::Poly> *lines, QList<IMG::Poly> *polygons, QList<IMG::Poly> *lines,
QCache<const SubDiv *, IMG::Polys> *polyCache) const QCache<const SubDiv *, IMG::Polys> *polyCache) const
{ {
SubFile::Handle rgnHdl(_rgn), lblHdl(_lbl), netHdl(_net); SubFile::Handle rgnHdl(_rgn), lblHdl(_lbl), netHdl(_net), nodHdl(_nod);
if (!_rgn->initialized() && !_rgn->init(rgnHdl)) if (!_rgn->initialized() && !_rgn->init(rgnHdl))
return; return;
@ -140,6 +149,7 @@ void VectorTile::polys(const RectC &rect, int bits, bool baseMap,
lblHdl, &p); lblHdl, &p);
_rgn->extPolyObjects(rgnHdl, subdiv, shift, RGNFile::Line, _lbl, _rgn->extPolyObjects(rgnHdl, subdiv, shift, RGNFile::Line, _lbl,
lblHdl, &l); lblHdl, &l);
_rgn->links(rgnHdl, subdiv, _net, netHdl, _nod, nodHdl, &l);
copyPolys(rect, &p, polygons); copyPolys(rect, &p, polygons);
copyPolys(rect, &l, lines); copyPolys(rect, &l, lines);

View File

@ -6,13 +6,15 @@
#include "rgnfile.h" #include "rgnfile.h"
#include "lblfile.h" #include "lblfile.h"
#include "netfile.h" #include "netfile.h"
#include "nodfile.h"
class VectorTile { class VectorTile {
public: public:
VectorTile() : _tre(0), _rgn(0), _lbl(0), _net(0), _gmp(0) {} VectorTile() : _tre(0), _rgn(0), _lbl(0), _net(0), _nod(0), _gmp(0) {}
~VectorTile() ~VectorTile()
{ {
delete _tre; delete _rgn; delete _lbl; delete _net; delete _gmp; delete _tre; delete _rgn; delete _lbl; delete _net; delete _nod;
delete _gmp;
} }
bool init(); bool init();
@ -37,7 +39,7 @@ public:
{ {
return (type == SubFile::TRE || type == SubFile::LBL return (type == SubFile::TRE || type == SubFile::LBL
|| type == SubFile::RGN || type == SubFile::NET || type == SubFile::RGN || type == SubFile::NET
|| type == SubFile::GMP); || type == SubFile::NOD || type == SubFile::GMP);
} }
private: private:
@ -47,6 +49,7 @@ private:
RGNFile *_rgn; RGNFile *_rgn;
LBLFile *_lbl; LBLFile *_lbl;
NETFile *_net; NETFile *_net;
NODFile *_nod;
SubFile *_gmp; SubFile *_gmp;
}; };