2020-06-27 22:46:26 +02:00
|
|
|
#include "bitstream.h"
|
|
|
|
#include "huffmanstream.h"
|
|
|
|
#include "subdiv.h"
|
|
|
|
#include "nodfile.h"
|
2020-09-18 20:56:00 +02:00
|
|
|
#include "lblfile.h"
|
2020-11-10 00:58:19 +01:00
|
|
|
#include "rgnfile.h"
|
2019-05-10 18:56:19 +02:00
|
|
|
#include "netfile.h"
|
|
|
|
|
2021-09-20 21:43:17 +02:00
|
|
|
using namespace Garmin;
|
2021-04-10 15:27:40 +02:00
|
|
|
using namespace IMG;
|
2020-06-27 22:46:26 +02:00
|
|
|
|
2020-09-18 20:56:00 +02:00
|
|
|
static bool readAdjCounts(BitStream4R &bs, QVector<quint16> &cnts, quint16 &mask)
|
2020-06-27 22:46:26 +02:00
|
|
|
{
|
|
|
|
quint32 val, cnt, bits;
|
|
|
|
if (!bs.read(4, val))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
cnt = ((val >> 2) & 3) + 2;
|
|
|
|
bits = ((val * 2) & 6) + 4;
|
|
|
|
mask = 1<<(3 + ((val * 2) & 6));
|
|
|
|
if (cnt == 5) {
|
|
|
|
if (!bs.read(8, cnt))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cnt < 2)
|
|
|
|
return false;
|
|
|
|
cnts.resize(cnt - 1);
|
|
|
|
for (int i = 0; i < cnts.size(); i++)
|
|
|
|
if (!bs.read(bits, cnts[i]))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-09-18 20:56:00 +02:00
|
|
|
static bool skipShape(BitStream4R &bs)
|
2020-06-27 22:46:26 +02:00
|
|
|
{
|
2020-09-18 20:56:00 +02:00
|
|
|
quint32 v1, v2, v2b;
|
|
|
|
|
2022-02-05 12:37:14 +01:00
|
|
|
if (!bs.readVUint32SM(v1, v2, v2b))
|
2020-09-18 20:56:00 +02:00
|
|
|
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;
|
|
|
|
|
2020-06-27 22:46:26 +02:00
|
|
|
for (int i = 0; i < cnts.size(); i++) {
|
|
|
|
if (cnts.at(i) & mask) {
|
2020-09-18 20:56:00 +02:00
|
|
|
if (!skipShape(bs))
|
2020-06-27 22:46:26 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-09-18 20:56:00 +02:00
|
|
|
static bool seekToLevel(BitStream4R &bs, quint8 level)
|
2020-06-27 22:46:26 +02:00
|
|
|
{
|
|
|
|
quint32 v1, v2, v2b;
|
|
|
|
|
|
|
|
for (quint8 i = 1; i < level; ) {
|
2022-02-05 12:37:14 +01:00
|
|
|
if (!bs.readVUint32SM(v1, v2, v2b))
|
2020-06-27 22:46:26 +02:00
|
|
|
return false;
|
|
|
|
if (!bs.skip(v1))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (v2 & 2)
|
|
|
|
return false;
|
|
|
|
if (v2 & 1)
|
|
|
|
i++;
|
|
|
|
};
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-09-18 20:56:00 +02:00
|
|
|
static bool seekToLine(BitStream4R &bs, quint8 line)
|
2020-06-27 22:46:26 +02:00
|
|
|
{
|
|
|
|
quint32 v1, v2, v2b;
|
|
|
|
|
|
|
|
for (quint8 i = 0; i < line; i++) {
|
2022-02-05 12:37:14 +01:00
|
|
|
if (!bs.readVUint32SM(v1, v2, v2b))
|
2020-06-27 22:46:26 +02:00
|
|
|
return false;
|
|
|
|
if (!bs.skip(v1))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (v2 & 2)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-03-19 13:25:47 +01:00
|
|
|
static bool readNodeGeometry(const NODFile *nod, SubFile::Handle &nodHdl,
|
|
|
|
NODFile::AdjacencyInfo &adj, quint16 cnt, MapData::Poly &poly)
|
|
|
|
{
|
|
|
|
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(const 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool NETFile::readLine(BitStream4R &bs, const SubDiv *subdiv,
|
|
|
|
MapData::Poly &poly) const
|
2020-09-18 20:56:00 +02:00
|
|
|
{
|
|
|
|
quint32 v1, v2, v2b;
|
2022-02-05 12:37:14 +01:00
|
|
|
if (!bs.readVUint32SM(v1, v2, v2b))
|
2020-09-18 20:56:00 +02:00
|
|
|
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()));
|
|
|
|
|
2022-03-19 13:25:47 +01:00
|
|
|
HuffmanDeltaStreamR stream(bs, *_tp);
|
2020-09-18 20:56:00 +02:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2022-03-19 13:25:47 +01:00
|
|
|
bool NETFile::readShape(const NODFile *nod, SubFile::Handle &nodHdl,
|
|
|
|
NODFile::AdjacencyInfo &adj, BitStream4R &bs, const SubDiv *subdiv,
|
|
|
|
quint32 shift, quint16 cnt, bool check, MapData::Poly &poly) const
|
2020-09-18 20:56:00 +02:00
|
|
|
{
|
|
|
|
quint32 v1, v2, v2b;
|
2022-02-05 12:37:14 +01:00
|
|
|
if (!bs.readVUint32SM(v1, v2, v2b))
|
2020-09-18 20:56:00 +02:00
|
|
|
return false;
|
|
|
|
BitStream4R::State state;
|
|
|
|
bs.save(state);
|
|
|
|
bs.resize(v1);
|
|
|
|
|
|
|
|
quint32 flags;
|
|
|
|
if (!bs.read(8, flags))
|
|
|
|
return false;
|
|
|
|
flags |= (v2 << 8);
|
|
|
|
|
2021-08-25 00:34:31 +02:00
|
|
|
bool hasAdjustBit = flags & (1 << (v2b + 7));
|
2020-09-18 20:56:00 +02:00
|
|
|
bool startWithStream = flags & (1 << (v2b + 6));
|
2021-08-25 00:34:31 +02:00
|
|
|
bool useEosBit = flags & (1 << (v2b + 5));
|
2020-09-18 20:56:00 +02:00
|
|
|
|
2022-03-19 13:25:47 +01:00
|
|
|
HuffmanDeltaStreamR stream(bs, *_tp);
|
2021-11-04 23:01:33 +01:00
|
|
|
if (!stream.init(flags, v2b + 5))
|
2021-10-03 11:08:26 +02:00
|
|
|
return false;
|
2020-09-18 20:56:00 +02:00
|
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2020-09-29 18:53:49 +02:00
|
|
|
while (!adj.eog) {
|
2020-09-18 20:56:00 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-03 11:08:26 +02:00
|
|
|
|
2020-09-18 20:56:00 +02:00
|
|
|
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;
|
|
|
|
|
2021-08-25 00:34:31 +02:00
|
|
|
if (hasAdjustBit && !stream.read(1, adjustBit))
|
2020-09-18 20:56:00 +02:00
|
|
|
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;
|
|
|
|
|
2020-09-29 18:53:49 +02:00
|
|
|
if (adj.eog)
|
2020-09-18 20:56:00 +02:00
|
|
|
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)
|
2022-02-05 12:37:14 +01:00
|
|
|
&& bs.readVUint32SM(v1, v2, v2b)))
|
2020-09-18 20:56:00 +02:00
|
|
|
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;
|
2020-09-29 18:53:49 +02:00
|
|
|
} while (!adj.eog && nodes < cnt);
|
2020-09-18 20:56:00 +02:00
|
|
|
|
|
|
|
if (nodes == cnt)
|
|
|
|
break;
|
|
|
|
|
|
|
|
steps = 0;
|
|
|
|
stepsCnt = 0;
|
|
|
|
eos = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-03-19 13:25:47 +01:00
|
|
|
bool NETFile::linkLabel(Handle &hdl, quint32 offset,
|
2020-11-10 00:58:19 +01:00
|
|
|
const LBLFile *lbl, Handle &lblHdl, Label &label) const
|
2020-09-18 20:56:00 +02:00
|
|
|
{
|
|
|
|
if (!seek(hdl, offset))
|
|
|
|
return false;
|
2022-03-25 19:28:32 +01:00
|
|
|
BitStream1 bs(*this, hdl, _links.size - (offset - _links.offset));
|
2020-09-18 20:56:00 +02:00
|
|
|
|
2020-10-22 20:32:12 +02:00
|
|
|
quint32 flags, labelPtr;
|
2020-09-18 20:56:00 +02:00
|
|
|
if (!bs.read(8, flags))
|
|
|
|
return false;
|
2020-10-22 20:32:12 +02:00
|
|
|
if (!(flags & 1))
|
|
|
|
return true;
|
2020-09-18 20:56:00 +02:00
|
|
|
|
2020-10-22 20:32:12 +02:00
|
|
|
if (!bs.readUInt24(labelPtr))
|
|
|
|
return false;
|
2020-11-10 00:58:19 +01:00
|
|
|
if (labelPtr & 0x3FFFFF)
|
|
|
|
label = lbl->label(lblHdl, labelPtr & 0x3FFFFF);
|
2020-09-18 20:56:00 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2020-06-27 22:46:26 +02:00
|
|
|
|
2020-11-10 00:58:19 +01:00
|
|
|
bool NETFile::load(Handle &hdl, const RGNFile *rgn, Handle &rgnHdl)
|
2019-05-10 18:56:19 +02:00
|
|
|
{
|
2020-01-21 21:50:13 +01:00
|
|
|
quint16 hdrLen;
|
2019-05-10 18:56:19 +02:00
|
|
|
|
2020-01-21 21:50:13 +01:00
|
|
|
if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen)
|
2022-03-25 19:28:32 +01:00
|
|
|
&& seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _base.offset)
|
|
|
|
&& readUInt32(hdl, _base.size) && readByte(hdl, &_netShift)))
|
2019-05-10 18:56:19 +02:00
|
|
|
return false;
|
|
|
|
|
2021-03-19 20:09:11 +01:00
|
|
|
if (hdrLen >= 0x4C) {
|
2020-06-27 22:46:26 +02:00
|
|
|
quint32 info;
|
|
|
|
if (!(seek(hdl, _gmpOffset + 0x37) && readUInt32(hdl, info)))
|
|
|
|
return false;
|
2022-03-25 19:28:32 +01:00
|
|
|
if (!(seek(hdl, _gmpOffset + 0x43) && readUInt32(hdl, _links.offset)
|
|
|
|
&& readUInt32(hdl, _links.size) && readByte(hdl, &_linksShift)))
|
2020-06-27 22:46:26 +02:00
|
|
|
return false;
|
|
|
|
|
2021-03-19 20:09:11 +01:00
|
|
|
quint8 tableId = ((info >> 2) & 0x0F);
|
2022-03-25 19:28:32 +01:00
|
|
|
if (_links.size && (!rgn->huffmanTable() || rgn->huffmanTable()->id()
|
2020-11-10 00:58:19 +01:00
|
|
|
!= tableId)) {
|
|
|
|
_huffmanTable = new HuffmanTable(tableId);
|
|
|
|
if (!_huffmanTable->load(rgn, rgnHdl))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
_tp = _huffmanTable ? _huffmanTable : rgn->huffmanTable();
|
|
|
|
}
|
2019-05-10 18:56:19 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-11-10 00:58:19 +01:00
|
|
|
void NETFile::clear()
|
|
|
|
{
|
|
|
|
delete _huffmanTable;
|
|
|
|
_huffmanTable = 0;
|
|
|
|
}
|
|
|
|
|
2022-03-19 13:25:47 +01:00
|
|
|
NETFile::~NETFile()
|
|
|
|
{
|
|
|
|
delete _huffmanTable;
|
|
|
|
}
|
|
|
|
|
2020-09-18 20:56:00 +02:00
|
|
|
bool NETFile::link(const SubDiv *subdiv, quint32 shift, Handle &hdl,
|
2021-07-21 02:06:35 +02:00
|
|
|
const NODFile *nod, Handle &nodHdl2, Handle &nodHdl, const LBLFile *lbl,
|
|
|
|
Handle &lblHdl, const NODFile::BlockInfo &blockInfo, quint8 linkId,
|
|
|
|
quint8 lineId, QList<MapData::Poly> *lines) const
|
2020-06-27 22:46:26 +02:00
|
|
|
{
|
2020-11-10 00:58:19 +01:00
|
|
|
MapData::Poly poly;
|
2020-09-18 20:56:00 +02:00
|
|
|
if (!nod->linkType(nodHdl, blockInfo, linkId, poly.type))
|
2020-06-27 22:46:26 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
NODFile::LinkInfo linkInfo;
|
|
|
|
if (!nod->linkInfo(nodHdl, blockInfo, linkId, linkInfo))
|
|
|
|
return false;
|
|
|
|
|
2022-03-25 19:28:32 +01:00
|
|
|
quint32 linkOffset = _links.offset + (linkInfo.linkOffset << _linksShift);
|
|
|
|
if (linkOffset > _links.offset + _links.size)
|
2020-09-18 20:56:00 +02:00
|
|
|
return false;
|
|
|
|
if (!seek(hdl, linkOffset))
|
|
|
|
return false;
|
2022-03-25 19:28:32 +01:00
|
|
|
BitStream4R bs(*this, hdl, linkOffset - _links.offset);
|
2020-09-18 20:56:00 +02:00
|
|
|
QVector<quint16> ca;
|
|
|
|
quint16 mask = 0;
|
|
|
|
quint32 size;
|
2020-06-27 22:46:26 +02:00
|
|
|
|
2021-08-23 22:27:36 +02:00
|
|
|
bool firstIsShape = (linkInfo.flags >> 10) & 1;
|
|
|
|
bool singleTopology = (linkInfo.flags >> 9) & 1;
|
|
|
|
bool hasLevels = (linkInfo.flags >> 11) & 1;
|
2020-06-27 22:46:26 +02:00
|
|
|
|
2021-07-18 22:32:49 +02:00
|
|
|
if (!singleTopology || hasLevels) {
|
2020-06-27 22:46:26 +02:00
|
|
|
if (!bs.readVUInt32(size))
|
|
|
|
return false;
|
2020-09-18 20:56:00 +02:00
|
|
|
}
|
2021-07-18 22:32:49 +02:00
|
|
|
if (!singleTopology) {
|
2020-09-18 20:56:00 +02:00
|
|
|
if (!readAdjCounts(bs, ca, mask))
|
|
|
|
return false;
|
|
|
|
}
|
2020-06-27 22:46:26 +02:00
|
|
|
|
2020-09-18 20:56:00 +02:00
|
|
|
if (!subdiv->level()) {
|
2021-07-21 02:06:35 +02:00
|
|
|
NODFile::AdjacencyInfo adj(nodHdl2, blockInfo, linkId, linkInfo);
|
2020-09-18 20:56:00 +02:00
|
|
|
|
2021-07-18 22:32:49 +02:00
|
|
|
if (singleTopology) {
|
|
|
|
if (firstIsShape) {
|
2022-03-19 13:25:47 +01:00
|
|
|
if (!readShape(nod, nodHdl, adj, bs, subdiv, shift, 0xFFFF,
|
|
|
|
false, poly))
|
2020-09-18 20:56:00 +02:00
|
|
|
return false;
|
|
|
|
} else {
|
2022-03-19 13:25:47 +01:00
|
|
|
if (!readNodeGeometry(nod, nodHdl, adj, 0xFFFF, poly))
|
2020-09-18 20:56:00 +02:00
|
|
|
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;
|
2021-07-18 22:32:49 +02:00
|
|
|
bool shape = (i > 0) ? ca.at(i-1) & mask : firstIsShape;
|
2020-09-18 20:56:00 +02:00
|
|
|
if (i == lineId) {
|
|
|
|
if (shape) {
|
|
|
|
bool check = (i < ca.size()) ? (ca.at(i) & mask) : false;
|
2022-03-19 13:25:47 +01:00
|
|
|
if (!readShape(nod, nodHdl, adj, bs, subdiv, shift,
|
|
|
|
step, check, poly))
|
2020-09-18 20:56:00 +02:00
|
|
|
return false;
|
|
|
|
} else {
|
2022-03-19 13:25:47 +01:00
|
|
|
if (!readNodeGeometry(nod, nodHdl, adj, step, poly))
|
2020-09-18 20:56:00 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (shape && !skipShape(bs))
|
|
|
|
return false;
|
|
|
|
if (!skipNodes(nod, nodHdl, adj, step))
|
|
|
|
return false;
|
|
|
|
}
|
2020-06-27 22:46:26 +02:00
|
|
|
}
|
2020-09-18 20:56:00 +02:00
|
|
|
} else {
|
2021-07-18 22:32:49 +02:00
|
|
|
Q_ASSERT(hasLevels);
|
|
|
|
|
|
|
|
if (!skipAdjShapes(bs, ca, mask, firstIsShape))
|
2020-06-27 22:46:26 +02:00
|
|
|
return false;
|
2020-09-18 20:56:00 +02:00
|
|
|
|
2020-06-27 22:46:26 +02:00
|
|
|
if (!seekToLevel(bs, subdiv->level()))
|
|
|
|
return false;
|
|
|
|
if (!seekToLine(bs, lineId))
|
|
|
|
return false;
|
2022-03-19 13:25:47 +01:00
|
|
|
if (!readLine(bs, subdiv, poly))
|
2020-06-27 22:46:26 +02:00
|
|
|
return false;
|
2020-09-18 20:56:00 +02:00
|
|
|
}
|
2020-06-27 22:46:26 +02:00
|
|
|
|
2020-10-22 20:32:12 +02:00
|
|
|
if (lbl)
|
2022-03-19 13:25:47 +01:00
|
|
|
linkLabel(hdl, linkOffset, lbl, lblHdl, poly.label);
|
2020-06-27 22:46:26 +02:00
|
|
|
|
2020-09-18 20:56:00 +02:00
|
|
|
lines->append(poly);
|
2020-06-27 22:46:26 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-11-10 00:58:19 +01:00
|
|
|
bool NETFile::lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset) const
|
2019-05-10 18:56:19 +02:00
|
|
|
{
|
2022-03-25 19:28:32 +01:00
|
|
|
if (!(seek(hdl, _base.offset + (netOffset << _netShift))
|
2019-05-10 18:56:19 +02:00
|
|
|
&& readUInt24(hdl, lblOffset)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
lblOffset &= 0x3FFFFF;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|