1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-24 03:35: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/data/link.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/textpointitem.h \
src/map/projection.h \
@ -243,6 +247,10 @@ SOURCES += src/main.cpp \
src/GUI/mapview.cpp \
src/GUI/areaitem.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/textpointitem.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 "common/programpaths.h"
#include "vectortile.h"
@ -110,8 +110,8 @@ IMG::IMG(const QString &fileName)
QString fn(QByteArray(name, sizeof(name)));
if (VectorTile::isTileFile(tt)) {
VectorTile *tile;
QMap<QString, VectorTile*>::iterator it = tileMap.find(fn);
if (it == tileMap.end()) {
TileMap::const_iterator it = tileMap.find(fn);
if (it == tileMap.constEnd()) {
tile = new VectorTile();
tileMap.insert(fn, tile);
} else
@ -152,7 +152,8 @@ IMG::IMG(const QString &fileName)
}
// 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();
if (!tile->init()) {

View File

@ -56,10 +56,10 @@ bool LBLFile::init(Handle &hdl)
quint8 multiplier, poiMultiplier;
if (!(seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset)
&& readUInt32(hdl, _size) && readByte(hdl, multiplier)
&& readByte(hdl, _encoding) && seek(hdl, _gmpOffset + 0x57)
&& readUInt32(hdl, _size) && readUInt8(hdl, multiplier)
&& readUInt8(hdl, _encoding) && seek(hdl, _gmpOffset + 0x57)
&& readUInt32(hdl, _poiOffset) && readUInt32(hdl, _poiSize)
&& readByte(hdl, poiMultiplier) && seek(hdl, _gmpOffset + 0xAA)
&& readUInt8(hdl, poiMultiplier) && seek(hdl, _gmpOffset + 0xAA)
&& readUInt16(hdl, codepage)))
return false;
@ -89,7 +89,7 @@ Label LBLFile::label6b(Handle &hdl, quint32 offset) const
return Label();
while (true) {
if (!(readByte(hdl, b1) && readByte(hdl, b2) && readByte(hdl, b3)))
if (!(readUInt8(hdl, b1) && readUInt8(hdl, b2) && readUInt8(hdl, b3)))
return Label();
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();
while (true) {
if (!readByte(hdl, c))
if (!readUInt8(hdl, c))
return Label();
if (!c || c == 0x1d)
break;

View File

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

View File

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

View File

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

View File

@ -4,6 +4,7 @@
#include "img.h"
#include "subfile.h"
#include "subdiv.h"
#include "huffmantable.h"
class LBLFile;
class NETFile;
@ -14,26 +15,28 @@ public:
RGNFile(IMG *img)
: SubFile(img), _offset(0), _size(0), _polygonsOffset(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),
_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,
NETFile *net, QList<IMG::Poly> *polygons, QList<IMG::Poly> *lines,
QList<IMG::Point> *points);
void extObjects(const RectC &rect, const SubDiv *subdiv, LBLFile *lbl,
QList<IMG::Poly> *polygons, QList<IMG::Poly> *lines,
void objects(const RectC &rect, const SubDiv *subdiv,
LBLFile *lbl, NETFile *net, QList<IMG::Poly> *polygons,
QList<IMG::Poly> *lines, QList<IMG::Point> *points);
void extObjects(const RectC &rect, const SubDiv *subdiv, quint32 shift,
LBLFile *lbl, QList<IMG::Poly> *polygons, QList<IMG::Poly> *lines,
QList<IMG::Point> *points);
private:
class Segment {
public:
enum Type {
Point = 0x10,
IndexedPoint = 0x20,
Line = 0x40,
Polygon = 0x80
Point = 0x1,
IndexedPoint = 0x2,
Line = 0x4,
Polygon = 0x8,
RoadReference = 0x10
};
Segment() : _start(0), _end(0), _type(Point) {}
@ -54,45 +57,6 @@ private:
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);
QVector<Segment> segments(Handle &hdl, const SubDiv *subdiv) const;
@ -103,12 +67,18 @@ private:
const Segment &segment, LBLFile *lbl, Handle &lblHdl,
QList<IMG::Point> *points) const;
bool extPolyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
const Segment &segment, LBLFile *lbl, Handle &lblHdl,
QList<IMG::Poly> *polys) const;
quint32 shift, const Segment &segment, LBLFile *lbl, Handle &lblHdl,
QList<IMG::Poly> *polys, bool line) const;
bool extPointObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
const Segment &segment, LBLFile *lbl, Handle &lblHdl,
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);
quint32 _offset;
@ -116,10 +86,15 @@ private:
quint32 _polygonsOffset;
quint32 _polygonsSize;
quint32 _polygonsFlags[3];
quint32 _linesOffset;
quint32 _linesSize;
quint32 _linesFlags[3];
quint32 _pointsOffset;
quint32 _pointsSize;
quint32 _pointsFlags[3];
HuffmanTable _huffmanTable;
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 x = 0; x < img.width(); x += 8/bpp) {
quint8 color;
if (!file->readByte(hdl, color))
if (!file->readUInt8(hdl, color))
return false;
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;
if (!(file->readByte(hdl, b) && file->readByte(hdl, g)
&& file->readByte(hdl, r)))
if (!(file->readUInt8(hdl, b) && file->readUInt8(hdl, g)
&& file->readUInt8(hdl, r)))
return false;
color = qRgb(r, g, b);
@ -333,14 +333,14 @@ static bool skipLocalization(SubFile *file, SubFile::Handle &hdl)
quint8 t8;
quint16 len;
if (!file->readByte(hdl, t8))
if (!file->readUInt8(hdl, t8))
return false;
len = t8;
if (len & 0x01)
len = len >> 1;
else {
if (!file->readByte(hdl, t8))
if (!file->readUInt8(hdl, t8))
return false;
len = (((quint16)t8) << 8) | len;
len = len >> 2;
@ -361,7 +361,7 @@ bool Style::itemInfo(SubFile *file, SubFile::Handle &hdl,
if (section.arrayItemSize == 5) {
if (!(file->readUInt16(hdl, t16_1) && file->readUInt16(hdl, t16_2)
&& file->readByte(hdl, t8)))
&& file->readUInt8(hdl, t8)))
return false;
info.offset = t16_2 | (t8<<16);
} else if (section.arrayItemSize == 4) {
@ -369,7 +369,7 @@ bool Style::itemInfo(SubFile *file, SubFile::Handle &hdl,
return false;
info.offset = t16_2;
} 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;
info.offset = t8;
} else
@ -400,7 +400,7 @@ bool Style::parsePolygons(SubFile *file, SubFile::Handle &hdl,
quint8 t8, flags;
if (!(file->seek(hdl, section.offset + info.offset)
&& file->readByte(hdl, t8)))
&& file->readUInt8(hdl, t8)))
return false;
flags = t8 & 0x0F;
@ -516,7 +516,7 @@ bool Style::parseLines(SubFile *file, SubFile::Handle &hdl,
quint8 t8_1, t8_2, flags, rows;
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;
flags = t8_1 & 0x07;
rows = t8_1 >> 3;
@ -541,7 +541,7 @@ bool Style::parseLines(SubFile *file, SubFile::Handle &hdl,
_lines[type] = Style::Line(img);
} else {
if (!(file->readByte(hdl, w1) && file->readByte(hdl, w2)))
if (!(file->readUInt8(hdl, w1) && file->readUInt8(hdl, w2)))
return false;
_lines[type] = (w2 > w1)
@ -568,7 +568,7 @@ bool Style::parseLines(SubFile *file, SubFile::Handle &hdl,
_lines[type] = Style::Line(img);
} else {
if (!(file->readByte(hdl, w1) && file->readByte(hdl, w2)))
if (!(file->readUInt8(hdl, w1) && file->readUInt8(hdl, w2)))
return false;
_lines[type] = (w2 > w1)
@ -595,7 +595,7 @@ bool Style::parseLines(SubFile *file, SubFile::Handle &hdl,
_lines[type] = Style::Line(img);
} else {
if (!(file->readByte(hdl, w1) && file->readByte(hdl, w2)))
if (!(file->readUInt8(hdl, w1) && file->readUInt8(hdl, w2)))
return false;
_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);
} else {
if (!(file->readByte(hdl, w1) && file->readByte(hdl, w2)))
if (!(file->readUInt8(hdl, w1) && file->readUInt8(hdl, w2)))
return false;
_lines[type] = (w2 > w1)
@ -644,7 +644,7 @@ bool Style::parseLines(SubFile *file, SubFile::Handle &hdl,
_lines[type] = Style::Line(img);
} else {
if (!file->readByte(hdl, w1))
if (!file->readUInt8(hdl, w1))
return false;
_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);
} else {
if (!file->readByte(hdl, w1))
if (!file->readUInt8(hdl, w1))
return false;
_lines[type] = Style::Line(QPen(c1, w1, Qt::SolidLine,
@ -689,7 +689,7 @@ bool Style::parseLines(SubFile *file, SubFile::Handle &hdl,
if (textColor) {
quint8 labelFlags;
if (!file->readByte(hdl, labelFlags))
if (!file->readUInt8(hdl, labelFlags))
return false;
if (labelFlags & 0x08) {
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++) {
while (bits < 28) {
if (!file->readByte(hdl, byte))
if (!file->readUInt8(hdl, byte))
return false;
mask = 0x000000FF << bits;
@ -801,9 +801,9 @@ bool Style::parsePoints(SubFile *file, SubFile::Handle &hdl,
quint8 t8_1, width, height, numColors, imgType;
if (!(file->seek(hdl, section.offset + info.offset)
&& file->readByte(hdl, t8_1) && file->readByte(hdl, width)
&& file->readByte(hdl, height) && file->readByte(hdl, numColors)
&& file->readByte(hdl, imgType)))
&& file->readUInt8(hdl, t8_1) && file->readUInt8(hdl, width)
&& file->readUInt8(hdl, height) && file->readUInt8(hdl, numColors)
&& file->readUInt8(hdl, imgType)))
return false;
bool localization = t8_1 & 0x04;
@ -820,8 +820,8 @@ bool Style::parsePoints(SubFile *file, SubFile::Handle &hdl,
_points[type] = Point(img);
if (t8_1 == 0x03) {
if (!(file->readByte(hdl, numColors)
&& file->readByte(hdl, imgType)))
if (!(file->readUInt8(hdl, numColors)
&& file->readUInt8(hdl, imgType)))
return false;
if ((bpp = colors2bpp(numColors, imgType)) < 0)
continue;
@ -830,8 +830,8 @@ bool Style::parsePoints(SubFile *file, SubFile::Handle &hdl,
if (!readBitmap(file, hdl, img, bpp))
return false;
} else if (t8_1 == 0x02) {
if (!(file->readByte(hdl, numColors)
&& file->readByte(hdl, imgType)))
if (!(file->readUInt8(hdl, numColors)
&& file->readUInt8(hdl, imgType)))
return false;
if ((bpp = colors2bpp(numColors, imgType)) < 0)
continue;
@ -845,7 +845,7 @@ bool Style::parsePoints(SubFile *file, SubFile::Handle &hdl,
if (textColor) {
quint8 labelFlags;
QColor color;
if (!file->readByte(hdl, labelFlags))
if (!file->readUInt8(hdl, labelFlags))
return false;
if (labelFlags & 0x08) {
if (!readColor(file, hdl, color))
@ -874,7 +874,7 @@ bool Style::parseDrawOrder(SubFile *file, SubFile::Handle &hdl,
quint8 type;
quint32 subtype;
if (!(file->readByte(hdl, type) && file->readUInt32(hdl, subtype)))
if (!(file->readUInt8(hdl, type) && file->readUInt32(hdl, subtype)))
return false;
if (!subtype)
@ -944,6 +944,9 @@ Style::Style(SubFile *typ)
if (typ)
parseTYPFile(typ);
// Override stuff breaking the style display logic
_points[0x11400] = Point(None);
}
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)
{
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)
@ -1041,4 +1045,11 @@ QDebug operator<<(QDebug dbg, const Style::Line &line)
<< penColor(line.background()) << ", " << !line.img().isNull() << ")";
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

View File

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

View File

@ -69,6 +69,49 @@ bool SubFile::readVUInt32(Handle &hdl, quint32 &val) const
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
{
return _file ? _file->fileName() : _img->fileName();

View File

@ -4,8 +4,8 @@
#include <QVector>
#include <QDebug>
class IMG;
class QFile;
class IMG;
class SubFile
{
@ -37,9 +37,19 @@ public:
void addBlock(quint16 block) {_blocks->append(block);}
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;
if (!(readByte(handle, b0) && readByte(handle, b1)))
@ -88,6 +98,8 @@ public:
}
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();}
QString fileName() const;
@ -96,6 +108,8 @@ protected:
quint32 _gmpOffset;
private:
bool readByte(Handle &handle, quint8 &val) const;
IMG *_img;
QVector<quint16> *_blocks;
QFile *_file;

View File

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

View File

@ -22,6 +22,8 @@ public:
const RectC &bounds() const {return _bounds;}
QList<SubDiv*> subdivs(const RectC &rect, int bits);
quint32 shift(quint8 bits) const
{return (bits == _levels.last().bits) ? (_flags >> 0xb) & 7 : 0;}
private:
struct MapLevel {
@ -51,6 +53,7 @@ private:
quint32 _subdivOffset;
Extended _extended;
int _firstLevel;
quint32 _flags;
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);
for (int i = 0; i < subdivs.size(); i++) {
_rgn->objects(rect, subdivs.at(i), _lbl, _net, polygons, lines, points);
_rgn->extObjects(rect, subdivs.at(i), _lbl, polygons, lines,
points);
const SubDiv *subdiv = subdivs.at(i);
quint32 shift = _tre->shift(subdiv->bits());
_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:
VectorTile() : _tre(0), _rgn(0), _lbl(0), _net(0), _gmp(0) {}
~VectorTile()
{delete _tre; delete _rgn; delete _lbl; delete _net; delete _gmp;}
{
delete _tre; delete _rgn; delete _lbl; delete _net; delete _gmp;
}
bool init();
void clear() {_tre->clear();}