mirror of
https://github.com/tumic0/GPXSee.git
synced 2024-11-28 05:34:47 +01:00
Level 0
This commit is contained in:
parent
0e026d6a96
commit
d738ad7b5a
@ -1,35 +1,6 @@
|
||||
#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, _file.pos(_hdl) + _length))
|
||||
@ -41,7 +12,7 @@ bool BitStream1::flush()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BitStream4::flush()
|
||||
bool BitStream4F::flush()
|
||||
{
|
||||
if (_length && !_file.seek(_hdl, _file.pos(_hdl) + _length))
|
||||
return false;
|
||||
@ -96,7 +67,14 @@ bool BitStream4R::readBytes(int bytes, quint32 &val)
|
||||
Q_ASSERT(!b);
|
||||
}
|
||||
|
||||
return read(bytes * 8, val);
|
||||
val = 0;
|
||||
for (int i = 0; i < bytes; i++) {
|
||||
if (!read(8, b))
|
||||
return false;
|
||||
val |= (b << (i * 8));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BitStream4R::readVUInt32(quint32 &val)
|
||||
@ -139,7 +117,7 @@ bool BitStream4R::readVuint32SM(quint32 &val1, quint32 &val2, quint32 &val2Bits)
|
||||
return false;
|
||||
|
||||
if (!(b & 1)) {
|
||||
val1 = b >> 3 & 0x1f;
|
||||
val1 = b >> 3;
|
||||
val2 = b >> 1 & 3;
|
||||
val2Bits = 2;
|
||||
} else {
|
||||
@ -188,14 +166,33 @@ bool BitStream4R::skip(quint32 bytes)
|
||||
return true;
|
||||
}
|
||||
|
||||
void BitStream4R::resize(quint32 length)
|
||||
void BitStream4R::resize(quint32 bytes)
|
||||
{
|
||||
quint32 ab = (32 - _used)/8;
|
||||
quint32 ab = (32 - (_used + _unused) + 7)/8;
|
||||
|
||||
if (ab < length)
|
||||
_length = length - ab;
|
||||
if (ab <= bytes)
|
||||
_length = bytes - ab;
|
||||
else {
|
||||
_length = 0;
|
||||
_used += length * 8;
|
||||
_unused += (ab - bytes) * 8;
|
||||
}
|
||||
}
|
||||
|
||||
void BitStream4R::save(State &state)
|
||||
{
|
||||
state.pos = _file.pos(_hdl);
|
||||
state.length = _length;
|
||||
state.used = _used;
|
||||
state.unused = _unused;
|
||||
state.data = _data;
|
||||
}
|
||||
|
||||
bool BitStream4R::restore(const State &state)
|
||||
{
|
||||
_length = state.length;
|
||||
_used = state.used;
|
||||
_unused = state.unused;
|
||||
_data = state.data;
|
||||
|
||||
return _file.seek(_hdl, state.pos);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ public:
|
||||
BitStream1(const SubFile &file, SubFile::Handle &hdl, quint32 length)
|
||||
: _file(file), _hdl(hdl), _length(length), _remaining(0) {}
|
||||
|
||||
bool read(int bits, quint32 &val);
|
||||
template<typename T> bool read(int bits, T &val);
|
||||
bool flush();
|
||||
quint64 bitsAvailable() const {return (quint64)_length * 8 + _remaining;}
|
||||
|
||||
@ -25,7 +25,6 @@ public:
|
||||
: _file(file), _hdl(hdl), _length(length), _used(32), _unused(0),
|
||||
_data(0) {}
|
||||
|
||||
bool flush();
|
||||
quint64 bitsAvailable() const
|
||||
{return (quint64)_length * 8 + (32 - _used) - _unused;}
|
||||
|
||||
@ -42,10 +41,19 @@ public:
|
||||
: BitStream4(file, hdl, length) {}
|
||||
|
||||
bool read(int bits, quint32 &val);
|
||||
bool flush();
|
||||
};
|
||||
|
||||
class BitStream4R : public BitStream4 {
|
||||
public:
|
||||
struct State {
|
||||
quint32 pos;
|
||||
quint32 length;
|
||||
quint32 used;
|
||||
quint32 unused;
|
||||
quint32 data;
|
||||
};
|
||||
|
||||
BitStream4R(const SubFile &file, SubFile::Handle &hdl, quint32 length);
|
||||
|
||||
template<typename T> bool read(int bits, T &val);
|
||||
@ -54,9 +62,42 @@ public:
|
||||
bool readVuint32SM(quint32 &val1, quint32 &val2, quint32 &val2Bits);
|
||||
|
||||
bool skip(quint32 bytes);
|
||||
void resize(quint32 length);
|
||||
void resize(quint32 bytes);
|
||||
void save(State &state);
|
||||
bool restore(const State &state);
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
bool BitStream1::read(int bits, T &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;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool BitStream4R::read(int bits, T &val)
|
||||
{
|
||||
|
@ -28,3 +28,14 @@ bool HuffmanStreamR::init()
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HuffmanStreamR::init(int lonSign, int latSign, quint32 data,
|
||||
quint32 dataSize)
|
||||
{
|
||||
_lonSign = lonSign;
|
||||
_latSign = latSign;
|
||||
_symbolData = data;
|
||||
_symbolDataSize = dataSize;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -11,6 +11,8 @@ public:
|
||||
: _bs(bitstream), _table(table), _symbolDataSize(0), _symbolData(0),
|
||||
_lonSign(0), _latSign(0) {}
|
||||
|
||||
bool read(int bits, quint32 &val);
|
||||
bool readSymbol(quint32 &symbol);
|
||||
bool readNext(qint32 &lonDelta, qint32 &latDelta)
|
||||
{
|
||||
if (!(readDelta(_lonSign, lonDelta) && readDelta(_latSign, latDelta)))
|
||||
@ -52,7 +54,31 @@ bool HuffmanStream<BitStream>::sign(int &val)
|
||||
}
|
||||
|
||||
template <class BitStream>
|
||||
bool HuffmanStream<BitStream>::readDelta(int sign, qint32 &symbol)
|
||||
bool HuffmanStream<BitStream>::read(int bits, quint32 &val)
|
||||
{
|
||||
if (_symbolDataSize < (quint32)bits) {
|
||||
quint32 next;
|
||||
quint8 nextSize = qMin((quint64)(32 - _symbolDataSize),
|
||||
_bs.bitsAvailable());
|
||||
|
||||
if (!_bs.read(nextSize, next))
|
||||
return false;
|
||||
|
||||
_symbolData = (_symbolData << nextSize) | next;
|
||||
_symbolDataSize += nextSize;
|
||||
}
|
||||
|
||||
if (_symbolDataSize < (quint32)bits)
|
||||
return false;
|
||||
|
||||
val = (_symbolData << (32-_symbolDataSize)) >> (32 - bits);
|
||||
_symbolDataSize -= bits;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class BitStream>
|
||||
bool HuffmanStream<BitStream>::readSymbol(quint32 &symbol)
|
||||
{
|
||||
quint8 size;
|
||||
quint32 next;
|
||||
@ -65,10 +91,19 @@ bool HuffmanStream<BitStream>::readDelta(int sign, qint32 &symbol)
|
||||
_symbolDataSize += nextSize;
|
||||
|
||||
symbol = _table.symbol(_symbolData << (32 - _symbolDataSize), size);
|
||||
if (size > _symbolDataSize)
|
||||
return false;
|
||||
|
||||
if (size <= _symbolDataSize)
|
||||
_symbolDataSize -= size;
|
||||
else
|
||||
_symbolDataSize -= size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class BitStream>
|
||||
bool HuffmanStream<BitStream>::readDelta(int sign, qint32 &delta)
|
||||
{
|
||||
quint32 symbol;
|
||||
if (!readSymbol(symbol))
|
||||
return false;
|
||||
|
||||
if (symbol && !sign) {
|
||||
@ -79,7 +114,7 @@ bool HuffmanStream<BitStream>::readDelta(int sign, qint32 &symbol)
|
||||
_symbolDataSize--;
|
||||
}
|
||||
}
|
||||
symbol = sign * symbol;
|
||||
delta = sign * symbol;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -100,6 +135,7 @@ public:
|
||||
: HuffmanStream(bitstream, table) {}
|
||||
|
||||
bool init();
|
||||
bool init(int lonSign, int latSign, quint32 data, quint32 dataSize);
|
||||
};
|
||||
|
||||
#endif // HUFFMANSTREAM_H
|
||||
|
@ -2,10 +2,11 @@
|
||||
#include "huffmanstream.h"
|
||||
#include "subdiv.h"
|
||||
#include "nodfile.h"
|
||||
#include "lblfile.h"
|
||||
#include "netfile.h"
|
||||
|
||||
|
||||
bool adjCnts(BitStream4R &bs, QVector<quint16> &cnts, quint16 &mask)
|
||||
static bool readAdjCounts(BitStream4R &bs, QVector<quint16> &cnts, quint16 &mask)
|
||||
{
|
||||
quint32 val, cnt, bits;
|
||||
if (!bs.read(4, val))
|
||||
@ -17,7 +18,6 @@ bool adjCnts(BitStream4R &bs, QVector<quint16> &cnts, quint16 &mask)
|
||||
if (cnt == 5) {
|
||||
if (!bs.read(8, cnt))
|
||||
return false;
|
||||
Q_ASSERT(cnt > 4);
|
||||
}
|
||||
|
||||
if (cnt < 2)
|
||||
@ -30,14 +30,25 @@ bool adjCnts(BitStream4R &bs, QVector<quint16> &cnts, quint16 &mask)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool skipNodes(BitStream4R &bs, const QVector<quint16> &cnts, quint16 mask)
|
||||
static bool skipShape(BitStream4R &bs)
|
||||
{
|
||||
quint32 v1, v2, v2b;
|
||||
|
||||
if (!bs.readVuint32SM(v1, v2, v2b))
|
||||
return false;
|
||||
|
||||
return bs.skip(v1);
|
||||
}
|
||||
|
||||
static bool skipAdjShapes(BitStream4R &bs, const QVector<quint16> &cnts,
|
||||
quint16 mask, bool firstIsShape)
|
||||
{
|
||||
if (firstIsShape && !skipShape(bs))
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < cnts.size(); i++) {
|
||||
if (cnts.at(i) & mask) {
|
||||
quint32 v1, v2, v2b;
|
||||
if (!bs.readVuint32SM(v1, v2, v2b))
|
||||
return false;
|
||||
if (!bs.skip(v1))
|
||||
if (!skipShape(bs))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -45,7 +56,7 @@ bool skipNodes(BitStream4R &bs, const QVector<quint16> &cnts, quint16 mask)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool seekToLevel(BitStream4R &bs, quint8 level)
|
||||
static bool seekToLevel(BitStream4R &bs, quint8 level)
|
||||
{
|
||||
quint32 v1, v2, v2b;
|
||||
|
||||
@ -55,7 +66,6 @@ bool seekToLevel(BitStream4R &bs, quint8 level)
|
||||
if (!bs.skip(v1))
|
||||
return false;
|
||||
|
||||
Q_ASSERT(!(v2 & 2));
|
||||
if (v2 & 2)
|
||||
return false;
|
||||
if (v2 & 1)
|
||||
@ -65,7 +75,7 @@ bool seekToLevel(BitStream4R &bs, quint8 level)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool seekToLine(BitStream4R &bs, quint8 line)
|
||||
static bool seekToLine(BitStream4R &bs, quint8 line)
|
||||
{
|
||||
quint32 v1, v2, v2b;
|
||||
|
||||
@ -75,7 +85,6 @@ bool seekToLine(BitStream4R &bs, quint8 line)
|
||||
if (!bs.skip(v1))
|
||||
return false;
|
||||
|
||||
Q_ASSERT(!(v2 & 2));
|
||||
if (v2 & 2)
|
||||
return false;
|
||||
}
|
||||
@ -83,15 +92,295 @@ bool seekToLine(BitStream4R &bs, quint8 line)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool readLine(BitStream4R &bs, const SubDiv *subdiv,
|
||||
const HuffmanTable &table, IMG::Poly &poly)
|
||||
{
|
||||
quint32 v1, v2, v2b;
|
||||
if (!bs.readVuint32SM(v1, v2, v2b))
|
||||
return false;
|
||||
bs.resize(v1);
|
||||
|
||||
quint32 lon, lat;
|
||||
if (!(bs.read(0x12 - v2b, lon) && bs.read(16, lat)))
|
||||
return false;
|
||||
if (2 < v2b)
|
||||
lon |= (v2 >> 2) << (0x12U - v2b);
|
||||
|
||||
QPoint pos = QPoint(LS(subdiv->lon(), 8) + LS((qint16)lon, 32-subdiv->bits()),
|
||||
LS(subdiv->lat(), 8) + LS((qint16)lat, 32-subdiv->bits()));
|
||||
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
|
||||
|
||||
poly.boundingRect = RectC(c, c);
|
||||
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||
|
||||
HuffmanStreamR stream(bs, table);
|
||||
if (!stream.init())
|
||||
return false;
|
||||
qint32 lonDelta, latDelta;
|
||||
|
||||
while (stream.readNext(lonDelta, latDelta)) {
|
||||
pos.rx() += LS(lonDelta, 32-subdiv->bits());
|
||||
if (pos.rx() < 0 && subdiv->lon() >= 0)
|
||||
pos.rx() = 0x7fffffff;
|
||||
pos.ry() += LS(latDelta, 32-subdiv->bits());
|
||||
|
||||
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
|
||||
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||
poly.boundingRect = poly.boundingRect.united(c);
|
||||
}
|
||||
|
||||
return stream.atEnd();
|
||||
}
|
||||
|
||||
static bool readNodeGeometry(NODFile *nod, SubFile::Handle &nodHdl,
|
||||
NODFile::AdjacencyInfo &adj, IMG::Poly &poly, quint16 cnt = 0xFFFF)
|
||||
{
|
||||
for (int i = 0; i <= cnt; i++) {
|
||||
int ret = nod->nextNode(nodHdl, adj);
|
||||
if (ret < 0)
|
||||
return false;
|
||||
else if (ret > 0)
|
||||
return (cnt == 0xFFFF);
|
||||
|
||||
Coordinates c(toWGS32(adj.nodeInfo.pos.x()),
|
||||
toWGS32(adj.nodeInfo.pos.y()));
|
||||
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||
poly.boundingRect = poly.boundingRect.united(c);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool skipNodes(NODFile *nod, SubFile::Handle &nodHdl,
|
||||
NODFile::AdjacencyInfo &adj, int cnt)
|
||||
{
|
||||
for (int i = 0; i < cnt; i++)
|
||||
if (nod->nextNode(nodHdl, adj))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool readShape(NODFile *nod, SubFile::Handle &nodHdl,
|
||||
NODFile::AdjacencyInfo &adj, BitStream4R &bs, const HuffmanTable &table,
|
||||
const SubDiv *subdiv, quint32 shift, IMG::Poly &poly, quint16 cnt = 0xFFFF,
|
||||
bool check = false)
|
||||
{
|
||||
quint32 v1, v2, v2b;
|
||||
if (!bs.readVuint32SM(v1, v2, v2b))
|
||||
return false;
|
||||
BitStream4R::State state;
|
||||
bs.save(state);
|
||||
bs.resize(v1);
|
||||
|
||||
quint32 flags;
|
||||
if (!bs.read(8, flags))
|
||||
return false;
|
||||
flags |= (v2 << 8);
|
||||
|
||||
bool hasCoordinatesAdjustBit = flags & (1 << (v2b + 7));
|
||||
bool useEosBit = flags & (1 << (v2b + 5));
|
||||
bool startWithStream = flags & (1 << (v2b + 6));
|
||||
|
||||
quint32 extraBits;
|
||||
int lonSign, latSign;
|
||||
|
||||
if ((flags >> (v2b + 4) & 1) == 0) {
|
||||
extraBits = v2b + 4;
|
||||
lonSign = 0;
|
||||
} else {
|
||||
extraBits = v2b + 3;
|
||||
lonSign = 1;
|
||||
if ((flags >> (v2b + 3) & 1) != 0) {
|
||||
lonSign = -1;
|
||||
}
|
||||
}
|
||||
extraBits -= 1;
|
||||
if ((flags >> extraBits & 1) == 0) {
|
||||
latSign = 0;
|
||||
} else {
|
||||
extraBits -= 1;
|
||||
latSign = -1;
|
||||
if ((flags >> extraBits & 1) == 0) {
|
||||
latSign = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (nod->nextNode(nodHdl, adj))
|
||||
return false;
|
||||
QPoint pos(adj.nodeInfo.pos);
|
||||
quint16 nodes = 0;
|
||||
|
||||
if (!startWithStream) {
|
||||
Coordinates c(toWGS32(adj.nodeInfo.pos.x()),
|
||||
toWGS32(adj.nodeInfo.pos.y()));
|
||||
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||
poly.boundingRect = poly.boundingRect.united(c);
|
||||
|
||||
while (!(adj.flags & 1)) {
|
||||
int ret = nod->nextNode(nodHdl, adj);
|
||||
if (ret < 0)
|
||||
return false;
|
||||
else if (ret > 0)
|
||||
break;
|
||||
nodes++;
|
||||
|
||||
c = Coordinates(toWGS32(adj.nodeInfo.pos.x()),
|
||||
toWGS32(adj.nodeInfo.pos.y()));
|
||||
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||
poly.boundingRect = poly.boundingRect.united(c);
|
||||
pos = adj.nodeInfo.pos;
|
||||
}
|
||||
}
|
||||
|
||||
HuffmanStreamR stream(bs, table);
|
||||
if (!stream.init(lonSign, latSign, flags, extraBits))
|
||||
return false;
|
||||
qint32 lonDelta, latDelta;
|
||||
QVector<QPoint> deltas;
|
||||
|
||||
quint32 adjustBit = 0;
|
||||
quint32 stepsCnt = 0;
|
||||
quint32 steps = 0;
|
||||
quint32 eos = 0;
|
||||
|
||||
while (true) {
|
||||
if ((stepsCnt == steps) && !useEosBit) {
|
||||
if (!stream.readSymbol(steps))
|
||||
break;
|
||||
if (!steps)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!stream.readNext(lonDelta, latDelta))
|
||||
break;
|
||||
|
||||
if (hasCoordinatesAdjustBit && !stream.read(1, adjustBit))
|
||||
return false;
|
||||
|
||||
stepsCnt++;
|
||||
|
||||
if (useEosBit) {
|
||||
if (!stream.read(1, eos))
|
||||
return false;
|
||||
} else {
|
||||
if (steps == stepsCnt)
|
||||
eos = 1;
|
||||
}
|
||||
|
||||
if (!startWithStream) {
|
||||
pos.rx() += LS(lonDelta, 32-subdiv->bits()-shift);
|
||||
pos.ry() += LS(latDelta, 32-subdiv->bits()-shift);
|
||||
|
||||
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
|
||||
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||
poly.boundingRect = poly.boundingRect.united(c);
|
||||
} else {
|
||||
deltas.append(QPoint(lonDelta, latDelta));
|
||||
poly.points.append(QPointF());
|
||||
}
|
||||
|
||||
if (startWithStream && eos) {
|
||||
for (int i = deltas.size() - 1, j = 0; i >= 0; i--, j++) {
|
||||
pos.rx() -= LS(deltas.at(i).x(), 32-subdiv->bits()-shift);
|
||||
pos.ry() -= LS(deltas.at(i).y(), 32-subdiv->bits()-shift);
|
||||
|
||||
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
|
||||
poly.points[poly.points.size() - 1 - j] = QPointF(c.lon(), c.lat());
|
||||
poly.boundingRect = poly.boundingRect.united(c);
|
||||
}
|
||||
|
||||
pos = adj.nodeInfo.pos;
|
||||
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
|
||||
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||
poly.boundingRect = poly.boundingRect.united(c);
|
||||
|
||||
stepsCnt = 0;
|
||||
steps = 0;
|
||||
startWithStream = false;
|
||||
|
||||
if (adj.flags & 1)
|
||||
eos = 0;
|
||||
}
|
||||
|
||||
if (eos) {
|
||||
if (nodes >= cnt)
|
||||
break;
|
||||
|
||||
do {
|
||||
int ret = nod->nextNode(nodHdl, adj);
|
||||
if (ret < 0)
|
||||
return false;
|
||||
else if (ret > 0)
|
||||
break;
|
||||
nodes++;
|
||||
|
||||
if (check && nodes == cnt) {
|
||||
if (!(bs.restore(state) && bs.skip(v1)
|
||||
&& bs.readVuint32SM(v1, v2, v2b)))
|
||||
return false;
|
||||
if (5 < v2b)
|
||||
v2 >>= v2b - 2;
|
||||
if (v2 & 1)
|
||||
break;
|
||||
}
|
||||
|
||||
Coordinates c(toWGS32(adj.nodeInfo.pos.x()),
|
||||
toWGS32(adj.nodeInfo.pos.y()));
|
||||
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||
poly.boundingRect = poly.boundingRect.united(c);
|
||||
pos = adj.nodeInfo.pos;
|
||||
} while (!(adj.flags & 1) && nodes < cnt);
|
||||
|
||||
if (nodes == cnt)
|
||||
break;
|
||||
|
||||
steps = 0;
|
||||
stepsCnt = 0;
|
||||
eos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool NETFile::linkLabel(Handle &hdl, quint32 offset, quint32 size, LBLFile *lbl,
|
||||
Handle &lblHdl, Label &label)
|
||||
{
|
||||
if (!seek(hdl, offset))
|
||||
return false;
|
||||
BitStream1 bs(*this, hdl, size);
|
||||
|
||||
quint32 flags, b, labelPtr = 0;
|
||||
if (!bs.read(8, flags))
|
||||
return false;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (!bs.read(8, b))
|
||||
return false;
|
||||
labelPtr |= (b << (i * 8));
|
||||
}
|
||||
|
||||
if (lbl && (labelPtr & 0x3FFFFF)) {
|
||||
if (labelPtr & 0x400000) {
|
||||
quint32 lblOff;
|
||||
if (lblOffset(hdl, labelPtr & 0x3FFFFF, lblOff) && lblOff)
|
||||
label = lbl->label(lblHdl, lblOff);
|
||||
|
||||
} else
|
||||
label = lbl->label(lblHdl, labelPtr & 0x3FFFFF);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NETFile::init(Handle &hdl)
|
||||
{
|
||||
quint8 multiplier;
|
||||
quint16 hdrLen;
|
||||
|
||||
if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen)
|
||||
&& seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset)
|
||||
&& readUInt32(hdl, _size) && readUInt8(hdl, multiplier)))
|
||||
&& readUInt32(hdl, _size) && readUInt8(hdl, _shift)))
|
||||
return false;
|
||||
|
||||
if (hdrLen >= 0x47) {
|
||||
@ -105,20 +394,25 @@ bool NETFile::init(Handle &hdl)
|
||||
return false;
|
||||
}
|
||||
|
||||
_multiplier = 1<<multiplier;
|
||||
_init = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NETFile::link(const SubDiv *subdiv, Handle &hdl, NODFile *nod,
|
||||
Handle &nodHdl, const NODFile::BlockInfo blockInfo, quint8 linkId,
|
||||
quint8 lineId, const HuffmanTable &table, QList<IMG::Poly> *lines)
|
||||
bool NETFile::link(const SubDiv *subdiv, quint32 shift, Handle &hdl,
|
||||
NODFile *nod, Handle &nodHdl, LBLFile *lbl, Handle &lblHdl,
|
||||
const NODFile::BlockInfo blockInfo, quint8 linkId, quint8 lineId,
|
||||
const HuffmanTable &table, QList<IMG::Poly> *lines)
|
||||
{
|
||||
if (!_multiplier && !init(hdl))
|
||||
if (!_init && !init(hdl))
|
||||
return false;
|
||||
|
||||
// TODO
|
||||
if (!subdiv->level())
|
||||
Q_ASSERT(_tableId == table.id());
|
||||
if (_tableId != table.id())
|
||||
return false;
|
||||
|
||||
IMG::Poly poly;
|
||||
if (!nod->linkType(nodHdl, blockInfo, linkId, poly.type))
|
||||
return false;
|
||||
|
||||
NODFile::LinkInfo linkInfo;
|
||||
@ -126,95 +420,89 @@ bool NETFile::link(const SubDiv *subdiv, Handle &hdl, NODFile *nod,
|
||||
return false;
|
||||
|
||||
quint32 linkOffset = _linksOffset + (linkInfo.linkOffset << _linksShift);
|
||||
Q_ASSERT(linkOffset <= _linksOffset + _linksSize);
|
||||
if (linkOffset > _linksOffset + _linksSize)
|
||||
return false;
|
||||
if (!seek(hdl, linkOffset))
|
||||
return false;
|
||||
BitStream4R bs(*this, hdl, linkOffset - _linksOffset);
|
||||
QVector<quint16> ca;
|
||||
quint16 mask = 0;
|
||||
quint32 size;
|
||||
|
||||
quint8 s68 = (linkInfo.flags >> 0x12) & 1;
|
||||
quint8 s69 = (linkInfo.flags >> 0x11) & 1;
|
||||
quint8 s6a = (linkInfo.flags >> 0x13) & 1;
|
||||
|
||||
if (s6a == 1) {
|
||||
QVector<quint16> ca;
|
||||
quint16 mask;
|
||||
|
||||
if (!seek(hdl, linkOffset))
|
||||
return false;
|
||||
|
||||
BitStream4R bs(*this, hdl, linkOffset - _linksOffset);
|
||||
quint32 size;
|
||||
|
||||
if (s69 == 0 || s6a == 1) {
|
||||
if (!bs.readVUInt32(size))
|
||||
return false;
|
||||
|
||||
if (s69 == 0) {
|
||||
if (!adjCnts(bs, ca, mask))
|
||||
return false;
|
||||
}
|
||||
if (s68 == 1) {
|
||||
quint32 v1, v2, v2b;
|
||||
if (!bs.readVuint32SM(v1, v2, v2b))
|
||||
return false;
|
||||
Q_ASSERT(v1);
|
||||
if (!bs.skip(v1))
|
||||
return false;
|
||||
}
|
||||
if (!skipNodes(bs, ca, mask))
|
||||
}
|
||||
if (s69 == 0) {
|
||||
if (!readAdjCounts(bs, ca, mask))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!subdiv->level()) {
|
||||
NODFile::AdjacencyInfo adj(nod, blockInfo, linkId, linkInfo);
|
||||
|
||||
if (s69 == 1) {
|
||||
if (s68 == 1) {
|
||||
if (!readShape(nod, nodHdl, adj, bs, table, subdiv, shift, poly))
|
||||
return false;
|
||||
} else {
|
||||
if (!readNodeGeometry(nod, nodHdl, adj, poly))
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
quint16 mask2 = mask + 0xffff;
|
||||
for (int i = 0; i <= ca.size(); i++) {
|
||||
quint16 step = (i < ca.size()) ? ca.at(i) & mask2 : 0xFFFF;
|
||||
bool shape = (i > 0) ? ca.at(i-1) & mask : (s68 == 1);
|
||||
if (i == lineId) {
|
||||
if (shape) {
|
||||
bool check = (i < ca.size()) ? (ca.at(i) & mask) : false;
|
||||
if (!readShape(nod, nodHdl, adj, bs, table, subdiv,
|
||||
shift, poly, step, check))
|
||||
return false;
|
||||
} else {
|
||||
if (!readNodeGeometry(nod, nodHdl, adj, poly, step))
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (shape && !skipShape(bs))
|
||||
return false;
|
||||
if (!skipNodes(nod, nodHdl, adj, step))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!skipAdjShapes(bs, ca, mask, s68 == 1))
|
||||
return false;
|
||||
|
||||
if (!seekToLevel(bs, subdiv->level()))
|
||||
return false;
|
||||
if (!seekToLine(bs, lineId))
|
||||
return false;
|
||||
|
||||
quint32 v1, v2, v2b;
|
||||
if (!bs.readVuint32SM(v1, v2, v2b))
|
||||
if (!readLine(bs, subdiv, table, poly))
|
||||
return false;
|
||||
bs.resize(v1);
|
||||
|
||||
quint32 lon, lat;
|
||||
if (!(bs.read(0x12 - v2b, lon) && bs.read(16, lat)))
|
||||
return false;
|
||||
if (2 < v2b)
|
||||
lon |= (v2 >> 2) << (0x12U - v2b);
|
||||
|
||||
QPoint pos = QPoint(LS(subdiv->lon(), 8) + LS((qint16)lon,
|
||||
32-subdiv->bits()), LS(subdiv->lat(), 8) + LS((qint16)lat,
|
||||
32-subdiv->bits()));
|
||||
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
|
||||
|
||||
IMG::Poly poly;
|
||||
if (!nod->linkType(nodHdl, blockInfo, linkId, poly.type))
|
||||
return false;
|
||||
poly.boundingRect = RectC(c, c);
|
||||
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||
|
||||
Q_ASSERT(_tableId == table.id());
|
||||
HuffmanStreamR stream(bs, table);
|
||||
if (!stream.init())
|
||||
return false;
|
||||
qint32 lonDelta, latDelta;
|
||||
|
||||
while (stream.readNext(lonDelta, latDelta)) {
|
||||
pos.rx() += LS(lonDelta, 32-subdiv->bits());
|
||||
if (pos.rx() < 0 && subdiv->lon() >= 0)
|
||||
pos.rx() = 0x7fffffff;
|
||||
pos.ry() += LS(latDelta, 32-subdiv->bits());
|
||||
|
||||
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
|
||||
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||
poly.boundingRect = poly.boundingRect.united(c);
|
||||
}
|
||||
|
||||
lines->append(poly);
|
||||
}
|
||||
|
||||
linkLabel(hdl, linkOffset, _linksSize - (linkOffset - _linksOffset), lbl,
|
||||
lblHdl, poly.label);
|
||||
|
||||
lines->append(poly);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NETFile::lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset)
|
||||
{
|
||||
if (!_multiplier && !init(hdl))
|
||||
if (!_init && !init(hdl))
|
||||
return false;
|
||||
|
||||
if (!(seek(hdl, _offset + netOffset * _multiplier)
|
||||
if (!(seek(hdl, _offset + (netOffset << _shift))
|
||||
&& readUInt24(hdl, lblOffset)))
|
||||
return false;
|
||||
|
||||
|
@ -14,24 +14,29 @@ class NETFile : public SubFile
|
||||
{
|
||||
public:
|
||||
NETFile(IMG *img) : SubFile(img), _offset(0), _size(0), _linksOffset(0),
|
||||
_linksSize(0), _multiplier(0), _linksShift(0) {}
|
||||
_linksSize(0), _shift(0), _linksShift(0), _init(false) {}
|
||||
NETFile(const QString &path) : SubFile(path), _offset(0), _size(0),
|
||||
_linksOffset(0), _linksSize(0), _multiplier(0), _linksShift(0) {}
|
||||
_linksOffset(0), _linksSize(0), _shift(0), _linksShift(0),
|
||||
_init(false) {}
|
||||
NETFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset),
|
||||
_offset(0), _size(0), _linksOffset(0), _linksSize(0), _multiplier(0),
|
||||
_linksShift(0) {}
|
||||
_offset(0), _size(0), _linksOffset(0), _linksSize(0), _shift(0),
|
||||
_linksShift(0), _init(false) {}
|
||||
|
||||
bool lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset);
|
||||
bool link(const SubDiv *subdiv, Handle &hdl, NODFile *nod, Handle &nodHdl,
|
||||
bool link(const SubDiv *subdiv, quint32 shift, Handle &hdl, NODFile *nod,
|
||||
Handle &nodHdl, LBLFile *lbl, Handle &lblHdl,
|
||||
const NODFile::BlockInfo blockInfo, quint8 linkId, quint8 lineId,
|
||||
const HuffmanTable &table, QList<IMG::Poly> *lines);
|
||||
|
||||
private:
|
||||
bool init(Handle &hdl);
|
||||
bool linkLabel(Handle &hdl, quint32 offset, quint32 size, LBLFile *lbl,
|
||||
Handle &lblHdl, Label &label);
|
||||
|
||||
quint32 _offset, _size, _linksOffset, _linksSize;
|
||||
quint8 _multiplier, _linksShift;
|
||||
quint8 _shift, _linksShift;
|
||||
quint8 _tableId;
|
||||
bool _init;
|
||||
};
|
||||
|
||||
#endif // NETFILE_H
|
||||
|
@ -1,6 +1,81 @@
|
||||
#include "bitstream.h"
|
||||
#include "nodfile.h"
|
||||
|
||||
|
||||
#define ARRAY_SIZE(array) \
|
||||
(sizeof(array) / sizeof(array[0]))
|
||||
|
||||
static const struct {
|
||||
quint8 lon;
|
||||
quint8 lat;
|
||||
} LLBITS[] = {
|
||||
{0xc, 0xc}, {0x8, 0x10}, {0x10, 0x8}, {0x10, 0x10}, {0xc, 0x14},
|
||||
{0x14, 0xc}, {0x14, 0x14}
|
||||
};
|
||||
|
||||
union NodeShift {
|
||||
qint32 offset;
|
||||
quint8 id;
|
||||
};
|
||||
|
||||
static bool adjDistInfo(BitStream1 &bs, bool extraBit, quint8 &flags)
|
||||
{
|
||||
quint32 data, cnt;
|
||||
|
||||
if (!bs.read(extraBit | 8, data))
|
||||
return false;
|
||||
|
||||
data <<= !extraBit;
|
||||
flags |= (quint8)data & 1;
|
||||
data >>= 1;
|
||||
|
||||
for (cnt = 0; (data >> cnt) & 1; cnt++) {
|
||||
if (cnt == 4)
|
||||
break;
|
||||
}
|
||||
if (!bs.read(cnt * 4, data))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool adjNodeInfo(BitStream1 &bs, bool extraBit, NodeShift &shift,
|
||||
quint8 &flags)
|
||||
{
|
||||
quint32 data;
|
||||
|
||||
if (!bs.read(9, data))
|
||||
return false;
|
||||
|
||||
data <<= !extraBit;
|
||||
|
||||
if (data & 1)
|
||||
shift.id = data >> 1;
|
||||
else {
|
||||
quint32 bits = (data >> 1) & 7;
|
||||
quint32 data2;
|
||||
flags |= 2;
|
||||
|
||||
if (!bs.read(bits + extraBit + 1, data2))
|
||||
return false;
|
||||
|
||||
data = data2 << (6 - extraBit) | data >> 4;
|
||||
bits = 0x19 - bits;
|
||||
shift.offset = ((qint32)(data << bits) >> bits);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool skipOptAdjData(BitStream1 &bs)
|
||||
{
|
||||
// TODO
|
||||
Q_UNUSED(bs);
|
||||
Q_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool NODFile::init(Handle &hdl)
|
||||
{
|
||||
quint16 hdrLen;
|
||||
@ -9,9 +84,10 @@ bool NODFile::init(Handle &hdl)
|
||||
return false;
|
||||
|
||||
if (hdrLen >= 0x7b) {
|
||||
if (!(seek(hdl, _gmpOffset + 0x21) && readUInt8(hdl, _blockShift)
|
||||
&& readUInt8(hdl, _nodeShift)))
|
||||
if (!(seek(hdl, _gmpOffset + 0x1d) && readUInt32(hdl, _flags)
|
||||
&& readUInt8(hdl, _blockShift) && readUInt8(hdl, _nodeShift)))
|
||||
return false;
|
||||
|
||||
if (!(seek(hdl, _gmpOffset + 0x67) && readUInt32(hdl, _blockOffset)
|
||||
&& readUInt32(hdl, _blockSize) && readUInt16(hdl, _blockRecordSize)
|
||||
&& readUInt32(hdl, _indexOffset) && readUInt32(hdl, _indexSize)
|
||||
@ -38,42 +114,49 @@ quint32 NODFile::indexIdSize(Handle &hdl)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool NODFile::blockInfo(Handle &hdl, quint32 blockIndexId,
|
||||
bool NODFile::readBlock(Handle &hdl, quint32 blockOffset,
|
||||
BlockInfo &blockInfo) const
|
||||
{
|
||||
quint32 blockOffset;
|
||||
quint32 offset = _indexRecordSize * blockIndexId + _indexOffset;
|
||||
quint32 offsetSize = (_indexFlags & 3) + 1;
|
||||
blockInfo.offset = blockOffset;
|
||||
|
||||
|
||||
Q_ASSERT(offset <= _indexOffset + _indexSize);
|
||||
if (!(seek(hdl, offset) && readVUInt32(hdl, offsetSize, blockOffset)))
|
||||
return false;
|
||||
|
||||
blockInfo.offset = (blockOffset << _blockShift) + _blockOffset;
|
||||
|
||||
if (!(seek(hdl, blockInfo.offset) && readUInt16(hdl, blockInfo.h0)
|
||||
&& readUInt32(hdl, blockInfo.h2) && readUInt32(hdl, blockInfo.h6)
|
||||
&& readUInt32(hdl, blockInfo.ha) && readUInt16(hdl, blockInfo.he)
|
||||
&& readUInt8(hdl, blockInfo.h10) && readUInt8(hdl, blockInfo.h11)
|
||||
&& readUInt8(hdl, blockInfo.h12)))
|
||||
if (!(seek(hdl, blockInfo.offset + _blockOffset)
|
||||
&& readUInt16(hdl, blockInfo.hdr.s0) && readUInt32(hdl, blockInfo.hdr.s2)
|
||||
&& readUInt32(hdl, blockInfo.hdr.s6) && readUInt32(hdl, blockInfo.hdr.sa)
|
||||
&& readUInt16(hdl, blockInfo.hdr.se) && readUInt8(hdl, blockInfo.hdr.s10)
|
||||
&& readUInt8(hdl, blockInfo.hdr.s11) && readUInt8(hdl, blockInfo.hdr.s12)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NODFile::blockInfo(Handle &hdl, quint32 blockId, BlockInfo &blockInfo) const
|
||||
{
|
||||
quint32 blockOffset;
|
||||
quint32 offset = _indexRecordSize * blockId + _indexOffset;
|
||||
quint32 offsetSize = (_indexFlags & 3) + 1;
|
||||
|
||||
if (offset > _indexOffset + _indexSize)
|
||||
return false;
|
||||
if (!(seek(hdl, offset) && readVUInt32(hdl, offsetSize, blockOffset)))
|
||||
return false;
|
||||
|
||||
return readBlock(hdl, blockOffset << _blockShift, blockInfo);
|
||||
}
|
||||
|
||||
bool NODFile::linkInfo(Handle &hdl, const BlockInfo &blockInfo, quint32 linkId,
|
||||
LinkInfo &linkInfo) const
|
||||
{
|
||||
Q_ASSERT(linkId < blockInfo.h10);
|
||||
if (linkId >= blockInfo.hdr.s10)
|
||||
return false;
|
||||
|
||||
quint32 infoOffset = ((blockInfo.he * linkId) >> 3) + 0x13
|
||||
+ ((blockInfo.h0 >> 0xb) & 1) + blockInfo.offset;
|
||||
quint32 s1 = ((blockInfo.h0 >> 2) & 0x1f) + 8;
|
||||
quint32 s2 = (blockInfo.h0 >> 7) & 0xf;
|
||||
quint32 skip = (blockInfo.he * linkId) & 7;
|
||||
quint32 infoOffset = ((blockInfo.hdr.se * linkId) >> 3) + 0x13
|
||||
+ ((blockInfo.hdr.s0 >> 0xb) & 1) + blockInfo.offset + _blockOffset;
|
||||
quint32 s1 = ((blockInfo.hdr.s0 >> 2) & 0x1f) + 8;
|
||||
quint32 s2 = (blockInfo.hdr.s0 >> 7) & 0xf;
|
||||
quint32 skip = (blockInfo.hdr.se * linkId) & 7;
|
||||
|
||||
Q_ASSERT(infoOffset <= _blockOffset + _blockSize);
|
||||
if (infoOffset > _blockOffset + _blockSize || infoOffset < blockInfo.offset)
|
||||
return false;
|
||||
if (!seek(hdl, infoOffset))
|
||||
return false;
|
||||
|
||||
@ -90,20 +173,340 @@ bool NODFile::linkInfo(Handle &hdl, const BlockInfo &blockInfo, quint32 linkId,
|
||||
} else {
|
||||
if (!bs.read(s1 - s2, linkInfo.linkOffset))
|
||||
return false;
|
||||
linkInfo.linkOffset += blockInfo.ha;
|
||||
linkInfo.linkOffset += blockInfo.hdr.sa;
|
||||
}
|
||||
|
||||
if (!bs.read(s2, linkInfo.nodeOffset))
|
||||
return false;
|
||||
linkInfo.nodeOffset = (blockInfo.offset - linkInfo.nodeOffset)
|
||||
>> _nodeShift;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NODFile::nodeInfo(Handle &hdl, const BlockInfo &blockInfo,
|
||||
quint32 nodeOffset, NodeInfo &nodeInfo) const
|
||||
{
|
||||
quint32 infoOffset = (nodeOffset << _nodeShift) + _blockOffset;
|
||||
if (infoOffset > _blockOffset + _blockSize || infoOffset < blockInfo.offset)
|
||||
return false;
|
||||
if (!seek(hdl, infoOffset))
|
||||
return false;
|
||||
|
||||
BitStream1 bs(*this, hdl, _blockOffset + _blockSize - infoOffset);
|
||||
|
||||
if (!bs.read(8, nodeInfo.flags))
|
||||
return false;
|
||||
|
||||
if ((nodeInfo.flags & 7) >= ARRAY_SIZE(LLBITS))
|
||||
return false;
|
||||
quint8 lonBits = LLBITS[nodeInfo.flags & 7].lon;
|
||||
quint8 latBits = LLBITS[nodeInfo.flags & 7].lat;
|
||||
quint8 maxBits = ((_flags >> 10) & 7) | 0x18;
|
||||
|
||||
quint32 lon, lat;
|
||||
if (!(bs.read(lonBits, lon) && bs.read(latBits, lat)))
|
||||
return false;
|
||||
|
||||
quint8 lonShift = 0x20 - lonBits;
|
||||
quint8 latShift = 0x20 - latBits;
|
||||
quint8 shift = 0x20 - maxBits;
|
||||
QPoint pos((((int)(lon << lonShift) >> lonShift) << shift)
|
||||
+ blockInfo.hdr.s2, (((int)(lat << latShift) >> latShift) << shift)
|
||||
+ blockInfo.hdr.s6);
|
||||
nodeInfo.bytes = ((lonBits + latBits) >> 3) + 1;
|
||||
|
||||
if ((maxBits < 0x1c) && (nodeInfo.flags & 8)) {
|
||||
quint8 extraBits = 0x1c - maxBits;
|
||||
quint32 extraLon, extraLat;
|
||||
|
||||
if (!(bs.read(extraBits, extraLon) && bs.read(extraBits, extraLat)))
|
||||
return false;
|
||||
pos.setX(pos.x() | extraLon << 4); pos.setY(pos.y() | extraLat << 4);
|
||||
nodeInfo.bytes++;
|
||||
}
|
||||
// TODO?: extra bits
|
||||
|
||||
nodeInfo.pos = pos;
|
||||
nodeInfo.flags &= 0xf8;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NODFile::nodeOffset(Handle &hdl, const BlockInfo &blockInfo,
|
||||
quint8 nodeId, quint32 &nodeOffset) const
|
||||
{
|
||||
if (nodeId >= blockInfo.hdr.s11)
|
||||
return false;
|
||||
|
||||
quint32 offset = ((blockInfo.hdr.s10 * blockInfo.hdr.se + 7) >> 3)
|
||||
+ 0x13 + nodeId * 3 + _blockOffset + blockInfo.offset
|
||||
+ ((blockInfo.hdr.s0 >> 0xb) & 1);
|
||||
|
||||
if (!(seek(hdl, offset) && readUInt24(hdl, nodeOffset)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NODFile::nodeBlock(Handle &hdl, quint32 nodeOffset,
|
||||
BlockInfo &blockInfo) const
|
||||
{
|
||||
int low = 0;
|
||||
int high = _indexSize / _indexRecordSize - 1;
|
||||
quint32 offsetSize = (_indexFlags & 3) + 1;
|
||||
|
||||
while (low <= high) {
|
||||
quint32 m = ((low + high) / 2);
|
||||
quint32 offset = _indexRecordSize * m + _indexOffset;
|
||||
quint32 blockOffset, prevBlockOffset;
|
||||
|
||||
if (m > 0) {
|
||||
if (!(seek(hdl, offset - _indexRecordSize)
|
||||
&& readVUInt32(hdl, offsetSize, prevBlockOffset)
|
||||
&& readVUInt32(hdl, offsetSize, blockOffset)))
|
||||
return false;
|
||||
} else {
|
||||
if (!(seek(hdl, offset)
|
||||
&& readVUInt32(hdl, offsetSize, blockOffset)))
|
||||
return false;
|
||||
prevBlockOffset = 0;
|
||||
}
|
||||
prevBlockOffset <<= _blockShift;
|
||||
blockOffset <<= _blockShift;
|
||||
|
||||
if (blockOffset < nodeOffset)
|
||||
low = m + 1;
|
||||
else {
|
||||
if (prevBlockOffset <= nodeOffset)
|
||||
return readBlock(hdl, blockOffset, blockInfo);
|
||||
else
|
||||
high = m - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NODFile::absAdjInfo(Handle &hdl, AdjacencyInfo &adj) const
|
||||
{
|
||||
quint32 infoOffset = (adj.nodeOffset << _nodeShift) + _blockOffset
|
||||
+ adj.nodeInfo.bytes;
|
||||
if (!seek(hdl, infoOffset))
|
||||
return false;
|
||||
BitStream1 bs(*this, hdl, _blockOffset + _blockSize - infoOffset);
|
||||
|
||||
quint8 linkId = adj.blockInfo.hdr.s10;
|
||||
quint32 m2p = 2;
|
||||
quint32 skip = 8;
|
||||
quint32 flags;
|
||||
quint32 nextOffset;
|
||||
bool extraBit = (adj.nodeInfo.flags >> 6) & 1;
|
||||
bool linkIdValid = true;
|
||||
bool firstLoop = true;
|
||||
|
||||
do {
|
||||
adj.flags = 0;
|
||||
|
||||
if (!bs.read(8, flags))
|
||||
return false;
|
||||
|
||||
if (firstLoop) {
|
||||
skip >>= (flags >> 5) & 1;
|
||||
flags |= 0x20;
|
||||
}
|
||||
firstLoop = false;
|
||||
quint32 f4 = flags & 0x10;
|
||||
quint32 f4sn = (f4 >> 4) ^ 1;
|
||||
quint32 m1 = (flags >> 5) & f4sn;
|
||||
quint32 m2 = (f4 >> 3) | (f4sn & (flags >> 6));
|
||||
|
||||
if (m1) {
|
||||
if (!bs.read(8, linkId))
|
||||
return false;
|
||||
linkIdValid = true;
|
||||
}
|
||||
|
||||
if ((m2 != m2p) || (flags & 0x10) || m1) {
|
||||
quint32 data;
|
||||
if (!bs.read(skip, data))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(flags & 0x10)) {
|
||||
if (!adjDistInfo(bs, (m2 == 1 && linkIdValid), adj.flags))
|
||||
return false;
|
||||
|
||||
NodeShift shift;
|
||||
if (!adjNodeInfo(bs, extraBit, shift, adj.flags))
|
||||
return false;
|
||||
if (adj.flags & 2)
|
||||
nextOffset = adj.nodeOffset + shift.offset;
|
||||
else if (!nodeOffset(adj.extHdl, adj.blockInfo, shift.id, nextOffset))
|
||||
return false;
|
||||
|
||||
m2p = m2;
|
||||
}
|
||||
|
||||
if (flags & 0x8) {
|
||||
quint32 data;
|
||||
if (!bs.read(8, data))
|
||||
return false;
|
||||
if (!(data & 0xe0)) {
|
||||
if (!bs.read(8, data))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ((_flags & 0x18) && !skipOptAdjData(bs))
|
||||
return false;
|
||||
|
||||
if ((m2 == 1) && linkIdValid) {
|
||||
LinkInfo li;
|
||||
if (adj.linkId == 0xFFFFFFFF) {
|
||||
if (!linkInfo(adj.extHdl, adj.blockInfo, linkId, li))
|
||||
return false;
|
||||
} else
|
||||
li.linkOffset = 0xFFFFFFFF;
|
||||
|
||||
if ((adj.linkOffset == li.linkOffset) || (adj.linkId == linkId)) {
|
||||
adj.nodeOffset = nextOffset;
|
||||
if (!(adj.flags & 2)) {
|
||||
adj.linkId = 0xFFFFFFFF;
|
||||
return nodeBlock(hdl, adj.nodeOffset << _nodeShift,
|
||||
adj.blockInfo);
|
||||
} else {
|
||||
adj.linkId = linkId;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
linkIdValid = false;
|
||||
}
|
||||
} while (!(flags & 0x80));
|
||||
|
||||
adj.nodeOffset = 0xFFFFFFFF;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NODFile::relAdjInfo(Handle &hdl, AdjacencyInfo &adj) const
|
||||
{
|
||||
quint32 infoOffset = (adj.nodeOffset << _nodeShift) + _blockOffset
|
||||
+ adj.nodeInfo.bytes;
|
||||
if (!seek(hdl, infoOffset))
|
||||
return false;
|
||||
|
||||
BitStream1 bs(*this, hdl, _blockOffset + _blockSize - infoOffset);
|
||||
|
||||
quint32 linkId = adj.blockInfo.hdr.s10;
|
||||
quint32 skip = 8;
|
||||
quint32 flagsBits = 8;
|
||||
quint32 flags;
|
||||
quint32 nextOffset;
|
||||
bool extraBit = (adj.nodeInfo.flags >> 6) & 1;
|
||||
bool linkIdValid = true;
|
||||
bool firstLoop = true;
|
||||
|
||||
do {
|
||||
adj.flags = 0;
|
||||
|
||||
if (!bs.read(flagsBits, flags))
|
||||
return false;
|
||||
|
||||
flags <<= (8U - flagsBits);
|
||||
if (firstLoop) {
|
||||
skip >>= (flags >> 5) & 1;
|
||||
flags = ((flags >> 1) & 0x20) | (flags & 0xffffffdf);
|
||||
}
|
||||
firstLoop = false;
|
||||
flagsBits >>= (flags >> 3) & 1;
|
||||
quint32 m = (((flags & 0x70) == 0x30) << 1) | ((flags >> 6) & 1);
|
||||
if (!m) {
|
||||
adj.nodeOffset = 0xFFFFFFFF;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((flags & 0x60) == 0x60) {
|
||||
if (!bs.read(8, linkId))
|
||||
return false;
|
||||
linkIdValid = true;
|
||||
}
|
||||
|
||||
if (((flags & 0x70) == 0x70)) {
|
||||
quint32 data;
|
||||
if (!bs.read(skip, data))
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((flags & 0x50) == 0x50) {
|
||||
if (!adjDistInfo(bs, false, adj.flags))
|
||||
return false;
|
||||
adj.flags |= 1;
|
||||
}
|
||||
if ((flags >> 6) & 1) {
|
||||
NodeShift shift;
|
||||
if (!adjNodeInfo(bs, extraBit, shift, adj.flags))
|
||||
return false;
|
||||
if (adj.flags & 2)
|
||||
nextOffset = adj.nodeOffset + shift.offset;
|
||||
else if (!nodeOffset(adj.extHdl, adj.blockInfo, shift.id, nextOffset))
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((_flags & 0x18) && !skipOptAdjData(bs))
|
||||
return false;
|
||||
|
||||
if (((m == 1) && linkIdValid)) {
|
||||
LinkInfo li;
|
||||
if (adj.linkId == 0xFFFFFFFF) {
|
||||
if (!linkInfo(adj.extHdl, adj.blockInfo, linkId, li))
|
||||
return false;
|
||||
} else
|
||||
li.linkOffset = 0xFFFFFFFF;
|
||||
|
||||
if ((adj.linkOffset == li.linkOffset) || (adj.linkId == linkId)) {
|
||||
adj.nodeOffset = nextOffset;
|
||||
if (!(adj.flags & 2)) {
|
||||
adj.linkId = 0xFFFFFFFF;
|
||||
return nodeBlock(hdl, adj.nodeOffset << _nodeShift,
|
||||
adj.blockInfo);
|
||||
} else {
|
||||
adj.linkId = linkId;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
linkIdValid = false;
|
||||
}
|
||||
} while (!(flags & 0x80));
|
||||
|
||||
adj.nodeOffset = 0xFFFFFFFF;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int NODFile::nextNode(Handle &hdl, AdjacencyInfo &adjInfo)
|
||||
{
|
||||
if (adjInfo.nodeOffset == 0xFFFFFFFF)
|
||||
return 1;
|
||||
|
||||
if (!nodeInfo(hdl, adjInfo.blockInfo, adjInfo.nodeOffset,
|
||||
adjInfo.nodeInfo))
|
||||
return -1;
|
||||
if (!adjacencyInfo(hdl, adjInfo))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool NODFile::linkType(Handle &hdl, const BlockInfo &blockInfo, quint8 linkId,
|
||||
quint32 &type) const
|
||||
{
|
||||
quint32 offset = ((blockInfo.h10 * blockInfo.he + 7) >> 3) + 0x13 +
|
||||
blockInfo.offset + ((blockInfo.h0 >> 0xb) & 1) + (quint32)blockInfo.h11
|
||||
* 3;
|
||||
quint32 offset = ((blockInfo.hdr.s10 * blockInfo.hdr.se + 7) >> 3) + 0x13
|
||||
+ blockInfo.offset + _blockOffset + ((blockInfo.hdr.s0 >> 0xb) & 1)
|
||||
+ blockInfo.hdr.s11 * 3;
|
||||
quint32 low = 0;
|
||||
quint32 high = blockInfo.h12 - 1;
|
||||
quint32 high = blockInfo.hdr.s12 - 1;
|
||||
quint32 pos;
|
||||
quint16 val;
|
||||
|
||||
@ -142,7 +545,7 @@ bool NODFile::linkType(Handle &hdl, const BlockInfo &blockInfo, quint8 linkId,
|
||||
}
|
||||
}
|
||||
|
||||
type *= 256;
|
||||
type <<= 8;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -7,23 +7,53 @@
|
||||
class NODFile : public SubFile
|
||||
{
|
||||
public:
|
||||
struct BlockInfo {
|
||||
struct BlockInfo
|
||||
{
|
||||
quint32 offset;
|
||||
quint16 h0;
|
||||
quint32 h2;
|
||||
quint32 h6;
|
||||
quint32 ha;
|
||||
quint16 he;
|
||||
quint8 h10; // links count
|
||||
quint8 h11;
|
||||
quint8 h12;
|
||||
struct
|
||||
{
|
||||
quint32 s2; // node lon base
|
||||
quint32 s6; // node lat base
|
||||
quint32 sa;
|
||||
quint16 s0; // flags
|
||||
quint16 se; // link info bit size
|
||||
quint8 s10; // links count
|
||||
quint8 s11; // nodes count
|
||||
quint8 s12; // link types count
|
||||
} hdr;
|
||||
};
|
||||
|
||||
struct LinkInfo {
|
||||
struct LinkInfo
|
||||
{
|
||||
quint32 linkOffset;
|
||||
quint32 nodeOffset;
|
||||
quint32 flags;
|
||||
};
|
||||
|
||||
struct NodeInfo
|
||||
{
|
||||
QPoint pos;
|
||||
quint8 flags;
|
||||
quint8 bytes;
|
||||
};
|
||||
|
||||
struct AdjacencyInfo
|
||||
{
|
||||
AdjacencyInfo(const SubFile *file, const BlockInfo &blockInfo,
|
||||
quint32 linkId, const LinkInfo &linkInfo) : extHdl(file),
|
||||
blockInfo(blockInfo), nodeOffset(linkInfo.nodeOffset),
|
||||
linkOffset(linkInfo.linkOffset), linkId(linkId)
|
||||
{}
|
||||
|
||||
Handle extHdl;
|
||||
struct BlockInfo blockInfo;
|
||||
struct NodeInfo nodeInfo;
|
||||
quint32 nodeOffset;
|
||||
quint32 linkOffset;
|
||||
quint32 linkId;
|
||||
quint8 flags;
|
||||
};
|
||||
|
||||
NODFile(IMG *img) : SubFile(img), _indexOffset(0), _indexSize(0),
|
||||
_indexFlags(0), _blockOffset(0), _blockSize(0), _indexRecordSize(0),
|
||||
_blockRecordSize(0), _blockShift(0), _nodeShift(0) {}
|
||||
@ -36,19 +66,33 @@ public:
|
||||
_nodeShift(0) {}
|
||||
|
||||
quint32 indexIdSize(Handle &hdl);
|
||||
bool blockInfo(Handle &hdl, quint32 blockIndexId,
|
||||
BlockInfo &blockInfo) const;
|
||||
bool blockInfo(Handle &hdl, quint32 blockId, BlockInfo &blockInfo) const;
|
||||
bool linkInfo(Handle &hdl, const BlockInfo &blockInfo, quint32 linkId,
|
||||
LinkInfo &linkInfo) const;
|
||||
bool linkType(Handle &hdl, const BlockInfo &blockInfo, quint8 linkId,
|
||||
quint32 &type) const;
|
||||
int nextNode(Handle &hdl, AdjacencyInfo &adjInfo);
|
||||
|
||||
private:
|
||||
bool init(Handle &hdl);
|
||||
bool nodeInfo(Handle &hdl, const BlockInfo &blockInfo, quint32 nodeOffset,
|
||||
NodeInfo &nodeInfo) const;
|
||||
bool nodeOffset(Handle &hdl, const BlockInfo &blockInfo, quint8 nodeId,
|
||||
quint32 &nodeOffset) const;
|
||||
bool absAdjInfo(Handle &hdl, AdjacencyInfo &adj) const;
|
||||
bool relAdjInfo(Handle &hdl, AdjacencyInfo &adj) const;
|
||||
bool adjacencyInfo(Handle &hdl, AdjacencyInfo &adj) const
|
||||
{
|
||||
return (adj.nodeInfo.flags & 0x20) ? absAdjInfo(hdl, adj)
|
||||
: relAdjInfo(hdl, adj);
|
||||
}
|
||||
bool nodeBlock(Handle &hdl, quint32 nodeOffset, BlockInfo &blockInfo) const;
|
||||
bool readBlock(Handle &hdl, quint32 blockOffset, BlockInfo &blockInfo) const;
|
||||
|
||||
quint32 _indexOffset, _indexSize, _indexFlags, _blockOffset, _blockSize;
|
||||
quint16 _indexRecordSize, _blockRecordSize;
|
||||
quint8 _blockShift, _nodeShift;
|
||||
quint32 _flags;
|
||||
};
|
||||
|
||||
#endif // NETFILE_H
|
||||
|
@ -424,8 +424,9 @@ bool RGNFile::extPointObjects(Handle &hdl, const SubDiv *subdiv, LBLFile *lbl,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RGNFile::links(Handle &hdl, const SubDiv *subdiv, NETFile *net,
|
||||
Handle &netHdl, NODFile *nod, Handle &nodHdl, QList<IMG::Poly> *lines) const
|
||||
bool RGNFile::links(Handle &hdl, const SubDiv *subdiv, quint32 shift,
|
||||
NETFile *net, Handle &netHdl, NODFile *nod, Handle &nodHdl, LBLFile *lbl,
|
||||
Handle &lblHdl, QList<IMG::Poly> *lines) const
|
||||
{
|
||||
quint32 size, blockIndexIdSize, blockIndexId;
|
||||
quint8 flags;
|
||||
@ -494,8 +495,8 @@ bool RGNFile::links(Handle &hdl, const SubDiv *subdiv, NETFile *net,
|
||||
lineId = 0;
|
||||
}
|
||||
|
||||
net->link(subdiv, netHdl, nod, nodHdl, blockInfo, linkId, lineId,
|
||||
_huffmanTable, lines);
|
||||
net->link(subdiv, shift, netHdl, nod, nodHdl, lbl, lblHdl,
|
||||
blockInfo, linkId, lineId, _huffmanTable, lines);
|
||||
}
|
||||
|
||||
Q_ASSERT(entryStart + size == pos(hdl));
|
||||
|
@ -46,8 +46,9 @@ public:
|
||||
QList<IMG::Poly> *polys) const;
|
||||
bool extPointObjects(Handle &hdl, const SubDiv *subdiv, LBLFile *lbl,
|
||||
Handle &lblHdl, QList<IMG::Point> *points) const;
|
||||
bool links(Handle &hdl, const SubDiv *subdiv, NETFile *net, Handle &netHdl,
|
||||
NODFile *nod, Handle &nodHdl, QList<IMG::Poly> *lines) const;
|
||||
bool links(Handle &hdl, const SubDiv *subdiv, quint32 shift, NETFile *net,
|
||||
Handle &netHdl, NODFile *nod, Handle &nodHdl, LBLFile *lbl, Handle &lblHdl,
|
||||
QList<IMG::Poly> *lines) const;
|
||||
|
||||
bool subdivInit(Handle &hdl, SubDiv *subdiv) const;
|
||||
|
||||
|
@ -149,7 +149,8 @@ void VectorTile::polys(const RectC &rect, int bits, bool baseMap,
|
||||
lblHdl, &p);
|
||||
_rgn->extPolyObjects(rgnHdl, subdiv, shift, RGNFile::Line, _lbl,
|
||||
lblHdl, &l);
|
||||
_rgn->links(rgnHdl, subdiv, _net, netHdl, _nod, nodHdl, &l);
|
||||
_rgn->links(rgnHdl, subdiv, shift, _net, netHdl, _nod, nodHdl, _lbl,
|
||||
lblHdl, &l);
|
||||
|
||||
copyPolys(rect, &p, polygons);
|
||||
copyPolys(rect, &l, lines);
|
||||
|
Loading…
Reference in New Issue
Block a user