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

Added support for Huffman compressed RGN data

This commit is contained in:
Martin Tůma 2020-01-21 21:50:13 +01:00
parent 7cc39f25e1
commit cd22e6207a
23 changed files with 913 additions and 294 deletions

View File

@ -89,6 +89,10 @@ HEADERS += src/common/config.h \
src/GUI/areaitem.h \ src/GUI/areaitem.h \
src/data/link.h \ src/data/link.h \
src/map/IMG/bitmapline.h \ src/map/IMG/bitmapline.h \
src/map/IMG/bitstream.h \
src/map/IMG/deltastream.h \
src/map/IMG/huffmanstream.h \
src/map/IMG/huffmantable.h \
src/map/IMG/textpathitem.h \ src/map/IMG/textpathitem.h \
src/map/IMG/textpointitem.h \ src/map/IMG/textpointitem.h \
src/map/projection.h \ src/map/projection.h \
@ -243,6 +247,10 @@ SOURCES += src/main.cpp \
src/GUI/mapview.cpp \ src/GUI/mapview.cpp \
src/GUI/areaitem.cpp \ src/GUI/areaitem.cpp \
src/map/IMG/bitmapline.cpp \ src/map/IMG/bitmapline.cpp \
src/map/IMG/bitstream.cpp \
src/map/IMG/deltastream.cpp \
src/map/IMG/huffmanstream.cpp \
src/map/IMG/huffmantable.cpp \
src/map/IMG/textpathitem.cpp \ src/map/IMG/textpathitem.cpp \
src/map/IMG/textpointitem.cpp \ src/map/IMG/textpointitem.cpp \
src/map/maplist.cpp \ src/map/maplist.cpp \

83
src/map/IMG/bitstream.cpp Normal file
View File

@ -0,0 +1,83 @@
#include "bitstream.h"
bool BitStream1::read(int bits, quint32 &val)
{
val = 0;
for (int pos = 0; pos < bits; ) {
if (!_remaining) {
if (!_length || !_file.readUInt8(_hdl, _data))
return false;
_remaining = 8;
_length--;
}
quint32 get = bits - pos;
if (get >= _remaining) {
val |= _data << pos;
pos += _remaining;
_remaining = 0;
} else {
quint32 mask = (1<<get) - 1;
val |= (_data & mask)<<pos;
_data >>= get;
_remaining -= get;
break;
}
}
return true;
}
bool BitStream1::flush()
{
if (_length && !_file.seek(_hdl, _hdl.pos + _length))
return false;
_length = 0;
_remaining = 0;
return true;
}
bool BitStream4::read(int bits, quint32 &val)
{
if (bits <= 32 - (int)(_used + _unused)) {
val = bits ? (_data << _used) >> (32 - bits) : 0;
_used += bits;
return true;
}
quint32 old = 0;
if (_used < 32) {
old = (_data << _used) >> (32 - bits);
bits = (bits - 32) + _used;
}
_used = bits;
quint32 bytes = qMin(_length, (quint32)4);
if (!_file.readVUInt32SW(_hdl, bytes, _data))
return false;
_length -= bytes;
_unused = (4 - bytes) * 8;
_data <<= _unused;
val = _data >> (32 - _used) | old;
return true;
}
bool BitStream4::flush()
{
if (_length && !_file.seek(_hdl, _hdl.pos + _length))
return false;
_length = 0;
_unused = 32;
return true;
}

39
src/map/IMG/bitstream.h Normal file
View File

@ -0,0 +1,39 @@
#ifndef BITSTREAM_H
#define BITSTREAM_H
#include "subfile.h"
class BitStream1 {
public:
BitStream1(const SubFile &file, SubFile::Handle &hdl, quint32 length)
: _file(file), _hdl(hdl), _length(length), _remaining(0) {}
bool read(int bits, quint32 &val);
bool flush();
quint32 bitsAvailable() const {return _length * 8 + _remaining;}
private:
const SubFile &_file;
SubFile::Handle &_hdl;
quint32 _length, _remaining;
quint8 _data;
};
class BitStream4 {
public:
BitStream4(const SubFile &file, SubFile::Handle &hdl, quint32 length)
: _file(file), _hdl(hdl), _length(length), _used(32), _unused(0),
_data(0) {}
bool read(int bits, quint32 &val);
bool flush();
quint32 bitsAvailable() const {return _length * 8 + (32 - _used) - _unused;}
private:
const SubFile &_file;
SubFile::Handle &_hdl;
quint32 _length, _used, _unused;
quint32 _data;
};
#endif // BITSTREAM_H

View File

@ -0,0 +1,86 @@
#include "deltastream.h"
static int bitSize(quint8 baseSize, bool variableSign, bool extraBit)
{
int bits = 2;
if (baseSize <= 9)
bits += baseSize;
else
bits += 2 * baseSize - 9;
if (variableSign)
bits++;
if (extraBit)
bits++;
return bits;
}
DeltaStream::DeltaStream(const SubFile &file, SubFile::Handle &hdl,
quint32 length, quint8 info, bool extraBit, bool extended)
: BitStream1(file, hdl, length), _readBits(0xFFFFFFFF)
{
_extraBit = extraBit ? 1 : 0;
if (!(sign(_lonSign) && sign(_latSign)))
return;
if (extended) {
quint32 b;
if (!read(1, b))
return;
}
_lonBits = bitSize(info & 0x0F, !_lonSign, extraBit);
_latBits = bitSize(info >> 4, !_latSign, false);
_readBits = _lonBits + _latBits;
}
bool DeltaStream::readDelta(int bits, int sign, int extraBit,
qint32 &delta)
{
quint32 value;
if (!read(bits, value))
return false;
value >>= extraBit;
if (!sign) {
qint32 signMask = 1 << (bits - extraBit - 1);
if (value & signMask) {
qint32 comp = value ^ signMask;
if (comp)
delta = comp - signMask;
else {
qint32 other;
if (!readDelta(bits - extraBit, sign, false, other))
return false;
if (other < 0)
delta = 1 - signMask + other;
else
delta = signMask - 1 + other;
}
} else {
delta = value;
}
} else {
delta = value * sign;
}
return true;
}
bool DeltaStream::sign(int &val)
{
quint32 bit;
val = 0;
if (!read(1, bit))
return false;
if (bit) {
if (!read(1, bit))
return false;
val = bit ? -1 : 1;
}
return true;
}

28
src/map/IMG/deltastream.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef DELTASTREAM_H
#define DELTASTREAM_H
#include "bitstream.h"
class DeltaStream : public BitStream1 {
public:
DeltaStream(const SubFile &file, SubFile::Handle &hdl, quint32 length,
quint8 info, bool extraBit, bool extended);
bool readNext(qint32 &lonDelta, qint32 &latDelta)
{
return hasNext()
? (readDelta(_lonBits, _lonSign, _extraBit, lonDelta)
&& readDelta(_latBits, _latSign, false, latDelta)) : false;
}
bool atEnd() const {return (_readBits != 0xFFFFFFFF && !hasNext());}
private:
bool hasNext() const {return bitsAvailable() >= _readBits;}
bool sign(int &val);
bool readDelta(int bits, int sign, int extraBit, qint32 &delta);
int _lonSign, _latSign, _extraBit;
quint32 _lonBits, _latBits, _readBits;
};
#endif // DELTASTREAM_H

View File

