Properly mark one-way streets in data from NET links
[GPXSee.git] / src / map / IMG / netfile.cpp
blob9d5a603af1fc529d999e6046f593ccbc18ff5793
1 #include "bitstream.h"
2 #include "huffmanstream.h"
3 #include "subdiv.h"
4 #include "nodfile.h"
5 #include "lblfile.h"
6 #include "rgnfile.h"
7 #include "netfile.h"
9 using namespace Garmin;
10 using namespace IMG;
12 static bool readAdjCounts(BitStream4R &bs, QVector<quint16> &cnts, quint16 &mask)
14 quint32 val, cnt, bits;
15 if (!bs.read(4, val))
16 return false;
18 cnt = ((val >> 2) & 3) + 2;
19 bits = ((val * 2) & 6) + 4;
20 mask = 1<<(3 + ((val * 2) & 6));
21 if (cnt == 5) {
22 if (!bs.read(8, cnt))
23 return false;
26 if (cnt < 2)
27 return false;
28 cnts.resize(cnt - 1);
29 for (int i = 0; i < cnts.size(); i++)
30 if (!bs.read(bits, cnts[i]))
31 return false;
33 return true;
36 static bool skipShape(BitStream4R &bs)
38 quint32 v1, v2, v2b;
40 if (!bs.readVUint32SM(v1, v2, v2b))
41 return false;
43 return bs.skip(v1);
46 static bool skipAdjShapes(BitStream4R &bs, const QVector<quint16> &cnts,
47 quint16 mask, bool firstIsShape)
49 if (firstIsShape && !skipShape(bs))
50 return false;
52 for (int i = 0; i < cnts.size(); i++) {
53 if (cnts.at(i) & mask) {
54 if (!skipShape(bs))
55 return false;
59 return true;
62 static bool seekToLevel(BitStream4R &bs, quint8 level)
64 quint32 v1, v2, v2b;
66 for (quint8 i = 1; i < level; ) {
67 if (!bs.readVUint32SM(v1, v2, v2b))
68 return false;
69 if (!bs.skip(v1))
70 return false;
72 if (v2 & 2)
73 return false;
74 if (v2 & 1)
75 i++;
78 return true;
81 static bool seekToLine(BitStream4R &bs, quint8 line)
83 quint32 v1, v2, v2b;
85 for (quint8 i = 0; i < line; i++) {
86 if (!bs.readVUint32SM(v1, v2, v2b))
87 return false;
88 if (!bs.skip(v1))
89 return false;
91 if (v2 & 2)
92 return false;
95 return true;
98 static bool readNodeGeometry(const NODFile *nod, SubFile::Handle &nodHdl,
99 NODFile::AdjacencyInfo &adj, quint16 cnt, MapData::Poly &poly)
101 for (int i = 0; i <= cnt; i++) {
102 int ret = nod->nextNode(nodHdl, adj);
103 if (ret < 0)
104 return false;
105 else if (ret > 0)
106 return (cnt == 0xFFFF);
108 Coordinates c(toWGS32(adj.nodeInfo.pos.x()),
109 toWGS32(adj.nodeInfo.pos.y()));
110 poly.points.append(QPointF(c.lon(), c.lat()));
111 poly.boundingRect = poly.boundingRect.united(c);
114 return true;
117 static bool skipNodes(const NODFile *nod, SubFile::Handle &nodHdl,
118 NODFile::AdjacencyInfo &adj, int cnt)
120 for (int i = 0; i < cnt; i++)
121 if (nod->nextNode(nodHdl, adj))
122 return false;
124 return true;
128 bool NETFile::readLine(BitStream4R &bs, const SubDiv *subdiv,
129 MapData::Poly &poly) const
131 quint32 v1, v2, v2b;
132 if (!bs.readVUint32SM(v1, v2, v2b))
133 return false;
134 bs.resize(v1);
136 quint32 lon, lat;
137 if (!(bs.read(0x12 - v2b, lon) && bs.read(16, lat)))
138 return false;
139 if (2 < v2b)
140 lon |= (v2 >> 2) << (0x12U - v2b);
142 QPoint pos = QPoint(LS(subdiv->lon(), 8) + LS((qint16)lon, 32-subdiv->bits()),
143 LS(subdiv->lat(), 8) + LS((qint16)lat, 32-subdiv->bits()));
144 Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
146 poly.boundingRect = RectC(c, c);
147 poly.points.append(QPointF(c.lon(), c.lat()));
149 HuffmanDeltaStreamR stream(bs, *_tp);
150 if (!stream.init())
151 return false;
152 qint32 lonDelta, latDelta;
154 while (stream.readNext(lonDelta, latDelta)) {
155 if (!(lonDelta | latDelta))
156 break;
158 pos.rx() += LS(lonDelta, 32-subdiv->bits());
159 pos.ry() += LS(latDelta, 32-subdiv->bits());
161 Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
162 poly.points.append(QPointF(c.lon(), c.lat()));
163 poly.boundingRect = poly.boundingRect.united(c);
166 return stream.atEnd();
169 bool NETFile::readShape(const NODFile *nod, SubFile::Handle &nodHdl,
170 NODFile::AdjacencyInfo &adj, BitStream4R &bs, const SubDiv *subdiv,
171 quint32 shift, quint16 cnt, bool check, MapData::Poly &poly) const
173 quint32 v1, v2, v2b;
174 if (!bs.readVUint32SM(v1, v2, v2b))
175 return false;
176 BitStream4R::State state;
177 bs.save(state);
178 bs.resize(v1);
180 quint32 flags;
181 if (!bs.read(8, flags))
182 return false;
183 flags |= (v2 << 8);
185 bool hasAdjustBit = flags & (1 << (v2b + 7));
186 bool startWithStream = flags & (1 << (v2b + 6));
187 bool useEosBit = flags & (1 << (v2b + 5));
189 HuffmanDeltaStreamR stream(bs, *_tp);
190 if (!stream.init(flags, v2b + 5))
191 return false;
194 if (nod->nextNode(nodHdl, adj))
195 return false;
196 QPoint pos(adj.nodeInfo.pos);
197 quint16 nodes = 0;
199 if (!startWithStream) {
200 Coordinates c(toWGS32(adj.nodeInfo.pos.x()),
201 toWGS32(adj.nodeInfo.pos.y()));
202 poly.points.append(QPointF(c.lon(), c.lat()));
203 poly.boundingRect = poly.boundingRect.united(c);
205 while (!adj.eog) {
206 int ret = nod->nextNode(nodHdl, adj);
207 if (ret < 0)
208 return false;
209 else if (ret > 0)
210 break;
211 nodes++;
213 c = Coordinates(toWGS32(adj.nodeInfo.pos.x()),
214 toWGS32(adj.nodeInfo.pos.y()));
215 poly.points.append(QPointF(c.lon(), c.lat()));
216 poly.boundingRect = poly.boundingRect.united(c);
217 pos = adj.nodeInfo.pos;
222 qint32 lonDelta, latDelta;
223 QVector<QPoint> deltas;
224 quint32 adjustBit = 0;
225 quint32 stepsCnt = 0;
226 quint32 steps = 0;
227 quint32 eos = 0;
229 while (true) {
230 if ((stepsCnt == steps) && !useEosBit) {
231 if (!stream.readSymbol(steps))
232 break;
233 if (!steps)
234 break;
237 if (!stream.readNext(lonDelta, latDelta))
238 break;
239 if (hasAdjustBit && !stream.read(1, adjustBit))
240 return false;
242 if (!(lonDelta | latDelta) && !startWithStream && !hasAdjustBit)
243 break;
245 stepsCnt++;
247 if (useEosBit) {
248 if (!stream.read(1, eos))
249 return false;
250 } else {
251 if (steps == stepsCnt)
252 eos = 1;
255 if (!startWithStream) {
256 pos.rx() += LS(lonDelta, 32-subdiv->bits()-shift);
257 pos.ry() += LS(latDelta, 32-subdiv->bits()-shift);
259 Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
260 poly.points.append(QPointF(c.lon(), c.lat()));
261 poly.boundingRect = poly.boundingRect.united(c);
262 } else {
263 deltas.append(QPoint(lonDelta, latDelta));
264 poly.points.append(QPointF());
267 if (startWithStream && eos) {
268 for (int i = deltas.size() - 1, j = 0; i >= 0; i--, j++) {
269 pos.rx() -= LS(deltas.at(i).x(), 32-subdiv->bits()-shift);
270 pos.ry() -= LS(deltas.at(i).y(), 32-subdiv->bits()-shift);
272 Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
273 poly.points[poly.points.size() - 1 - j] = QPointF(c.lon(), c.lat());
274 poly.boundingRect = poly.boundingRect.united(c);
277 pos = adj.nodeInfo.pos;
278 Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
279 poly.points.append(QPointF(c.lon(), c.lat()));
280 poly.boundingRect = poly.boundingRect.united(c);
282 stepsCnt = 0;
283 steps = 0;
284 startWithStream = false;
286 if (adj.eog)
287 eos = 0;
290 if (eos) {
291 if (nodes >= cnt)
292 break;
294 do {
295 int ret = nod->nextNode(nodHdl, adj);
296 if (ret < 0)
297 return false;
298 else if (ret > 0)
299 break;
300 nodes++;
302 if (check && nodes == cnt) {
303 if (!(bs.restore(state) && bs.skip(v1)
304 && bs.readVUint32SM(v1, v2, v2b)))
305 return false;
306 if (5 < v2b)
307 v2 >>= v2b - 2;
308 if (v2 & 1)
309 break;
312 Coordinates c(toWGS32(adj.nodeInfo.pos.x()),
313 toWGS32(adj.nodeInfo.pos.y()));
314 poly.points.append(QPointF(c.lon(), c.lat()));
315 poly.boundingRect = poly.boundingRect.united(c);
316 pos = adj.nodeInfo.pos;
317 } while (!adj.eog && nodes < cnt);
319 if (nodes == cnt)
320 break;
322 steps = 0;
323 stepsCnt = 0;
324 eos = 0;
328 return true;
331 bool NETFile::linkLabel(Handle &hdl, quint32 offset,
332 const LBLFile *lbl, Handle &lblHdl, Label &label) const
334 if (!seek(hdl, offset))
335 return false;
336 BitStream1 bs(*this, hdl, _links.size - (offset - _links.offset));
338 quint32 flags, labelPtr;
339 if (!bs.read(8, flags))
340 return false;
341 if (!(flags & 1))
342 return true;
344 if (!bs.readUInt24(labelPtr))
345 return false;
346 if (labelPtr & 0x3FFFFF)
347 label = lbl->label(lblHdl, labelPtr & 0x3FFFFF);
349 return true;
352 bool NETFile::load(Handle &hdl, const RGNFile *rgn, Handle &rgnHdl)
354 quint16 hdrLen;
356 if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen)
357 && seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _base.offset)
358 && readUInt32(hdl, _base.size) && readByte(hdl, &_netShift)))
359 return false;
361 if (hdrLen >= 0x4C) {
362 quint32 info;
363 if (!(seek(hdl, _gmpOffset + 0x37) && readUInt32(hdl, info)))
364 return false;
365 if (!(seek(hdl, _gmpOffset + 0x43) && readUInt32(hdl, _links.offset)
366 && readUInt32(hdl, _links.size) && readByte(hdl, &_linksShift)))
367 return false;
369 quint8 tableId = ((info >> 2) & 0x0F);
370 if (_links.size && (!rgn->huffmanTable() || rgn->huffmanTable()->id()
371 != tableId)) {
372 _huffmanTable = new HuffmanTable(tableId);
373 if (!_huffmanTable->load(rgn, rgnHdl))
374 return false;
377 _tp = _huffmanTable ? _huffmanTable : rgn->huffmanTable();
380 return true;
383 void NETFile::clear()
385 delete _huffmanTable;
386 _huffmanTable = 0;
389 NETFile::~NETFile()
391 delete _huffmanTable;
394 bool NETFile::link(const SubDiv *subdiv, quint32 shift, Handle &hdl,
395 const NODFile *nod, Handle &nodHdl2, Handle &nodHdl, const LBLFile *lbl,
396 Handle &lblHdl, const NODFile::BlockInfo &blockInfo, quint8 linkId,
397 quint8 lineId, QList<MapData::Poly> *lines) const
399 MapData::Poly poly;
400 if (!nod->linkType(nodHdl, blockInfo, linkId, poly.type))
401 return false;
403 NODFile::LinkInfo linkInfo;
404 if (!nod->linkInfo(nodHdl, blockInfo, linkId, linkInfo))
405 return false;
407 quint32 linkOffset = _links.offset + (linkInfo.linkOffset << _linksShift);
408 if (linkOffset > _links.offset + _links.size)
409 return false;
410 if (!seek(hdl, linkOffset))
411 return false;
412 BitStream4R bs(*this, hdl, linkOffset - _links.offset);
413 QVector<quint16> ca;
414 quint16 mask = 0;
415 quint32 size;
417 bool firstIsShape = (linkInfo.flags >> 10) & 1;
418 bool singleTopology = (linkInfo.flags >> 9) & 1;
419 bool hasLevels = (linkInfo.flags >> 11) & 1;
421 if (!singleTopology || hasLevels) {
422 if (!bs.readVUInt32(size))
423 return false;
425 if (!singleTopology) {
426 if (!readAdjCounts(bs, ca, mask))
427 return false;
430 if (!subdiv->level()) {
431 NODFile::AdjacencyInfo adj(nodHdl2, blockInfo, linkId, linkInfo);
433 if (singleTopology) {
434 if (firstIsShape) {
435 if (!readShape(nod, nodHdl, adj, bs, subdiv, shift, 0xFFFF,
436 false, poly))
437 return false;
438 } else {
439 if (!readNodeGeometry(nod, nodHdl, adj, 0xFFFF, poly))
440 return false;
442 } else {
443 quint16 mask2 = mask + 0xffff;
444 for (int i = 0; i <= ca.size(); i++) {
445 quint16 step = (i < ca.size()) ? ca.at(i) & mask2 : 0xFFFF;
446 bool shape = (i > 0) ? ca.at(i-1) & mask : firstIsShape;
447 if (i == lineId) {
448 if (shape) {
449 bool check = (i < ca.size()) ? (ca.at(i) & mask) : false;
450 if (!readShape(nod, nodHdl, adj, bs, subdiv, shift,
451 step, check, poly))
452 return false;
453 } else {
454 if (!readNodeGeometry(nod, nodHdl, adj, step, poly))
455 return false;
457 break;
460 if (shape && !skipShape(bs))
461 return false;
462 if (!skipNodes(nod, nodHdl, adj, step))
463 return false;
466 } else {
467 Q_ASSERT(hasLevels);
469 if (!skipAdjShapes(bs, ca, mask, firstIsShape))
470 return false;
472 if (!seekToLevel(bs, subdiv->level()))
473 return false;
474 if (!seekToLine(bs, lineId))
475 return false;
476 if (!readLine(bs, subdiv, poly))
477 return false;
480 if (lbl)
481 linkLabel(hdl, linkOffset, lbl, lblHdl, poly.label);
482 if ((linkInfo.flags >> 3) & 1)
483 poly.oneway = true;
485 lines->append(poly);
487 return true;
490 bool NETFile::lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset) const
492 if (!(seek(hdl, _base.offset + (netOffset << _netShift))
493 && readUInt24(hdl, lblOffset)))
494 return false;
496 lblOffset &= 0x3FFFFF;
498 return true;