@ -0,0 +1,101 @@
#include "huffmanstream.h"
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 (!(sign(_lonSign) && sign(_latSign)))
return;
} else {
_lonSign = 0;
_latSign = 0;
}
quint32 eb;
if (!read(1, eb))
return;
if (eb) {
qWarning("Extended polygon/lines not supported");
flush();
}
}
bool HuffmanStream::readNext(qint32 &lonDelta, qint32 &latDelta)
{
if (!readDelta(_lonSign, lonDelta))
return false;
if (!readDelta(_latSign, latDelta))
return false;
if (!(lonDelta|latDelta))
return false;
return true;
}
bool HuffmanStream::readOffset(qint32 &lonDelta, qint32 &latDelta)
{
if (!readDelta(1, lonDelta))
return false;
if (!readDelta(1, latDelta))
return false;
return true;
}
bool HuffmanStream::sign(int &val)
{
quint32 bit;
val = 0;
if (!read(1, bit))
return false;
if (bit) {
if (!read(1, bit))
return false;
val = bit ? -1 : 1;
}
return true;
}
bool HuffmanStream::readDelta(int sign, qint32 &symbol)
{
uchar size;
if (_symbolDataSize < 32) {
quint32 next;
quint8 nextSize = qMin((quint32)(32 - _symbolDataSize),
bitsAvailable());
if (!read(nextSize, next))
return false;
_symbolData = (_symbolData << nextSize) | next;
_symbolDataSize += nextSize;
}
symbol = _table.symbol(_symbolData << (32U - _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;
}

View File

@ -0,0 +1,27 @@
#ifndef HUFFMANSTREAM_H
#define HUFFMANSTREAM_H
#include "bitstream.h"
#include "huffmantable.h"
class HuffmanStream : public BitStream4 {
public:
HuffmanStream(const SubFile &file, SubFile::Handle &hdl, quint32 length,
const HuffmanTable &table, bool line);
bool readNext(qint32 &lonDelta, qint32 &latDelta);
bool readOffset(qint32 &lonDelta, qint32 &latDelta);
bool atEnd() const
{return _symbolDataSize + bitsAvailable() < _table.maxSymbolSize();}
private:
bool sign(int &val);
bool readDelta(int sign, qint32 &delta);
const HuffmanTable &_table;
quint32 _symbolDataSize;
quint32 _symbolData;
int _lonSign, _latSign;
};
#endif // HUFFMANSTREAM_H

View File

@ -0,0 +1,139 @@
#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)
{
quint32 val = 0;
for (quint32 i = bytes; i; i--)
val |= ((quint32)*(buffer + i)) << ((i-1) * 8);
return val;
}
bool HuffmanTable::load(const SubFile &file, SubFile::Handle &hdl,
quint32 offset, quint32 size, quint32 id)
{
if (!getBuffer(file, hdl, offset, size, id))
return false;
_s0 = (quint8)_buffer.at(0) & 0x0F;
_s1e = (quint8)_buffer.at(0) & 0x10 ? 1 : 8;
_s2 = (quint8)_buffer.at(1);
_s3 = bs(_s2);
_s1d = (quint8)_buffer.at(2);
_s1f = (quint8)_buffer.at(3);
_s20 = bs(_s1f);
_s1 = _s20 + 1;
_s22 = vs(_buffer.at(4));
_s1c = _s3 + 1 + _s22;
_s14 = (quint8*)(_buffer.data()) + 4 + _s22;
_s10 = _s14 + _s1c * _s1d;
_s18 = _s10 + (_s1 << _s0);
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 = hdl.pos + 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;
}
quint32 HuffmanTable::symbol(quint32 data, quint8 &size) const
{
quint32 ss, sym;
quint8 *tp;
if (_s0 == 0) {
sym = _s1d - 1;
ss = 0;
} else {
quint32 offset = _s1 * (data >> (0x20U - _s0));
tp = _s10 + offset;
if ((*tp & 1) != 0) {
sym = readVUint32(tp, _s20);
size = *tp >> 1;
return sym;
}
ss = *tp >> 1;
sym = tp[1];
}
tp = ss * _s1c + _s14;
data = data >> (0x20U - _s2);
quint8 *prev = tp;
while (ss < sym) {
quint32 cnt = (ss + 1 + sym) >> 1;
tp = _s14 + (cnt * _s1c);
quint32 nd = readVUint32(tp - 1, _s3);
if (data <= nd) {
if (data == nd)
ss = cnt;
else
tp = prev;
sym = cnt - (data < nd);
cnt = ss;
}
ss = cnt;
prev = tp;
}
sym = readVUint32(tp - 1, _s3);
tp = tp + _s3;
ss = readVUint32(tp, _s22);
size = *tp;
sym = (data - sym) >> (_s2 - *tp);
if (_s1e == 8)
sym = readVUint32(tp, _s20);
else {
sym = (sym + ss) * _s1f;
ss = sym >> 3;
sym = sym & 7;
quint32 shift = 8 - sym;
sym = *(_s18 + ss) >> sym;
if (shift < _s1f) {
tp = _s18 + ss;
ss = readVUint32(tp, ((_s1f + 7) - shift) >> 3);
sym = (ss << shift) | sym;
}
}
return sym;
}

View File

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

View File

@ -1,4 +1,4 @@
#include <QSet> #include <QMap>
#include <QtEndian> #include <QtEndian>
#include "common/programpaths.h" #include "common/programpaths.h"
#include "vectortile.h" #include "vectortile.h"
@ -110,8 +110,8 @@ IMG::IMG(const QString &fileName)
QString fn(QByteArray(name, sizeof(name))); QString fn(QByteArray(name, sizeof(name)));
if (VectorTile::isTileFile(tt)) { if (VectorTile::isTileFile(tt)) {
VectorTile *tile; VectorTile *tile;
QMap<QString, VectorTile*>::iterator it = tileMap.find(fn); TileMap::const_iterator it = tileMap.find(fn);
if (it == tileMap.end()) { if (it == tileMap.constEnd()) {
tile = new VectorTile(); tile = new VectorTile();
tileMap.insert(fn, tile); tileMap.insert(fn, tile);
} else } else
@ -152,7 +152,8 @@ IMG::IMG(const QString &fileName)
} }
// Create tile tree // Create tile tree
for (TileMap::iterator it = tileMap.begin(); it != tileMap.end(); ++it) { for (TileMap::const_iterator it = tileMap.constBegin();
it != tileMap.constEnd(); ++it) {
VectorTile *tile = it.value(); VectorTile *tile = it.value();
if (!tile->init()) { if (!tile->init()) {

View File

@ -56,10 +56,10 @@ bool LBLFile::init(Handle &hdl)
quint8 multiplier, poiMultiplier; quint8 multiplier, poiMultiplier;
if (!(seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset) if (!(seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset)
&& readUInt32(hdl, _size) && readByte(hdl, multiplier) && readUInt32(hdl, _size) && readUInt8(hdl, multiplier)
&& readByte(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)
&& readByte(hdl, poiMultiplier) && seek(hdl, _gmpOffset + 0xAA) && readUInt8(hdl, poiMultiplier) && seek(hdl, _gmpOffset + 0xAA)
&& readUInt16(hdl, codepage))) && readUInt16(hdl, codepage)))
return false; return false;
@ -89,7 +89,7 @@ Label LBLFile::label6b(Handle &hdl, quint32 offset) const
return Label(); return Label();
while (true) { while (true) {
if (!(readByte(hdl, b1) && readByte(hdl, b2) && readByte(hdl, b3))) if (!(readUInt8(hdl, b1) && readUInt8(hdl, b2) && readUInt8(hdl, b3)))
return Label(); return Label();
int c[]= {b1>>2, (b1&0x3)<<4|b2>>4, (b2&0xF)<<2|b3>>6, b3&0x3F}; int c[]= {b1>>2, (b1&0x3)<<4|b2>>4, (b2&0xF)<<2|b3>>6, b3&0x3F};
@ -138,7 +138,7 @@ Label LBLFile::label8b(Handle &hdl, quint32 offset) const
return Label(); return Label();
while (true) { while (true) {
if (!readByte(hdl, c)) if (!readUInt8(hdl, c))
return Label(); return Label();
if (!c || c == 0x1d) if (!c || c == 0x1d)
break; break;

View File

@ -3,9 +3,11 @@
bool NETFile::init(Handle &hdl) bool NETFile::init(Handle &hdl)
{ {
quint8 multiplier; quint8 multiplier;
quint16 hdrLen;
if (!(seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset) if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen)
&& readUInt32(hdl, _size) && readByte(hdl, multiplier))) && seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset)
&& readUInt32(hdl, _size) && readUInt8(hdl, multiplier)))
return false; return false;
_multiplier = 1<<multiplier; _multiplier = 1<<multiplier;

View File

@ -15,8 +15,7 @@ public:
private: private:
bool init(Handle &hdl); bool init(Handle &hdl);
quint32 _offset; quint32 _offset, _size;
quint32 _size;
quint8 _multiplier; quint8 _multiplier;
}; };

View File

@ -1,124 +1,82 @@
#include <cstring>
#include "common/rectc.h" #include "common/rectc.h"
#include "common/garmin.h" #include "common/garmin.h"
#include "deltastream.h"
#include "huffmanstream.h"
#include "lblfile.h" #include "lblfile.h"
#include "netfile.h" #include "netfile.h"
#include "rgnfile.h" #include "rgnfile.h"
static int bitSize(quint8 baseSize, bool variableSign, bool extraBit) bool RGNFile::skipClassFields(Handle &hdl) const
{ {
int bits = 2; quint8 flags;
if (baseSize <= 9) quint32 rs;
bits += baseSize;
else
bits += 2 * baseSize - 9;
if (variableSign) if (!readUInt8(hdl, flags))
bits++;
if (extraBit)
bits++;
return bits;
}
bool RGNFile::BitStream::read(int bits, quint32 &val)
{
val = 0;
for (int pos = 0; pos < bits; ) {
if (!_remaining) {
if (!_length || !_file.readByte(_hdl, _data))
return false; return false;
_remaining = 8;
_length--; switch (flags >> 5) {
case 4:
rs = 1;
break;
case 5:
rs = 2;
break;
case 6:
rs = 3;
break;
case 7:
if (!readVUInt32(hdl, rs))
return false;
break;
default:
rs = 0;
break;
} }
quint32 get = bits - pos; return seek(hdl, hdl.pos + rs);
if (get >= _remaining) { }
val |= _data << pos;
pos += _remaining; bool RGNFile::skipLclFields(Handle &hdl, const quint32 flags[3],
_remaining = 0; Segment::Type type) const
} else { {
quint32 mask = (1<<get) - 1; quint32 bitfield = 0xFFFFFFFF;
val |= (_data & mask)<<pos;
_data >>= get; if (flags[0] & 0x20000000)
_remaining -= get; if (!readVBitfield32(hdl, bitfield))
return false;
for (int i = 0; i < 29; i++) {
if ((flags[0] >> i) & 1) {
if (bitfield & 1) {
quint32 m = flags[(i >> 4) + 1] >> ((i * 2) & 0x1e) & 3;
switch (i) {
case 5:
if (m == 1 && type == Segment::Point) {
quint16 u16;
if (!readUInt16(hdl, u16))
return false;
}
break;
default:
break; break;
} }
} }
bitfield >>= 1;
return true;
}
RGNFile::DeltaStream::DeltaStream(const SubFile &file, Handle &hdl,
quint32 length, quint8 info, bool extraBit, bool extended)
: BitStream(file, hdl, length), _readBits(0xFFFFFFFF)
{
_extraBit = extraBit ? 1 : 0;
if (!(sign(_lonSign) && sign(_latSign)))
return;
if (extended) {
quint32 b;
if (!read(1, b))
return;
} }
_lonBits = bitSize(info & 0x0F, !_lonSign, extraBit);
_latBits = bitSize(info >> 4, !_latSign, false);
_readBits = _lonBits + _latBits;
}
bool RGNFile::DeltaStream::readDelta(int bits, int sign, int extraBit,
qint32 &delta)
{
quint32 value;
if (!read(bits, value))
return false;
value >>= extraBit;
if (!sign) {
qint32 signMask = 1 << (bits - extraBit - 1);
if (value & signMask) {
qint32 comp = value ^ signMask;
if (comp)
delta = comp - signMask;
else {
qint32 other;
if (!readDelta(bits - extraBit, sign, false, other))
return false;
if (other < 0)
delta = 1 - signMask + other;
else
delta = signMask - 1 + other;
}
} else {
delta = value;
}
} else {
delta = value * sign;
} }
return true; return true;
} }
bool RGNFile::DeltaStream::sign(int &val) void RGNFile::clearFlags()
{ {
quint32 bit; memset(_polygonsFlags, 0, sizeof(_polygonsFlags));
val = 0; memset(_linesFlags, 0, sizeof(_linesFlags));
memset(_pointsFlags, 0, sizeof(_pointsFlags));
if (!read(1, bit))
return false;
if (bit) {
if (!read(1, bit))
return false;
val = bit ? -1 : 1;
}
return true;
} }
bool RGNFile::init(Handle &hdl) bool RGNFile::init(Handle &hdl)
{ {
quint16 hdrLen; quint16 hdrLen;
@ -128,26 +86,30 @@ bool RGNFile::init(Handle &hdl)
&& readUInt32(hdl, _size))) && readUInt32(hdl, _size)))
return false; return false;
if (hdrLen >= 0x5D) { if (hdrLen >= 0x68) {
if (!(readUInt32(hdl, _polygonsOffset) && readUInt32(hdl, _polygonsSize) if (!(readUInt32(hdl, _polygonsOffset) && readUInt32(hdl, _polygonsSize)
&& seek(hdl, _gmpOffset + 0x39) && readUInt32(hdl, _linesOffset) && seek(hdl, _gmpOffset + 0x2D) && readUInt32(hdl, _polygonsFlags[0])
&& readUInt32(hdl, _linesSize) && seek(hdl, _gmpOffset + 0x55) && readUInt32(hdl, _polygonsFlags[1]) && readUInt32(hdl, _polygonsFlags[2])
&& readUInt32(hdl, _pointsOffset) && readUInt32(hdl, _pointsSize))) && readUInt32(hdl, _linesOffset) && readUInt32(hdl, _linesSize)
&& seek(hdl, _gmpOffset + 0x49) && readUInt32(hdl, _linesFlags[0])
&& readUInt32(hdl, _linesFlags[1]) && readUInt32(hdl, _linesFlags[2])
&& readUInt32(hdl, _pointsOffset) && readUInt32(hdl, _pointsSize)
&& seek(hdl, _gmpOffset + 0x65) && readUInt32(hdl, _pointsFlags[0])
&& readUInt32(hdl, _pointsFlags[1]) && readUInt32(hdl, _pointsFlags[2])))
return false; return false;
} }
if (hdrLen >= 0x7D) { if (hdrLen >= 0x7D) {
quint32 dictOffset, dictSize; quint32 dictOffset, dictSize, info;
if (!(seek(hdl, _gmpOffset + 0x71) && readUInt32(hdl, dictOffset) if (!(seek(hdl, _gmpOffset + 0x71) && readUInt32(hdl, dictOffset)
&& readUInt32(hdl, dictSize))) && readUInt32(hdl, dictSize) && readUInt32(hdl, info)))
return false; return false;
// NT maps if (dictSize && dictOffset && (info & 0x1E))
if (dictSize || dictOffset) { if (!_huffmanTable.load(*this, hdl, dictOffset, dictSize,
qWarning("NT compression not supported"); ((info >> 1) & 0xF) - 1))
return false; return false;
} }
}
_init = true; _init = true;
@ -158,9 +120,6 @@ bool RGNFile::polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
const Segment &segment, LBLFile *lbl, Handle &lblHdl, NETFile *net, const Segment &segment, LBLFile *lbl, Handle &lblHdl, NETFile *net,
Handle &netHdl, QList<IMG::Poly> *polys) const Handle &netHdl, QList<IMG::Poly> *polys) const
{ {
if (segment.start() == segment.end())
return true;
if (!seek(hdl, segment.start())) if (!seek(hdl, segment.start()))
return false; return false;
@ -172,18 +131,18 @@ bool RGNFile::polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
while (hdl.pos < (int)segment.end()) { while (hdl.pos < (int)segment.end()) {
IMG::Poly poly; IMG::Poly poly;
if (!(readByte(hdl, type) && readUInt24(hdl, labelPtr) if (!(readUInt8(hdl, type) && readUInt24(hdl, labelPtr)
&& readInt16(hdl, lon) && readInt16(hdl, lat))) && readInt16(hdl, lon) && readInt16(hdl, lat)))
return false; return false;
if (type & 0x80) { if (type & 0x80) {
if (!readUInt16(hdl, len)) if (!readUInt16(hdl, len))
return false; return false;
} else { } else {
if (!readByte(hdl, len8)) if (!readUInt8(hdl, len8))
return false; return false;
len = len8; len = len8;
} }
if (!readByte(hdl, bitstreamInfo)) if (!readUInt8(hdl, bitstreamInfo))
return false; return false;
poly.type = (segment.type() == Segment::Polygon) poly.type = (segment.type() == Segment::Polygon)
@ -230,11 +189,11 @@ bool RGNFile::polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
} }
bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl, bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
const SubDiv *subdiv, const Segment &segment, LBLFile *lbl, Handle &lblHdl, const SubDiv *subdiv, quint32 shift, const Segment &segment, LBLFile *lbl,
QList<IMG::Poly> *polys) const Handle &lblHdl, QList<IMG::Poly> *polys, bool line) const
{ {
quint32 len, labelPtr = 0; quint32 labelPtr, len;
quint8 type, subtype, bitstreamInfo; quint8 type, subtype;
qint16 lon, lat; qint16 lon, lat;
@ -243,27 +202,59 @@ bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
while (hdl.pos < (int)segment.end()) { while (hdl.pos < (int)segment.end()) {
IMG::Poly poly; IMG::Poly poly;
QPoint pos;
RectC br;
if (!(readByte(hdl, type) && readByte(hdl, subtype) if (!(readUInt8(hdl, type) && readUInt8(hdl, subtype)
&& readInt16(hdl, lon) && readInt16(hdl, lat) && readInt16(hdl, lon) && readInt16(hdl, lat)
&& readVUInt32(hdl, len) && readByte(hdl, bitstreamInfo))) && readVUInt32(hdl, len)))
return false; return false;
if (subtype & 0x80) { poly.type = 0x10000 | (quint16(type)<<8) | (subtype & 0x1F);
qWarning("Polygons/lines with extra bytes not supported"); labelPtr = 0;
if (!_huffmanTable.isNull()) {
pos = QPoint((subdiv->lon()<<8) + ((qint32)lon<<(32-subdiv->bits())),
(subdiv->lat()<<8) + ((qint32)lat<<(32-subdiv->bits())));
qint32 lonDelta, latDelta;
HuffmanStream stream(*this, hdl, len, _huffmanTable, line);
if (shift) {
if (!stream.readOffset(lonDelta, latDelta))
return false; return false;
pos = QPoint(pos.x() | lonDelta<<(32-subdiv->bits()-shift),
pos.y() | latDelta<<(32-subdiv->bits()-shift));
}
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
br = RectC(c, c);
poly.points.append(QPointF(c.lon(), c.lat()));
while (stream.readNext(lonDelta, latDelta)) {
pos.rx() += lonDelta<<(32-subdiv->bits()-shift);
pos.ry() += latDelta<<(32-subdiv->bits()-shift);
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
poly.points.append(QPointF(c.lon(), c.lat()));
br = br.united(c);
} }
poly.type = 0x10000 + (quint16(type) << 8) + (subtype & 0x1F); if (!(stream.atEnd() && stream.flush()))
return false;
QPoint pos(subdiv->lon() + ((qint32)lon<<(24-subdiv->bits())), } else {
pos = QPoint(subdiv->lon() + ((qint32)lon<<(24-subdiv->bits())),
subdiv->lat() + ((qint32)lat<<(24-subdiv->bits()))); subdiv->lat() + ((qint32)lat<<(24-subdiv->bits())));
Coordinates c(toWGS24(pos.x()), toWGS24(pos.y())); Coordinates c(toWGS24(pos.x()), toWGS24(pos.y()));
RectC br(c, c); br = RectC(c, c);
poly.points.append(QPointF(c.lon(), c.lat())); poly.points.append(QPointF(c.lon(), c.lat()));
quint8 bitstreamInfo;
if (!readUInt8(hdl, bitstreamInfo))
return false;
qint32 lonDelta, latDelta; qint32 lonDelta, latDelta;
DeltaStream stream(*this, hdl, len - 1, bitstreamInfo, false, true); DeltaStream stream(*this, hdl, len - 1, bitstreamInfo, false, true);
while (stream.readNext(lonDelta, latDelta)) { while (stream.readNext(lonDelta, latDelta)) {
pos.rx() += lonDelta<<(24-subdiv->bits()); pos.rx() += lonDelta<<(24-subdiv->bits());
pos.ry() += latDelta<<(24-subdiv->bits()); pos.ry() += latDelta<<(24-subdiv->bits());
@ -274,12 +265,15 @@ bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
} }
if (!(stream.atEnd() && stream.flush())) if (!(stream.atEnd() && stream.flush()))
return false; return false;
}
if ((subtype & 0x20)) { if (subtype & 0x20 && !readUInt24(hdl, labelPtr))
if (!readUInt24(hdl, labelPtr)) return false;
if (subtype & 0x80 && !skipClassFields(hdl))
return false;
if (subtype & 0x40 && !skipLclFields(hdl, line ? _linesFlags
: _polygonsFlags, segment.type()))
return false; return false;
} else
labelPtr = 0;
if (!rect.intersects(br)) if (!rect.intersects(br))
continue; continue;
@ -307,11 +301,11 @@ bool RGNFile::pointObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
while (hdl.pos < (int)segment.end()) { while (hdl.pos < (int)segment.end()) {
IMG::Point point; IMG::Point point;
if (!(readByte(hdl, type) && readUInt24(hdl, labelPtr) if (!(readUInt8(hdl, type) && readUInt24(hdl, labelPtr)
&& readInt16(hdl, lon) && readInt16(hdl, lat))) && readInt16(hdl, lon) && readInt16(hdl, lat)))
return false; return false;
if (labelPtr & 0x800000) { if (labelPtr & 0x800000) {
if (!readByte(hdl, subtype)) if (!readUInt8(hdl, subtype))
return false; return false;
} else } else
subtype = 0; subtype = 0;
@ -340,8 +334,8 @@ bool RGNFile::pointObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
} }
bool RGNFile::extPointObjects(const RectC &rect, Handle &hdl, bool RGNFile::extPointObjects(const RectC &rect, Handle &hdl,
const SubDiv *subdiv, const Segment &segment, LBLFile *lbl, Handle &lblHdl, const SubDiv *subdiv, const Segment &segment, LBLFile *lbl,
QList<IMG::Point> *points) const Handle &lblHdl, QList<IMG::Point> *points) const
{ {
quint8 type, subtype; quint8 type, subtype;
qint16 lon, lat; qint16 lon, lat;
@ -353,97 +347,104 @@ bool RGNFile::extPointObjects(const RectC &rect, Handle &hdl,
while (hdl.pos < (int)segment.end()) { while (hdl.pos < (int)segment.end()) {
IMG::Point point; IMG::Point point;
if (!(readByte(hdl, type) && readByte(hdl, subtype) if (!(readUInt8(hdl, type) && readUInt8(hdl, subtype)
&& readInt16(hdl, lon) && readInt16(hdl, lat))) && readInt16(hdl, lon) && readInt16(hdl, lat)))
return false; return false;
if (subtype & 0x80) {
qWarning("Points with extra bytes not supported");
return false;
}
point.type = 0x10000 | (((quint32)type)<<8) | (subtype & 0x1F); point.type = 0x10000 | (((quint32)type)<<8) | (subtype & 0x1F);
qint16 lonOffset = lon<<(24-subdiv->bits()); qint16 lonOffset = lon<<(24-subdiv->bits());
qint16 latOffset = lat<<(24-subdiv->bits()); qint16 latOffset = lat<<(24-subdiv->bits());
point.coordinates = Coordinates(toWGS24(subdiv->lon() + lonOffset), point.coordinates = Coordinates(toWGS24(subdiv->lon() + lonOffset),
toWGS24(subdiv->lat() + latOffset)); toWGS24(subdiv->lat() + latOffset));
labelPtr = 0;
if (subtype & 0x20) { if (subtype & 0x20 && !readUInt24(hdl, labelPtr))
if (!readUInt24(hdl, labelPtr))
return false; return false;
if (subtype & 0x80 && !skipClassFields(hdl))
return false;
if (subtype & 0x40 && !skipLclFields(hdl, _pointsFlags, segment.type()))
return false;
if (!rect.contains(point.coordinates))
continue;
point.poi = labelPtr & 0x400000; point.poi = labelPtr & 0x400000;
if (lbl && (labelPtr & 0x3FFFFF)) { if (lbl && (labelPtr & 0x3FFFFF)) {
point.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF, point.poi); point.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF, point.poi);
point.id = ((quint64)point.type)<<40 point.id = ((quint64)point.type)<<40
| ((quint64)lbl->offset())<<24 | (labelPtr & 0x3FFFFF); | ((quint64)lbl->offset())<<24 | (labelPtr & 0x3FFFFF);
} }
}
if (rect.contains(point.coordinates))
points->append(point); points->append(point);
} }
return true; return true;
} }
void RGNFile::objects(const RectC &rect, const SubDiv *subdiv,
void RGNFile::objects(const RectC &rect, const SubDiv *subdiv, LBLFile *lbl, LBLFile *lbl, NETFile *net, QList<IMG::Poly> *polygons,
NETFile *net, QList<IMG::Poly> *polygons, QList<IMG::Poly> *lines, QList<IMG::Poly> *lines, QList<IMG::Point> *points)
QList<IMG::Point> *points)
{ {
Handle rgnHdl, lblHdl, netHdl; Handle rgnHdl, lblHdl, netHdl;
if (!_init && !init(rgnHdl)) if (!_init && !init(rgnHdl))
return; return;
QVector<RGNFile::Segment> seg(segments(rgnHdl, subdiv)); QVector<Segment> seg(segments(rgnHdl, subdiv));
for (int i = 0; i < seg.size(); i++) { for (int i = 0; i < seg.size(); i++) {
switch (seg.at(i).type()) { const Segment &segment = seg.at(i);
if (segment.start() == segment.end())
continue;
switch (segment.type()) {
case Segment::Point: case Segment::Point:
case Segment::IndexedPoint: case Segment::IndexedPoint:
if (points) if (points)
pointObjects(rect, rgnHdl, subdiv, seg.at(i), lbl, lblHdl, pointObjects(rect, rgnHdl, subdiv, segment, lbl, lblHdl,
points); points);
break; break;
case Segment::Line: case Segment::Line:
if (lines) if (lines)
polyObjects(rect, rgnHdl, subdiv, seg.at(i), lbl, lblHdl, polyObjects(rect, rgnHdl, subdiv, segment, lbl, lblHdl, net,
net, netHdl, lines); netHdl, lines);
break; break;
case Segment::Polygon: case Segment::Polygon:
if (polygons) if (polygons)
polyObjects(rect, rgnHdl, subdiv, seg.at(i), lbl, lblHdl, polyObjects(rect, rgnHdl, subdiv, segment, lbl, lblHdl, net,
net, netHdl, polygons); netHdl, polygons);
break;
case Segment::RoadReference:
break; break;
} }
} }
} }
void RGNFile::extObjects(const RectC &rect, const SubDiv *subdiv, LBLFile *lbl, void RGNFile::extObjects(const RectC &rect, const SubDiv *subdiv, quint32 shift,
QList<IMG::Poly> *polygons, QList<IMG::Poly> *lines, LBLFile *lbl, QList<IMG::Poly> *polygons, QList<IMG::Poly> *lines,
QList<IMG::Point> *points) QList<IMG::Point> *points)
{ {
Handle rgnHdl, lblHdl; Handle rgnHdl, lblHdl;
if (!_init && !init(rgnHdl)) if (!_init && !init(rgnHdl))
return; return;
if (polygons && subdiv->polygonsOffset() != subdiv->polygonsEnd()) { if (polygons && subdiv->polygonsOffset() != subdiv->polygonsEnd()) {
quint32 start = _polygonsOffset + subdiv->polygonsOffset(); quint32 start = _polygonsOffset + subdiv->polygonsOffset();
quint32 end = subdiv->polygonsEnd() quint32 end = subdiv->polygonsEnd()
? _polygonsOffset + subdiv->polygonsEnd() ? _polygonsOffset + subdiv->polygonsEnd()
: _polygonsOffset + _polygonsSize; : _polygonsOffset + _polygonsSize;
extPolyObjects(rect, rgnHdl, subdiv, Segment(start, end, extPolyObjects(rect, rgnHdl, subdiv, shift, Segment(start, end,
Segment::Polygon), lbl, lblHdl, polygons); Segment::Polygon), lbl, lblHdl, polygons, false);
} }
if (lines && subdiv->linesOffset() != subdiv->linesEnd()) { if (lines && subdiv->linesOffset() != subdiv->linesEnd()) {
quint32 start = _linesOffset + subdiv->linesOffset(); quint32 start = _linesOffset + subdiv->linesOffset();
quint32 end = subdiv->linesEnd() quint32 end = subdiv->linesEnd()
? _linesOffset + subdiv->linesEnd() ? _linesOffset + subdiv->linesEnd()
: _linesOffset + _linesSize; : _linesOffset + _linesSize;
extPolyObjects(rect, rgnHdl, subdiv, Segment(start, end, Segment::Line), extPolyObjects(rect, rgnHdl, subdiv, shift, Segment(start, end,
lbl, lblHdl, lines); Segment::Line), lbl, lblHdl, lines, true);
} }
if (points && subdiv->pointsOffset() != subdiv->pointsEnd()) { if (points && subdiv->pointsOffset() != subdiv->pointsEnd()) {
quint32 start = _pointsOffset + subdiv->pointsOffset(); quint32 start = _pointsOffset + subdiv->pointsOffset();
@ -458,13 +459,13 @@ void RGNFile::extObjects(const RectC &rect, const SubDiv *subdiv, LBLFile *lbl,
QVector<RGNFile::Segment> RGNFile::segments(Handle &hdl, const SubDiv *subdiv) QVector<RGNFile::Segment> RGNFile::segments(Handle &hdl, const SubDiv *subdiv)
const const
{ {
if (subdiv->offset() == subdiv->end() || !(subdiv->objects() & 0xF0)) if (subdiv->offset() == subdiv->end() || !(subdiv->objects() & 0x1F))
return QVector<Segment>(); return QVector<Segment>();
quint32 offset = _offset + subdiv->offset(); quint32 offset = _offset + subdiv->offset();
int no = 0; int no = 0;
for (quint8 mask = 0x10; mask; mask <<= 1) for (quint8 mask = 0x1; mask <= 0x10; mask <<= 1)
if (subdiv->objects() & mask) if (subdiv->objects() & mask)
no++; no++;
@ -476,7 +477,7 @@ QVector<RGNFile::Segment> RGNFile::segments(Handle &hdl, const SubDiv *subdiv)
quint16 po; quint16 po;
int cnt = 0; int cnt = 0;
for (quint8 mask = 0x10; mask; mask <<= 1) { for (quint16 mask = 0x1; mask <= 0x10; mask <<= 1) {
if (subdiv->objects() & mask) { if (subdiv->objects() & mask) {
if (cnt) { if (cnt) {
if (!readUInt16(hdl, po)) if (!readUInt16(hdl, po))
@ -498,8 +499,28 @@ QVector<RGNFile::Segment> RGNFile::segments(Handle &hdl, const SubDiv *subdiv)
#ifndef QT_NO_DEBUG #ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const RGNFile::Segment &segment) QDebug operator<<(QDebug dbg, const RGNFile::Segment &segment)
{ {
QString type;
switch (segment.type()) {
case RGNFile::Segment::Point:
type = "Point";
break;
case RGNFile::Segment::IndexedPoint:
type = "IndexedPoint";
break;
case RGNFile::Segment::Line:
type = "Line";
break;
case RGNFile::Segment::Polygon:
type = "Polygon";
break;
case RGNFile::Segment::RoadReference:
type = "RoadReference";
break;
}
dbg.nospace() << "Segment(" << segment.start() << ", " << segment.end() dbg.nospace() << "Segment(" << segment.start() << ", " << segment.end()
<< ", " << segment.type() << ")"; - segment.start() << ", " << type << ")";
return dbg.space(); return dbg.space();
} }
#endif // QT_NO_DEBUG #endif // QT_NO_DEBUG

View File

@ -4,6 +4,7 @@
#include "img.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;
@ -14,26 +15,28 @@ public:
RGNFile(IMG *img) RGNFile(IMG *img)
: SubFile(img), _offset(0), _size(0), _polygonsOffset(0), : SubFile(img), _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), _init(false) {clearFlags();}
RGNFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset), _offset(0), RGNFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset), _offset(0),
_size(0), _polygonsOffset(0), _polygonsSize(0), _linesOffset(0), _size(0), _polygonsOffset(0), _polygonsSize(0), _linesOffset(0),
_linesSize(0), _pointsOffset(0), _pointsSize(0), _init(false) {} _linesSize(0), _pointsOffset(0), _pointsSize(0), _init(false)
{clearFlags();}
void objects(const RectC &rect, const SubDiv *subdiv, LBLFile *lbl, void objects(const RectC &rect, const SubDiv *subdiv,
NETFile *net, QList<IMG::Poly> *polygons, QList<IMG::Poly> *lines, LBLFile *lbl, NETFile *net, QList<IMG::Poly> *polygons,
QList<IMG::Point> *points); QList<IMG::Poly> *lines, QList<IMG::Point> *points);
void extObjects(const RectC &rect, const SubDiv *subdiv, LBLFile *lbl, void extObjects(const RectC &rect, const SubDiv *subdiv, quint32 shift,
QList<IMG::Poly> *polygons, QList<IMG::Poly> *lines, LBLFile *lbl, QList<IMG::Poly> *polygons, QList<IMG::Poly> *lines,
QList<IMG::Point> *points); QList<IMG::Point> *points);
private: private:
class Segment { class Segment {
public: public:
enum Type { enum Type {
Point = 0x10, Point = 0x1,
IndexedPoint = 0x20, IndexedPoint = 0x2,
Line = 0x40, Line = 0x4,
Polygon = 0x80 Polygon = 0x8,
RoadReference = 0x10
}; };
Segment() : _start(0), _end(0), _type(Point) {} Segment() : _start(0), _end(0), _type(Point) {}
@ -54,45 +57,6 @@ private:
Type _type; Type _type;
}; };
class BitStream {
public:
BitStream(const SubFile &file, Handle &hdl, quint32 length)
: _file(file), _hdl(hdl), _length(length), _remaining(0) {}
bool read(int bits, quint32 &val);
bool flush() {return _file.seek(_hdl, _hdl.pos + _length);}
quint32 bitsAvailable() const {return _length * 8 + _remaining;}
private:
const SubFile &_file;
Handle &_hdl;
quint32 _length, _remaining;
quint8 _data;
};
class DeltaStream : public BitStream {
public:
DeltaStream(const SubFile &file, Handle &hdl, quint32 length,
quint8 info, bool extraBit, bool extended);
bool readNext(qint32 &lonDelta, qint32 &latDelta)
{
return hasNext()
? (readDelta(_lonBits, _lonSign, _extraBit, lonDelta)
&& readDelta(_latBits, _latSign, false, latDelta))
: false;
}
bool atEnd() const {return (_readBits != 0xFFFFFFFF && !hasNext());}
private:
bool hasNext() const {return bitsAvailable() >= _readBits;}
bool sign(int &val);
bool readDelta(int bits, int sign, int extraBit, qint32 &delta);
int _lonSign, _latSign, _extraBit;
quint32 _lonBits, _latBits, _readBits;
};
bool init(Handle &hdl); bool init(Handle &hdl);
QVector<Segment> segments(Handle &hdl, const SubDiv *subdiv) const; QVector<Segment> segments(Handle &hdl, const SubDiv *subdiv) const;
@ -103,12 +67,18 @@ private:
const Segment &segment, LBLFile *lbl, Handle &lblHdl, const Segment &segment, LBLFile *lbl, Handle &lblHdl,
QList<IMG::Point> *points) const; QList<IMG::Point> *points) const;
bool extPolyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv, bool extPolyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
const Segment &segment, LBLFile *lbl, Handle &lblHdl, quint32 shift, const Segment &segment, LBLFile *lbl, Handle &lblHdl,
QList<IMG::Poly> *polys) const; QList<IMG::Poly> *polys, bool line) const;
bool extPointObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv, bool extPointObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
const Segment &segment, LBLFile *lbl, Handle &lblHdl, const Segment &segment, LBLFile *lbl, Handle &lblHdl,
QList<IMG::Point> *points) const; QList<IMG::Point> *points) const;
void clearFlags();
bool skipClassFields(Handle &hdl) const;
bool skipLclFields(Handle &hdl, const quint32 flags[3],
Segment::Type type) const;
friend QDebug operator<<(QDebug dbg, const RGNFile::Segment &segment); friend QDebug operator<<(QDebug dbg, const RGNFile::Segment &segment);
quint32 _offset; quint32 _offset;
@ -116,10 +86,15 @@ private:
quint32 _polygonsOffset; quint32 _polygonsOffset;
quint32 _polygonsSize; quint32 _polygonsSize;
quint32 _polygonsFlags[3];
quint32 _linesOffset; quint32 _linesOffset;
quint32 _linesSize; quint32 _linesSize;
quint32 _linesFlags[3];
quint32 _pointsOffset; quint32 _pointsOffset;
quint32 _pointsSize; quint32 _pointsSize;
quint32 _pointsFlags[3];
HuffmanTable _huffmanTable;
bool _init; bool _init;
}; };

View File

@ -294,7 +294,7 @@ static bool readBitmap(SubFile *file, SubFile::Handle &hdl, QImage &img,
for (int y = 0; y < img.height(); y++) { for (int y = 0; y < img.height(); y++) {
for (int x = 0; x < img.width(); x += 8/bpp) { for (int x = 0; x < img.width(); x += 8/bpp) {
quint8 color; quint8 color;
if (!file->readByte(hdl, color)) if (!file->readUInt8(hdl, color))
return false; return false;
for (int i = 0; i < 8/bpp && x + i < img.width(); i++) { for (int i = 0; i < 8/bpp && x + i < img.width(); i++) {
@ -319,8 +319,8 @@ static bool readColor(SubFile *file, SubFile::Handle &hdl, QColor &color)
{ {
quint8 b, g, r; quint8 b, g, r;
if (!(file->readByte(hdl, b) && file->readByte(hdl, g) if (!(file->readUInt8(hdl, b) && file->readUInt8(hdl, g)
&& file->readByte(hdl, r))) && file->readUInt8(hdl, r)))
return false; return false;
color = qRgb(r, g, b); color = qRgb(r, g, b);
@ -333,14 +333,14 @@ static bool skipLocalization(SubFile *file, SubFile::Handle &hdl)
quint8 t8; quint8 t8;
quint16 len; quint16 len;
if (!file->readByte(hdl, t8)) if (!file->readUInt8(hdl, t8))
return false; return false;
len = t8; len = t8;
if (len & 0x01) if (len & 0x01)
len = len >> 1; len = len >> 1;
else { else {
if (!file->readByte(hdl, t8)) if (!file->readUInt8(hdl, t8))
return false; return false;
len = (((quint16)t8) << 8) | len; len = (((quint16)t8) << 8) | len;
len = len >> 2; len = len >> 2;
@ -361,7 +361,7 @@ bool Style::itemInfo(SubFile *file, SubFile::Handle &hdl,
if (section.arrayItemSize == 5) { if (section.arrayItemSize == 5) {
if (!(file->readUInt16(hdl, t16_1) && file->readUInt16(hdl, t16_2) if (!(file->readUInt16(hdl, t16_1) && file->readUInt16(hdl, t16_2)
&& file->readByte(hdl, t8))) && file->readUInt8(hdl, t8)))
return false; return false;
info.offset = t16_2 | (t8<<16); info.offset = t16_2 | (t8<<16);
} else if (section.arrayItemSize == 4) { } else if (section.arrayItemSize == 4) {
@ -369,7 +369,7 @@ bool Style::itemInfo(SubFile *file, SubFile::Handle &hdl,
return false; return false;
info.offset = t16_2; info.offset = t16_2;
} else if (section.arrayItemSize == 3) { } else if (section.arrayItemSize == 3) {
if (!(file->readUInt16(hdl, t16_1) && file->readByte(hdl, t8))) if (!(file->readUInt16(hdl, t16_1) && file->readUInt8(hdl, t8)))
return false; return false;
info.offset = t8; info.offset = t8;
} else } else
@ -400,7 +400,7 @@ bool Style::parsePolygons(SubFile *file, SubFile::Handle &hdl,
quint8 t8, flags; quint8 t8, flags;
if (!(file->seek(hdl, section.offset + info.offset) if (!(file->seek(hdl, section.offset + info.offset)
&& file->readByte(hdl, t8))) && file->readUInt8(hdl, t8)))
return false; return false;
flags = t8 & 0x0F; flags = t8 & 0x0F;
@ -516,7 +516,7 @@ bool Style::parseLines(SubFile *file, SubFile::Handle &hdl,
quint8 t8_1, t8_2, flags, rows; quint8 t8_1, t8_2, flags, rows;
if (!(file->seek(hdl, section.offset + info.offset) if (!(file->seek(hdl, section.offset + info.offset)
&& file->readByte(hdl, t8_1) && file->readByte(hdl, t8_2))) && file->readUInt8(hdl, t8_1) && file->readUInt8(hdl, t8_2)))
return false; return false;
flags = t8_1 & 0x07; flags = t8_1 & 0x07;
rows = t8_1 >> 3; rows = t8_1 >> 3;
@ -541,7 +541,7 @@ bool Style::parseLines(SubFile *file, SubFile::Handle &hdl,
_lines[type] = Style::Line(img); _lines[type] = Style::Line(img);
} else { } else {
if (!(file->readByte(hdl, w1) && file->readByte(hdl, w2))) if (!(file->readUInt8(hdl, w1) && file->readUInt8(hdl, w2)))
return false; return false;
_lines[type] = (w2 > w1) _lines[type] = (w2 > w1)
@ -568,7 +568,7 @@ bool Style::parseLines(SubFile *file, SubFile::Handle &hdl,
_lines[type] = Style::Line(img); _lines[type] = Style::Line(img);
} else { } else {
if (!(file->readByte(hdl, w1) && file->readByte(hdl, w2))) if (!(file->readUInt8(hdl, w1) && file->readUInt8(hdl, w2)))
return false; return false;
_lines[type] = (w2 > w1) _lines[type] = (w2 > w1)
@ -595,7 +595,7 @@ bool Style::parseLines(SubFile *file, SubFile::Handle &hdl,
_lines[type] = Style::Line(img); _lines[type] = Style::Line(img);
} else { } else {
if (!(file->readByte(hdl, w1) && file->readByte(hdl, w2))) if (!(file->readUInt8(hdl, w1) && file->readUInt8(hdl, w2)))
return false; return false;
_lines[type] = Style::Line(QPen(c1, w1, Qt::SolidLine, _lines[type] = Style::Line(QPen(c1, w1, Qt::SolidLine,
@ -618,7 +618,7 @@ bool Style::parseLines(SubFile *file, SubFile::Handle &hdl,
_lines[type] = Style::Line(img); _lines[type] = Style::Line(img);
} else { } else {
if (!(file->readByte(hdl, w1) && file->readByte(hdl, w2))) if (!(file->readUInt8(hdl, w1) && file->readUInt8(hdl, w2)))
return false; return false;
_lines[type] = (w2 > w1) _lines[type] = (w2 > w1)
@ -644,7 +644,7 @@ bool Style::parseLines(SubFile *file, SubFile::Handle &hdl,
_lines[type] = Style::Line(img); _lines[type] = Style::Line(img);
} else { } else {
if (!file->readByte(hdl, w1)) if (!file->readUInt8(hdl, w1))
return false; return false;
_lines[type] = Style::Line(QPen(c1, w1, Qt::SolidLine, _lines[type] = Style::Line(QPen(c1, w1, Qt::SolidLine,
@ -666,7 +666,7 @@ bool Style::parseLines(SubFile *file, SubFile::Handle &hdl,
_lines[type] = Style::Line(img); _lines[type] = Style::Line(img);
} else { } else {
if (!file->readByte(hdl, w1)) if (!file->readUInt8(hdl, w1))
return false; return false;
_lines[type] = Style::Line(QPen(c1, w1, Qt::SolidLine, _lines[type] = Style::Line(QPen(c1, w1, Qt::SolidLine,
@ -689,7 +689,7 @@ bool Style::parseLines(SubFile *file, SubFile::Handle &hdl,
if (textColor) { if (textColor) {
quint8 labelFlags; quint8 labelFlags;
if (!file->readByte(hdl, labelFlags)) if (!file->readUInt8(hdl, labelFlags))
return false; return false;
if (labelFlags & 0x08) { if (labelFlags & 0x08) {
if (!readColor(file, hdl, c1)) if (!readColor(file, hdl, c1))
@ -751,7 +751,7 @@ static bool readColorTable(SubFile *file, SubFile::Handle &hdl, QImage& img,
for (int i = 0; i < colors; i++) { for (int i = 0; i < colors; i++) {
while (bits < 28) { while (bits < 28) {
if (!file->readByte(hdl, byte)) if (!file->readUInt8(hdl, byte))
return false; return false;
mask = 0x000000FF << bits; mask = 0x000000FF << bits;
@ -801,9 +801,9 @@ bool Style::parsePoints(SubFile *file, SubFile::Handle &hdl,
quint8 t8_1, width, height, numColors, imgType; quint8 t8_1, width, height, numColors, imgType;
if (!(file->seek(hdl, section.offset + info.offset) if (!(file->seek(hdl, section.offset + info.offset)
&& file->readByte(hdl, t8_1) && file->readByte(hdl, width) && file->readUInt8(hdl, t8_1) && file->readUInt8(hdl, width)
&& file->readByte(hdl, height) && file->readByte(hdl, numColors) && file->readUInt8(hdl, height) && file->readUInt8(hdl, numColors)
&& file->readByte(hdl, imgType))) && file->readUInt8(hdl, imgType)))
return false; return false;
bool localization = t8_1 & 0x04; bool localization = t8_1 & 0x04;
@ -820,8 +820,8 @@ bool Style::parsePoints(SubFile *file, SubFile::Handle &hdl,
_points[type] = Point(img); _points[type] = Point(img);
if (t8_1 == 0x03) { if (t8_1 == 0x03) {
if (!(file->readByte(hdl, numColors) if (!(file->readUInt8(hdl, numColors)
&& file->readByte(hdl, imgType))) && file->readUInt8(hdl, imgType)))
return false; return false;
if ((bpp = colors2bpp(numColors, imgType)) < 0) if ((bpp = colors2bpp(numColors, imgType)) < 0)
continue; continue;
@ -830,8 +830,8 @@ bool Style::parsePoints(SubFile *file, SubFile::Handle &hdl,
if (!readBitmap(file, hdl, img, bpp)) if (!readBitmap(file, hdl, img, bpp))
return false; return false;
} else if (t8_1 == 0x02) { } else if (t8_1 == 0x02) {
if (!(file->readByte(hdl, numColors) if (!(file->readUInt8(hdl, numColors)
&& file->readByte(hdl, imgType))) && file->readUInt8(hdl, imgType)))
return false; return false;
if ((bpp = colors2bpp(numColors, imgType)) < 0) if ((bpp = colors2bpp(numColors, imgType)) < 0)
continue; continue;
@ -845,7 +845,7 @@ bool Style::parsePoints(SubFile *file, SubFile::Handle &hdl,
if (textColor) { if (textColor) {
quint8 labelFlags; quint8 labelFlags;
QColor color; QColor color;
if (!file->readByte(hdl, labelFlags)) if (!file->readUInt8(hdl, labelFlags))
return false; return false;
if (labelFlags & 0x08) { if (labelFlags & 0x08) {
if (!readColor(file, hdl, color)) if (!readColor(file, hdl, color))
@ -874,7 +874,7 @@ bool Style::parseDrawOrder(SubFile *file, SubFile::Handle &hdl,
quint8 type; quint8 type;
quint32 subtype; quint32 subtype;
if (!(file->readByte(hdl, type) && file->readUInt32(hdl, subtype))) if (!(file->readUInt8(hdl, type) && file->readUInt32(hdl, subtype)))
return false; return false;
if (!subtype) if (!subtype)
@ -944,6 +944,9 @@ Style::Style(SubFile *typ)
if (typ) if (typ)
parseTYPFile(typ); parseTYPFile(typ);
// Override stuff breaking the style display logic
_points[0x11400] = Point(None);
} }
const Style::Line &Style::line(quint32 type) const const Style::Line &Style::line(quint32 type) const
@ -973,7 +976,8 @@ const Style::Point &Style::point(quint32 type) const
bool Style::isContourLine(quint32 type) bool Style::isContourLine(quint32 type)
{ {
return (type == TYPE(0x20) || type == TYPE(0x21) || type == TYPE(0x22) return (type == TYPE(0x20) || type == TYPE(0x21) || type == TYPE(0x22)
|| type == TYPE(0x23) || type == TYPE(0x24) || type == TYPE(0x25)); || type == TYPE(0x23) || type == TYPE(0x24) || type == TYPE(0x25)
|| (type & 0xffff00) == TYPE(0x109));
} }
bool Style::isSpot(quint32 type) bool Style::isSpot(quint32 type)
@ -1041,4 +1045,11 @@ QDebug operator<<(QDebug dbg, const Style::Line &line)
<< penColor(line.background()) << ", " << !line.img().isNull() << ")"; << penColor(line.background()) << ", " << !line.img().isNull() << ")";
return dbg.space(); return dbg.space();
} }
QDebug operator<<(QDebug dbg, const Style::Point &point)
{
dbg.nospace() << "Point(" << point.textFontSize() << ", "
<< point.textColor() << ", " << !point.img().isNull() << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG #endif // QT_NO_DEBUG

View File

@ -80,6 +80,8 @@ public:
class Point { class Point {
public: public:
Point() : _textFontSize(NotSet) {} Point() : _textFontSize(NotSet) {}
Point(FontSize fontSize, const QColor &textColor = QColor())
: _textColor(textColor), _textFontSize(fontSize) {}
Point(const QImage &img) : _textFontSize(NotSet), _img(img) {} Point(const QImage &img) : _textFontSize(NotSet), _img(img) {}
void setTextColor(const QColor &color) {_textColor = color;} void setTextColor(const QColor &color) {_textColor = color;}
@ -149,6 +151,7 @@ private:
#ifndef QT_NO_DEBUG #ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const Style::Polygon &polygon); QDebug operator<<(QDebug dbg, const Style::Polygon &polygon);
QDebug operator<<(QDebug dbg, const Style::Line &line); QDebug operator<<(QDebug dbg, const Style::Line &line);
QDebug operator<<(QDebug dbg, const Style::Point &point);
#endif // QT_NO_DEBUG #endif // QT_NO_DEBUG
#endif // STYLE_H #endif // STYLE_H

View File

@ -69,6 +69,49 @@ bool SubFile::readVUInt32(Handle &hdl, quint32 &val) const
return true; return true;
} }
bool SubFile::readVUInt32SW(Handle &hdl, quint32 bytes, quint32 &val) const
{
quint8 b;
val = 0;
for (quint32 i = bytes; i; i--) {
if (!readByte(hdl, b))
return false;
val |= ((quint32)b) << ((i-1) * 8);
}
return true;
}
bool SubFile::readVBitfield32(Handle &hdl, quint32 &bitfield) const
{
quint8 bits;
if (!readUInt8(hdl, bits))
return false;
if (!(bits & 1)) {
seek(hdl, hdl.pos - 1);
if (!((bits>>1) & 1)) {
if (!((bits>>2) & 1)) {
if (!readUInt32(hdl, bitfield))
return false;
} else {
if (!readUInt24(hdl, bitfield))
return false;
}
bitfield >>= 3;
} else {
if (!readUInt16(hdl, bitfield))
return false;
bitfield >>= 2;
}
} else
bitfield = bits>>1;
return true;
}
QString SubFile::fileName() const QString SubFile::fileName() const
{ {
return _file ? _file->fileName() : _img->fileName(); return _file ? _file->fileName() : _img->fileName();

View File

@ -4,8 +4,8 @@
#include <QVector> #include <QVector>
#include <QDebug> #include <QDebug>
class IMG;
class QFile; class QFile;
class IMG;
class SubFile class SubFile
{ {
@ -37,9 +37,19 @@ public:
void addBlock(quint16 block) {_blocks->append(block);} void addBlock(quint16 block) {_blocks->append(block);}
bool seek(Handle &handle, quint32 pos) const; bool seek(Handle &handle, quint32 pos) const;
bool readByte(Handle &handle, quint8 &val) const;
bool readUInt16(Handle &handle, quint16 &val) const template<typename T>
bool readUInt8(Handle &handle, T &val) const
{
quint8 b;
if (!readByte(handle, b))
return false;
val = b;
return true;
}
template<typename T>
bool readUInt16(Handle &handle, T &val) const
{ {
quint8 b0, b1; quint8 b0, b1;
if (!(readByte(handle, b0) && readByte(handle, b1))) if (!(readByte(handle, b0) && readByte(handle, b1)))
@ -88,6 +98,8 @@ public:
} }
bool readVUInt32(Handle &hdl, quint32 &val) const; bool readVUInt32(Handle &hdl, quint32 &val) const;
bool readVUInt32SW(Handle &hdl, quint32 bytes, quint32 &val) const;
bool readVBitfield32(Handle &hdl, quint32 &bitfield) const;
quint16 offset() const {return _blocks->first();} quint16 offset() const {return _blocks->first();}
QString fileName() const; QString fileName() const;
@ -96,6 +108,8 @@ protected:
quint32 _gmpOffset; quint32 _gmpOffset;
private: private:
bool readByte(Handle &handle, quint8 &val) const;
IMG *_img; IMG *_img;
QVector<quint16> *_blocks; QVector<quint16> *_blocks;
QFile *_file; QFile *_file;

View File

@ -44,7 +44,7 @@ bool TREFile::init()
quint16 hdrLen; quint16 hdrLen;
if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen) if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen)
&& seek(hdl, _gmpOffset + 0x0D) && readByte(hdl, locked))) && seek(hdl, _gmpOffset + 0x0D) && readUInt8(hdl, locked)))
return false; return false;
// Tile bounds // Tile bounds
@ -62,12 +62,15 @@ bool TREFile::init()
&& readUInt32(hdl, subdivSize))) && readUInt32(hdl, subdivSize)))
return false; return false;
// TRE7 info
if (hdrLen > 0x9A) { if (hdrLen > 0x9A) {
// TRE7 info
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)))
return false; return false;
// flags
if (!(seek(hdl, _gmpOffset + 0x86) && readUInt32(hdl, _flags)))
return false;
} }
// Tile levels // Tile levels
@ -75,7 +78,7 @@ bool TREFile::init()
return false; return false;
quint8 levels[64]; quint8 levels[64];
for (quint32 i = 0; i < levelsSize; i++) for (quint32 i = 0; i < levelsSize; i++)
if (!readByte(hdl, levels[i])) if (!readUInt8(hdl, levels[i]))
return false; return false;
if (locked) { if (locked) {
quint32 key; quint32 key;
@ -126,15 +129,16 @@ bool TREFile::load(int idx)
return false; return false;
for (int j = 0; j < _levels.at(idx).subdivs; j++) { for (int j = 0; j < _levels.at(idx).subdivs; j++) {
quint32 offset; quint32 oo;
qint32 lon, lat; qint32 lon, lat;
quint8 objects;
quint16 width, height, nextLevel; quint16 width, height, nextLevel;
if (!(readUInt24(hdl, offset) && readByte(hdl, objects) if (!(readUInt32(hdl, oo) && readInt24(hdl, lon) && readInt24(hdl, lat)
&& readInt24(hdl, lon) && readInt24(hdl, lat)
&& readUInt16(hdl, width) && readUInt16(hdl, height))) && readUInt16(hdl, width) && readUInt16(hdl, height)))
goto error; goto error;
quint32 offset = oo & 0xfffffff;
quint8 objects = (((qint16)height < 0) << 4) | (oo >> 0x1c);
if (idx != _levels.size() - 1) if (idx != _levels.size() - 1)
if (!readUInt16(hdl, nextLevel)) if (!readUInt16(hdl, nextLevel))
goto error; goto error;
@ -146,6 +150,7 @@ bool TREFile::load(int idx)
width <<= (24 - _levels.at(idx).bits); width <<= (24 - _levels.at(idx).bits);
height <<= (24 - _levels.at(idx).bits); height <<= (24 - _levels.at(idx).bits);
s = new SubDiv(offset, lon, lat, _levels.at(idx).bits, objects); s = new SubDiv(offset, lon, lat, _levels.at(idx).bits, objects);
sl.append(s); sl.append(s);

View File

@ -22,6 +22,8 @@ public:
const RectC &bounds() const {return _bounds;} const RectC &bounds() const {return _bounds;}
QList<SubDiv*> subdivs(const RectC &rect, int bits); QList<SubDiv*> subdivs(const RectC &rect, int bits);
quint32 shift(quint8 bits) const
{return (bits == _levels.last().bits) ? (_flags >> 0xb) & 7 : 0;}
private: private:
struct MapLevel { struct MapLevel {
@ -51,6 +53,7 @@ private:
quint32 _subdivOffset; quint32 _subdivOffset;
Extended _extended; Extended _extended;
int _firstLevel; int _firstLevel;
quint32 _flags;
QMap<int, SubDivTree*> _subdivs; QMap<int, SubDivTree*> _subdivs;
}; };

View File

@ -76,9 +76,11 @@ void VectorTile::objects(const RectC &rect, int bits,
{ {
QList<SubDiv*> subdivs = _tre->subdivs(rect, bits); QList<SubDiv*> subdivs = _tre->subdivs(rect, bits);
for (int i = 0; i < subdivs.size(); i++) { for (int i = 0; i < subdivs.size(); i++) {
_rgn->objects(rect, subdivs.at(i), _lbl, _net, polygons, lines, points); const SubDiv *subdiv = subdivs.at(i);
_rgn->extObjects(rect, subdivs.at(i), _lbl, polygons, lines, quint32 shift = _tre->shift(subdiv->bits());
points);
_rgn->objects(rect, subdiv, _lbl, _net, polygons, lines, points);
_rgn->extObjects(rect, subdiv, shift, _lbl, polygons, lines, points);
} }
} }

View File

@ -12,7 +12,9 @@ class VectorTile {
public: public:
VectorTile() : _tre(0), _rgn(0), _lbl(0), _net(0), _gmp(0) {} VectorTile() : _tre(0), _rgn(0), _lbl(0), _net(0), _gmp(0) {}
~VectorTile() ~VectorTile()
{delete _tre; delete _rgn; delete _lbl; delete _net; delete _gmp;} {
delete _tre; delete _rgn; delete _lbl; delete _net; delete _gmp;
}
bool init(); bool init();
void clear() {_tre->clear();} void clear() {_tre->clear();}