1 /**********************************************************************************************
2 Copyright (C) 2009 Oliver Eichler <oliver.eichler@gmx.de>
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17 NOTE: this code is based on the opensource typ file generator at
18 http://ati.land.cz/gps/typdecomp/editor.cgi
19
20 **********************************************************************************************/
21
22 #include "CMainWindow.h"
23 #include "map/garmin/CGarminTyp.h"
24 #include "units/IUnit.h"
25 #include <QMessageBox>
26 #include <QtCore>
27
28 #include <stdio.h>
29 #include <string.h>
30
31 #undef DBG
32
33
decode(const QByteArray & array,QMap<quint32,polygon_property> & polygons,QMap<quint32,polyline_property> & polylines,QList<quint32> & drawOrder,QMap<quint32,point_property> & points)34 bool CGarminTyp::decode(const QByteArray& array, QMap<quint32, polygon_property>& polygons, QMap<quint32, polyline_property>& polylines, QList<quint32>& drawOrder, QMap<quint32, point_property>& points)
35 {
36 QDataStream in(array);
37 in.setVersion(QDataStream::Qt_4_5);
38 in.setByteOrder( QDataStream::LittleEndian);
39
40 /* Read typ file descriptor */
41 quint16 descriptor;
42 in >> descriptor;
43
44 qDebug() << "descriptor" << hex << descriptor;
45
46 if(!parseHeader(in))
47 {
48 return false;
49 }
50
51 if(!parseDrawOrder(in, drawOrder))
52 {
53 return false;
54 }
55
56 if(!parsePolygon(in, polygons))
57 {
58 return false;
59 }
60
61 if(!parsePolyline(in, polylines))
62 {
63 return false;
64 }
65
66 if(!parsePoint(in, points))
67 {
68 return false;
69 }
70
71 return true;
72 }
73
getCodec(quint16 codepage)74 QTextCodec* CGarminTyp::getCodec(quint16 codepage)
75 {
76 QTextCodec* codec = QTextCodec::codecForName(QString("CP%1").arg(codepage).toLatin1());
77 if(codepage == 65001)
78 {
79 codec = QTextCodec::codecForName("UTF-8");
80 }
81
82 return codec;
83 }
84
85
parseHeader(QDataStream & in)86 bool CGarminTyp::parseHeader(QDataStream& in)
87 {
88 int i;
89 QString garmintyp;
90 quint8 byte;
91
92 for(i = 0; i < 10; ++i)
93 {
94 in >> byte;
95 garmintyp.append(byte);
96 }
97 garmintyp.append(0);
98 if(garmintyp != "GARMIN TYP")
99 {
100 qDebug() << "CMapTDB::readTYP() not a known typ file";
101 return false;
102 }
103
104 /* reading typ creation date string */
105
106 in.device()->seek(0x0c);
107 in >> version >> year >> month >> day >> hour >> minutes >> seconds >> codepage;
108 month -= 1; /* Month are like Microsoft starting 0 ? */
109 year += 1900;
110
111 /* Reading points / lines / polygons struct */
112 in >> sectPoints.dataOffset >> sectPoints.dataLength;
113 in >> sectPolylines.dataOffset >> sectPolylines.dataLength;
114 in >> sectPolygons.dataOffset >> sectPolygons.dataLength;
115
116 in >> pid >> fid;
117
118 /* Read Array datas */
119 in >> sectPoints.arrayOffset >> sectPoints.arrayModulo >> sectPoints.arraySize;
120 in >> sectPolylines.arrayOffset >> sectPolylines.arrayModulo >> sectPolylines.arraySize;
121 in >> sectPolygons.arrayOffset >> sectPolygons.arrayModulo >> sectPolygons.arraySize;
122 in >> sectOrder.arrayOffset >> sectOrder.arrayModulo >> sectOrder.arraySize;
123
124 #ifdef DBG
125 qDebug() << "Version:" << version << "Codepage:" << codepage;
126 qDebug() << "PID" << hex << pid << "FID" << hex << fid;
127 qDebug() << "Points doff/dlen/aoff/amod/asize:" << hex << "\t" << sectPoints.dataOffset << "\t" << sectPoints.dataLength << "\t" << sectPoints.arrayOffset << "\t" << sectPoints.arrayModulo << "\t" << sectPoints.arrayOffset;
128 qDebug() << "Polylines doff/dlen/aoff/amod/asize:" << hex << "\t" << sectPolylines.dataOffset << "\t" << sectPolylines.dataLength << "\t" << sectPolylines.arrayOffset << "\t" << sectPolylines.arrayModulo << "\t" << sectPolylines.arrayOffset;
129 qDebug() << "Polygons doff/dlen/aoff/amod/asize:" << hex << "\t" << sectPolygons.dataOffset << "\t" << sectPolygons.dataLength << "\t" << sectPolygons.arrayOffset << "\t" << sectPolygons.arrayModulo << "\t" << sectPolygons.arrayOffset;
130 qDebug() << "Order doff/dlen/aoff/amod/asize:" << hex << "\t" << sectOrder.dataOffset << "\t" << sectOrder.dataLength << "\t" << sectOrder.arrayOffset << "\t" << sectOrder.arrayModulo << "\t" << sectOrder.arrayOffset;
131 #endif
132
133 return true;
134 }
135
136
parseDrawOrder(QDataStream & in,QList<quint32> & drawOrder)137 bool CGarminTyp::parseDrawOrder(QDataStream& in, QList<quint32>& drawOrder)
138 {
139 if(sectOrder.arraySize == 0)
140 {
141 return true;
142 }
143
144 if(sectOrder.arrayModulo != 5)
145 {
146 return false;
147 }
148
149 if((sectOrder.arraySize % sectOrder.arrayModulo) != 0)
150 {
151 return true;
152 }
153
154 in.device()->seek(sectOrder.arrayOffset);
155
156 int i, n;
157 quint8 typ;
158 quint32 subtyp;
159
160 int count = 1;
161
162 const int N = sectOrder.arraySize / sectOrder.arrayModulo;
163
164 for (i = 0; i < N; i++)
165 {
166 in >> typ >> subtyp;
167 // qDebug() << hex << typ << subtyp;
168 if (typ == 0)
169 {
170 count++;
171 }
172 else if(subtyp == 0)
173 {
174 #ifdef DBG
175 qDebug() << QString("Type 0x%1 is priority %2").arg(typ, 0, 16).arg(count);
176 #endif
177 int idx = drawOrder.indexOf(typ);
178 if(idx != NOIDX)
179 {
180 drawOrder.move(idx, 0);
181 }
182 }
183 else
184 {
185 quint32 exttyp = 0x010000 | (typ << 8);
186 quint32 mask = 0x1;
187
188 for(n = 0; n < 0x20; ++n)
189 {
190 if(subtyp & mask)
191 {
192 drawOrder.push_front(exttyp | n);
193 #ifdef DBG
194 qDebug() << QString("Type 0x%1 is priority %2").arg(exttyp | n, 0, 16).arg(count);
195 #endif
196 }
197 mask = mask << 1;
198 }
199 }
200 }
201
202
203 #ifdef DBG
204 for(unsigned i = 0; i < drawOrder.size(); ++i)
205 {
206 if(i && i % 16 == 0)
207 {
208 printf(" \n");
209 }
210 printf("%06X ", drawOrder[i]);
211 }
212
213
214 printf(" \n");
215 #endif
216
217 return true;
218 }
219
220
parsePolygon(QDataStream & in,QMap<quint32,polygon_property> & polygons)221 bool CGarminTyp::parsePolygon(QDataStream& in, QMap<quint32, polygon_property>& polygons)
222 {
223 bool tainted = false;
224
225 if(sectPolygons.arraySize == 0)
226 {
227 return true;
228 }
229
230 if(!sectPolygons.arrayModulo || ((sectPolygons.arraySize % sectPolygons.arrayModulo) != 0))
231 {
232 return true;
233 }
234
235 QTextCodec* codec = getCodec(codepage);
236
237 const int N = sectPolygons.arraySize / sectPolygons.arrayModulo;
238 for (int element = 0; element < N; element++)
239 {
240 quint16 t16_1 = 0, t16_2, subtyp;
241 quint8 t8;
242 quint32 typ, offset = 0;
243 bool hasLocalization = false;
244 bool hasTextColor = false;
245 quint8 ctyp;
246 QImage xpmDay(32, 32, QImage::Format_Indexed8);
247 QImage xpmNight(32, 32, QImage::Format_Indexed8);
248 quint8 r, g, b;
249 quint8 langcode;
250
251 in.device()->seek( sectPolygons.arrayOffset + (sectPolygons.arrayModulo * element ) );
252
253 if (sectPolygons.arrayModulo == 5)
254 {
255 in >> t16_1 >> t16_2 >> t8;
256 offset = t16_2 | (t8 << 16);
257 }
258 else if (sectPolygons.arrayModulo == 4)
259 {
260 in >> t16_1 >> t16_2;
261 offset = t16_2;
262 }
263 else if (sectPolygons.arrayModulo == 3)
264 {
265 in >> t16_1 >> t8;
266 offset = t8;
267 }
268
269 t16_2 = (t16_1 >> 5) | (( t16_1 & 0x1f) << 11);
270 typ = t16_2 & 0x7F;
271 subtyp = t16_1 & 0x1F;
272
273 if(t16_1 & 0x2000)
274 {
275 typ = 0x10000 | (typ << 8) | subtyp;
276 }
277
278 in.device()->seek(sectPolygons.dataOffset + offset);
279 in >> t8;
280 hasLocalization = t8 & 0x10;
281 hasTextColor = t8 & 0x20;
282 ctyp = t8 & 0x0F;
283
284 #ifdef DBG
285 qDebug() << "Polygon typ:" << hex << typ << "ctype:" << ctyp << "offset:" << (sectPolygons.dataOffset + offset) << "orig data:" << t16_1;
286 #endif
287
288 polygon_property& property = polygons[typ];
289
290 switch(ctyp)
291 {
292 case 0x01:
293 {
294 // day & night single color
295 in >> b >> g >> r;
296 property.brushDay = QBrush(qRgb(r, g, b));
297 in >> b >> g >> r;
298 property.brushNight = QBrush(qRgb(r, g, b));
299
300 // night and day color for line?
301 in >> b >> g >> r;
302 property.pen = QPen(QBrush(qRgb(r, g, b)), 2);
303 in >> b >> g >> r;
304 property.known = true;
305
306 break;
307 }
308
309 case 0x06:
310 {
311 // day & night single color
312 in >> b >> g >> r;
313 property.brushDay = QBrush(qRgb(r, g, b));
314 property.brushNight = QBrush(qRgb(r, g, b));
315 property.pen = Qt::NoPen;
316 property.known = true;
317
318 break;
319 }
320
321 case 0x07:
322 {
323 // day single color & night single color
324 in >> b >> g >> r;
325 property.brushDay = QBrush(qRgb(r, g, b));
326 in >> b >> g >> r;
327 property.brushNight = QBrush(qRgb(r, g, b));
328 property.pen = Qt::NoPen;
329 property.known = true;
330
331 break;
332 }
333
334 case 0x08:
335 {
336 // day & night two color
337 xpmDay.setColorCount(2);
338
339 in >> b >> g >> r;
340 xpmDay.setColor(1, qRgb(r, g, b) );
341 in >> b >> g >> r;
342 xpmDay.setColor(0, qRgb(r, g, b) );
343
344 decodeBitmap(in, xpmDay, 32, 32, 1);
345 property.brushDay.setTextureImage(xpmDay);
346 property.brushNight.setTextureImage(xpmDay);
347 property.pen = Qt::NoPen;
348 property.known = true;
349 break;
350 }
351
352 case 0x09:
353 {
354 //day two color & night two color
355 xpmDay.setColorCount(2);
356 xpmNight.setColorCount(2);
357 in >> b >> g >> r;
358 xpmDay.setColor(1, qRgb(r, g, b) );
359 in >> b >> g >> r;
360 xpmDay.setColor(0, qRgb(r, g, b) );
361 in >> b >> g >> r;
362 xpmNight.setColor(1, qRgb(r, g, b) );
363 in >> b >> g >> r;
364 xpmNight.setColor(0, qRgb(r, g, b) );
365
366 decodeBitmap(in, xpmDay, 32, 32, 1);
367 memcpy(xpmNight.bits(), xpmDay.bits(), (32 * 32));
368 property.brushDay.setTextureImage(xpmDay);
369 property.brushNight.setTextureImage(xpmNight);
370 property.pen = Qt::NoPen;
371 property.known = true;
372
373 break;
374 }
375
376 case 0x0B:
377 {
378 // day one color, transparent & night two color
379 xpmDay.setColorCount(2);
380 xpmNight.setColorCount(2);
381 in >> b >> g >> r;
382 xpmDay.setColor(1, qRgb(r, g, b) );
383 xpmDay.setColor(0, qRgba(255, 255, 255, 0) );
384
385 in >> b >> g >> r;
386 xpmNight.setColor(1, qRgb(r, g, b) );
387 in >> b >> g >> r;
388 xpmNight.setColor(0, qRgb(r, g, b) );
389
390 decodeBitmap(in, xpmDay, 32, 32, 1);
391 memcpy(xpmNight.bits(), xpmDay.bits(), (32 * 32));
392 property.brushDay.setTextureImage(xpmDay);
393 property.brushNight.setTextureImage(xpmNight);
394 property.pen = Qt::NoPen;
395 property.known = true;
396 break;
397 }
398
399 case 0x0D:
400 {
401 // day two color & night one color, transparent
402
403 xpmDay.setColorCount(2);
404 xpmNight.setColorCount(2);
405 in >> b >> g >> r;
406 xpmDay.setColor(1, qRgb(r, g, b) );
407 in >> b >> g >> r;
408 xpmDay.setColor(0, qRgb(r, g, b) );
409
410 in >> b >> g >> r;
411 xpmNight.setColor(1, qRgb(r, g, b) );
412 xpmNight.setColor(0, qRgba(255, 255, 255, 0) );
413
414 decodeBitmap(in, xpmDay, 32, 32, 1);
415 memcpy(xpmNight.bits(), xpmDay.bits(), (32 * 32));
416 property.brushDay.setTextureImage(xpmDay);
417 property.brushNight.setTextureImage(xpmNight);
418 property.pen = Qt::NoPen;
419 property.known = true;
420
421 break;
422 }
423
424 case 0x0E:
425 {
426 // day & night one color, transparent
427 xpmDay.setColorCount(2);
428 in >> b >> g >> r;
429 xpmDay.setColor(1, qRgb(r, g, b) );
430 xpmDay.setColor(0, qRgba(255, 255, 255, 0) );
431
432 decodeBitmap(in, xpmDay, 32, 32, 1);
433 property.brushDay.setTextureImage(xpmDay);
434 property.brushNight.setTextureImage(xpmDay);
435 property.pen = Qt::NoPen;
436 property.known = true;
437
438 break;
439 }
440
441 case 0x0F:
442 {
443 // day one color, transparent & night one color, transparent
444 xpmDay.setColorCount(2);
445 xpmNight.setColorCount(2);
446 in >> b >> g >> r;
447 xpmDay.setColor(1, qRgb(r, g, b) );
448 xpmDay.setColor(0, qRgba(255, 255, 255, 0) );
449
450 in >> b >> g >> r;
451 xpmNight.setColor(1, qRgb(r, g, b) );
452 xpmNight.setColor(0, qRgba(255, 255, 255, 0) );
453
454 decodeBitmap(in, xpmDay, 32, 32, 1);
455 memcpy(xpmNight.bits(), xpmDay.bits(), (32 * 32));
456 property.brushDay.setTextureImage(xpmDay);
457 property.brushNight.setTextureImage(xpmNight);
458 property.pen = Qt::NoPen;
459 property.known = true;
460
461 break;
462 }
463
464 default:
465 if(!tainted)
466 {
467 QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("Warning..."), tr("This is a typ file with unknown polygon encoding. Please report!"), QMessageBox::Abort, QMessageBox::Abort);
468 tainted = true;
469 }
470 qDebug() << "Failed polygon:" << typ << subtyp << hex << typ << subtyp << ctyp;
471 }
472
473 if(hasLocalization)
474 {
475 qint16 len;
476 quint8 n = 1;
477
478 in >> t8;
479 len = t8;
480
481 if(!(t8 & 0x01))
482 {
483 n = 2;
484 in >> t8;
485 len |= t8 << 8;
486 }
487
488 len -= n;
489 while(len > 0)
490 {
491 QByteArray str;
492 in >> langcode;
493 languages << langcode;
494 len -= 2 * n;
495 while(len > 0)
496 {
497 in >> t8;
498 len -= 2 * n;
499
500 if(t8 == 0)
501 {
502 break;
503 }
504
505 str += t8;
506 }
507 if(codec != nullptr)
508 {
509 property.strings[langcode] = codec->toUnicode(str);
510 }
511 #ifdef DBG
512 qDebug() << len << langcode << property.strings[langcode];
513 #endif
514 }
515 }
516
517 if(hasTextColor)
518 {
519 in >> t8;
520 property.labelType = (label_type_e)(t8 & 0x07);
521
522 if(t8 & 0x08)
523 {
524 in >> r >> g >> b;
525 property.colorLabelDay = qRgb(r, g, b);
526 }
527
528 if(t8 & 0x10)
529 {
530 in >> r >> g >> b;
531 property.colorLabelNight = qRgb(r, g, b);
532 }
533 #ifdef DBG
534 qDebug() << "ext. label: type" << property.labelType << "day" << property.colorLabelDay << "night" << property.colorLabelNight;
535 #endif
536 }
537 }
538
539 return true;
540 }
541
542
parsePolyline(QDataStream & in,QMap<quint32,polyline_property> & polylines)543 bool CGarminTyp::parsePolyline(QDataStream& in, QMap<quint32, polyline_property>& polylines)
544 {
545 bool tainted = false;
546
547 if(sectPolylines.arraySize == 0)
548 {
549 return true;
550 }
551
552 if(!sectPolylines.arrayModulo || ((sectPolylines.arraySize % sectPolylines.arrayModulo) != 0))
553 {
554 return true;
555 }
556
557 QTextCodec* codec = getCodec(codepage);
558
559 const int N = sectPolylines.arraySize / sectPolylines.arrayModulo;
560 for (int element = 0; element < N; element++)
561 {
562 quint16 t16_1 = 0, t16_2, subtyp;
563 quint8 t8_1, t8_2;
564 quint32 typ, offset = 0;
565 bool hasLocalization = false;
566 bool hasTextColor = false;
567 //bool renderMode = false;
568 quint8 ctyp, rows;
569 quint8 r, g, b;
570 quint8 langcode;
571
572 in.device()->seek( sectPolylines.arrayOffset + (sectPolylines.arrayModulo * element ) );
573
574 if (sectPolylines.arrayModulo == 5)
575 {
576 in >> t16_1 >> t16_2 >> t8_1;
577 offset = t16_2 | (t8_1 << 16);
578 }
579 else if (sectPolylines.arrayModulo == 4)
580 {
581 in >> t16_1 >> t16_2;
582 offset = t16_2;
583 }
584 else if (sectPolylines.arrayModulo == 3)
585 {
586 in >> t16_1 >> t8_1;
587 offset = t8_1;
588 }
589
590 t16_2 = (t16_1 >> 5) | (( t16_1 & 0x1f) << 11);
591 typ = t16_2 & 0x7F;
592 subtyp = t16_1 & 0x1F;
593
594 if(t16_1 & 0x2000)
595 {
596 typ = 0x10000 | (typ << 8) | subtyp;
597 }
598
599 in.device()->seek(sectPolylines.dataOffset + offset);
600 in >> t8_1 >> t8_2;
601 ctyp = t8_1 & 0x07;
602 rows = t8_1 >> 3;
603
604 hasLocalization = t8_2 & 0x01;
605 //renderMode = t8_2 & 0x02;
606 hasTextColor = t8_2 & 0x04;
607
608 #ifdef DBG
609 qDebug() << "Polyline typ:" << hex << typ << "ctyp:" << ctyp << "offset:" << (sectPolylines.dataOffset + offset) << "orig data:" << t16_1;
610 #endif
611
612 polyline_property& property = polylines[typ];
613 #ifdef DBG
614 qDebug() << "rows" << rows << "t8_2" << hex << t8_2;
615 #endif
616
617 switch(ctyp)
618 {
619 case 0x00:
620 {
621 if(rows)
622 {
623 QImage xpm(32, rows, QImage::Format_Indexed8 );
624 in >> b >> g >> r;
625 xpm.setColor(1, qRgb(r, g, b) );
626 in >> b >> g >> r;
627 xpm.setColor(0, qRgb(r, g, b) );
628 decodeBitmap(in, xpm, 32, rows, 1);
629 property.imgDay = xpm;
630 property.imgNight = xpm;
631 property.hasPixmap = true;
632 property.known = true;
633 }
634 else
635 {
636 quint8 w1, w2;
637 in >> b >> g >> r;
638 property.penLineDay = QPen(QBrush(qRgb(r, g, b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
639 property.penLineNight = QPen(QBrush(qRgb(r, g, b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
640 in >> b >> g >> r;
641 property.penBorderDay = QPen(QBrush(qRgb(r, g, b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
642 property.penBorderNight = QPen(QBrush(qRgb(r, g, b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
643 in >> w1 >> w2;
644 property.penLineDay.setWidth(w1);
645 property.penLineNight.setWidth(w1);
646 property.penBorderDay.setWidth(w2);
647 property.penBorderNight.setWidth(w2);
648 property.hasBorder = w2 > w1;
649 property.hasPixmap = false;
650 property.known = true;
651 }
652
653 break;
654 }
655
656 case 0x01:
657 {
658 if(rows)
659 {
660 QImage xpm1(32, rows, QImage::Format_Indexed8 );
661 QImage xpm2(32, rows, QImage::Format_Indexed8 );
662 in >> b >> g >> r;
663 xpm1.setColor(1, qRgb(r, g, b) );
664 in >> b >> g >> r;
665 xpm1.setColor(0, qRgb(r, g, b) );
666 in >> b >> g >> r;
667 xpm2.setColor(1, qRgb(r, g, b) );
668 in >> b >> g >> r;
669 xpm2.setColor(0, qRgb(r, g, b) );
670 decodeBitmap(in, xpm1, 32, rows, 1);
671 memcpy(xpm2.bits(), xpm1.bits(), (32 * rows));
672 property.imgDay = xpm1;
673 property.imgNight = xpm2;
674 property.hasPixmap = true;
675 property.known = true;
676 }
677 else
678 {
679 quint8 w1, w2;
680 in >> b >> g >> r;
681 property.penLineDay = QPen(QBrush(qRgb(r, g, b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
682 in >> b >> g >> r;
683 property.penBorderDay = QPen(QBrush(qRgb(r, g, b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
684 in >> b >> g >> r;
685 property.penLineNight = QPen(QBrush(qRgb(r, g, b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
686 in >> b >> g >> r;
687 property.penBorderNight = QPen(QBrush(qRgb(r, g, b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
688 in >> w1 >> w2;
689 property.penLineDay.setWidth(w1);
690 property.penLineNight.setWidth(w1);
691 property.penBorderDay.setWidth(w2);
692 property.penBorderNight.setWidth(w2);
693 property.hasBorder = w2 > w1;
694 property.hasPixmap = false;
695 property.known = true;
696 }
697 break;
698 }
699
700 case 0x03:
701 {
702 if(rows)
703 {
704 QImage xpm1(32, rows, QImage::Format_Indexed8 );
705 QImage xpm2(32, rows, QImage::Format_Indexed8 );
706 in >> b >> g >> r;
707 xpm1.setColor(1, qRgb(r, g, b) );
708 xpm1.setColor(0, qRgba(255, 255, 255, 0) );
709 in >> b >> g >> r;
710 xpm2.setColor(1, qRgb(r, g, b) );
711 in >> b >> g >> r;
712 xpm2.setColor(0, qRgb(r, g, b) );
713 decodeBitmap(in, xpm1, 32, rows, 1);
714 memcpy(xpm2.bits(), xpm1.bits(), (32 * rows));
715 property.imgDay = xpm1;
716 property.imgNight = xpm2;
717 property.hasPixmap = true;
718 property.known = true;
719 }
720 else
721 {
722 quint8 w1, w2;
723 in >> b >> g >> r;
724 property.penLineDay = QPen(QBrush(qRgb(r, g, b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
725 property.penBorderDay = QPen(Qt::NoPen);
726 in >> b >> g >> r;
727 property.penLineNight = QPen(QBrush(qRgb(r, g, b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
728 in >> b >> g >> r;
729 property.penBorderNight = QPen(QBrush(qRgb(r, g, b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
730 in >> w1 >> w2;
731 property.penLineDay.setWidth(w1);
732 property.penLineNight.setWidth(w1);
733 property.penBorderDay.setWidth(w2);
734 property.penBorderNight.setWidth(w2);
735 property.hasBorder = w2 > w1;
736 property.hasPixmap = false;
737 property.known = true;
738 }
739
740 break;
741 }
742
743 case 0x05:
744 {
745 if(rows)
746 {
747 QImage xpm1(32, rows, QImage::Format_Indexed8 );
748 QImage xpm2(32, rows, QImage::Format_Indexed8 );
749 in >> b >> g >> r;
750 xpm1.setColor(1, qRgb(r, g, b) );
751 in >> b >> g >> r;
752 xpm1.setColor(0, qRgb(r, g, b) );
753 in >> b >> g >> r;
754 xpm2.setColor(1, qRgb(r, g, b) );
755 xpm2.setColor(0, qRgba(255, 255, 255, 0) );
756 decodeBitmap(in, xpm1, 32, rows, 1);
757 memcpy(xpm2.bits(), xpm1.bits(), (32 * rows));
758 property.imgDay = xpm1;
759 property.imgNight = xpm2;
760 property.hasPixmap = true;
761 property.known = true;
762 }
763 else
764 {
765 quint8 w1;
766 in >> b >> g >> r;
767 property.penLineDay = QPen(QBrush(qRgb(r, g, b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
768 in >> b >> g >> r;
769 property.penBorderDay = QPen(QBrush(qRgb(r, g, b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
770 in >> b >> g >> r;
771 property.penLineNight = QPen(QBrush(qRgb(r, g, b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
772 property.penBorderNight = QPen(Qt::NoPen);
773 in >> w1;
774 property.penLineDay.setWidth(w1);
775 property.penLineNight.setWidth(w1);
776 property.hasBorder = false;
777 property.hasPixmap = false;
778 property.known = true;
779 }
780 break;
781 }
782
783 case 0x06:
784 {
785 if(rows)
786 {
787 QImage xpm(32, rows, QImage::Format_Indexed8 );
788 in >> b >> g >> r;
789 xpm.setColor(1, qRgb(r, g, b) );
790 xpm.setColor(0, qRgba(255, 255, 255, 0) );
791 decodeBitmap(in, xpm, 32, rows, 1);
792 property.imgDay = xpm;
793 property.imgNight = xpm;
794 property.hasPixmap = true;
795 property.known = true;
796 }
797 else
798 {
799 quint8 w1;
800 in >> b >> g >> r;
801 property.penLineDay = QPen(QBrush(qRgb(r, g, b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
802 property.penBorderDay = QPen(Qt::NoPen);
803 property.penLineNight = QPen(QBrush(qRgb(r, g, b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
804 property.penBorderNight = QPen(Qt::NoPen);
805 in >> w1;
806 property.penLineDay.setWidth(w1);
807 property.penLineNight.setWidth(w1);
808 property.hasBorder = false;
809 property.hasPixmap = false;
810 property.known = true;
811 }
812 break;
813 }
814
815 case 0x07:
816 {
817 if(rows)
818 {
819 QImage xpm1(32, rows, QImage::Format_Indexed8 );
820 QImage xpm2(32, rows, QImage::Format_Indexed8 );
821 in >> b >> g >> r;
822 xpm1.setColor(1, qRgb(r, g, b) );
823 xpm1.setColor(0, qRgba(255, 255, 255, 0) );
824 in >> b >> g >> r;
825 xpm2.setColor(1, qRgb(r, g, b) );
826 xpm2.setColor(0, qRgba(255, 255, 255, 0) );
827 decodeBitmap(in, xpm1, 32, rows, 1);
828 memcpy(xpm2.bits(), xpm1.bits(), (32 * rows));
829 property.imgDay = xpm1;
830 property.imgNight = xpm2;
831 property.hasPixmap = true;
832 property.known = true;
833 }
834 else
835 {
836 quint8 w1;
837 in >> b >> g >> r;
838 property.penLineDay = QPen(QBrush(qRgb(r, g, b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
839 property.penBorderDay = QPen(Qt::NoPen);
840 in >> b >> g >> r;
841 property.penLineNight = QPen(QBrush(qRgb(r, g, b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
842 property.penBorderNight = QPen(Qt::NoPen);
843 in >> w1;
844 property.penLineDay.setWidth(w1);
845 property.penLineNight.setWidth(w1);
846 property.hasBorder = false;
847 property.hasPixmap = false;
848 property.known = true;
849 }
850 break;
851 }
852
853 default:
854 if(!tainted)
855 {
856 QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("Warning..."), tr("This is a typ file with unknown polyline encoding. Please report!"), QMessageBox::Abort, QMessageBox::Abort);
857 tainted = true;
858 }
859
860 qDebug() << "Failed polyline" << hex << ":" << typ << ctyp << rows;
861 continue;
862 }
863
864 property.imgDay = property.imgDay.convertToFormat(QImage::Format_ARGB32_Premultiplied);
865 property.imgNight = property.imgNight.convertToFormat(QImage::Format_ARGB32_Premultiplied);
866 if(hasLocalization)
867 {
868 qint16 len;
869 quint8 n = 1;
870
871 in >> t8_1;
872 len = t8_1;
873
874 if(!(t8_1 & 0x01))
875 {
876 n = 2;
877 in >> t8_1;
878 len |= t8_1 << 8;
879 }
880
881 len -= n;
882 while(len > 0)
883 {
884 QByteArray str;
885 in >> langcode;
886 languages << langcode;
887 len -= 2 * n;
888 while(len > 0)
889 {
890 in >> t8_1;
891 len -= 2 * n;
892
893 if(t8_1 == 0)
894 {
895 break;
896 }
897
898 str += t8_1;
899 }
900 if(codec != nullptr)
901 {
902 property.strings[langcode] = codec->toUnicode(str);
903 }
904 #ifdef DBG
905 qDebug() << len << langcode << property.strings[langcode];
906 #endif
907 }
908 }
909
910 if(hasTextColor)
911 {
912 in >> t8_1;
913 property.labelType = (label_type_e)(t8_1 & 0x07);
914
915 if(t8_1 & 0x08)
916 {
917 in >> r >> g >> b;
918 property.colorLabelDay = qRgb(r, g, b);
919 }
920
921 if(t8_1 & 0x10)
922 {
923 in >> r >> g >> b;
924 property.colorLabelNight = qRgb(r, g, b);
925 }
926 #ifdef DBG
927 qDebug() << "ext. label: type" << property.labelType << "day" << property.colorLabelDay << "night" << property.colorLabelNight;
928 #endif
929 }
930
931 if(property.hasPixmap)
932 {
933 property.imgDay = property.imgDay.mirrored(false, true);
934 property.imgNight = property.imgNight.mirrored(false, true);
935 }
936 }
937 return true;
938 }
939
940
decodeBppAndBytes(int ncolors,int w,int flags,int & bpp,int & bytes)941 bool CGarminTyp::decodeBppAndBytes(int ncolors, int w, int flags, int& bpp, int& bytes)
942 {
943 switch(flags)
944 {
945 case 0x00:
946 {
947 if(ncolors < 3)
948 {
949 bpp = ncolors;
950 }
951 else if(ncolors == 3)
952 {
953 bpp = 2;
954 }
955 else if(ncolors < 16)
956 {
957 bpp = 4;
958 }
959 else if(ncolors < 256)
960 {
961 bpp = 8;
962 }
963 else
964 {
965 return false;
966 }
967 break;
968 }
969
970 case 0x10:
971 {
972 if(ncolors == 0)
973 {
974 bpp = 1;
975 }
976 else if(ncolors < 3)
977 {
978 bpp = 2;
979 }
980 else if(ncolors < 15)
981 {
982 bpp = 4;
983 }
984 else if(ncolors < 256)
985 {
986 bpp = 8;
987 }
988 else
989 {
990 return false;
991 }
992 break;
993 }
994
995 case 0x20:
996 {
997 if(ncolors == 0)
998 {
999 bpp = 16;
1000 }
1001 else if(ncolors < 3)
1002 {
1003 bpp = ncolors;
1004 }
1005 else if(ncolors < 4)
1006 {
1007 bpp = 2;
1008 }
1009 else if(ncolors < 16)
1010 {
1011 bpp = 4;
1012 }
1013 else if(ncolors < 256)
1014 {
1015 bpp = 8;
1016 }
1017 else
1018 {
1019 return false;
1020 }
1021 break;
1022 }
1023
1024 default:
1025 return false;
1026 }
1027
1028 bytes = (w * bpp) / 8;
1029 if( (w * bpp) & 0x07 )
1030 {
1031 ++bytes;
1032 }
1033
1034 return true;
1035 }
1036
1037
decodeColorTable(QDataStream & in,QImage & img,int ncolors,int maxcolor,bool hasAlpha)1038 bool CGarminTyp::decodeColorTable(QDataStream& in, QImage& img, int ncolors, int maxcolor, bool hasAlpha)
1039 {
1040 img.setColorCount(ncolors);
1041
1042 if(hasAlpha)
1043 {
1044 int i;
1045 quint8 byte;
1046 quint32 bits = 0;
1047 quint32 reg = 0;
1048 quint32 mask = 0x000000FF;
1049
1050 for (i = 0; i < ncolors; i++)
1051 {
1052 while(bits < 28)
1053 {
1054 in >> byte;
1055 mask = 0x000000FF << bits;
1056 reg = reg & (~mask);
1057 reg = reg | (byte << bits);
1058 bits += 8;
1059 }
1060
1061 img.setColor(i, qRgba((reg >> 16) & 0x0FF, (reg >> 8) & 0x0FF, reg & 0x0FF, ~((reg >> 24) & 0x0F) << 4));
1062
1063 reg = reg >> 28;
1064 bits -= 28;
1065 }
1066 for(; i < maxcolor; ++i)
1067 {
1068 img.setColor(i, qRgba(0, 0, 0, 0));
1069 }
1070 }
1071 else
1072 {
1073 int i;
1074 quint8 r, g, b;
1075 for(i = 0; i < ncolors; ++i)
1076 {
1077 in >> b >> g >> r;
1078 img.setColor(i, qRgb(r, g, b));
1079 }
1080 for(; i < maxcolor; ++i)
1081 {
1082 img.setColor(i, qRgba(0, 0, 0, 0));
1083 }
1084 }
1085 return true;
1086 }
1087
1088
decodeBitmap(QDataStream & in,QImage & img,int w,int h,int bpp)1089 void CGarminTyp::decodeBitmap(QDataStream& in, QImage& img, int w, int h, int bpp)
1090 {
1091 int x = 0, j = 0;
1092 quint8 color;
1093
1094 if(bpp == 0)
1095 {
1096 return;
1097 }
1098
1099 for (int y = 0; y < h; y++)
1100 {
1101 while ( x < w )
1102 {
1103 in >> color;
1104
1105 for ( int i = 0; (i < (8 / bpp)) && (x < w); i++ )
1106 {
1107 int value;
1108 if ( i > 0 )
1109 {
1110 value = (color >>= bpp);
1111 }
1112 else
1113 {
1114 value = color;
1115 }
1116 if ( bpp == 4)
1117 {
1118 value = value & 0xf;
1119 }
1120 if ( bpp == 2)
1121 {
1122 value = value & 0x3;
1123 }
1124 if ( bpp == 1)
1125 {
1126 value = value & 0x1;
1127 }
1128 img.setPixel(x, y, value);
1129 // qDebug() << QString("value(%4) pixel at (%1,%2) is 0x%3 j is %5").arg(x).arg(y).arg(value,0,16).arg(color).arg(j);
1130 x += 1;
1131 }
1132 j += 1;
1133 }
1134 x = 0;
1135 }
1136 }
1137
1138
parsePoint(QDataStream & in,QMap<quint32,point_property> & points)1139 bool CGarminTyp::parsePoint(QDataStream& in, QMap<quint32, point_property>& points)
1140 {
1141 // bool tainted = false;
1142
1143 if(!sectPoints.arrayModulo || ((sectPoints.arraySize % sectPoints.arrayModulo) != 0))
1144 {
1145 return true;
1146 }
1147
1148 QTextCodec* codec = getCodec(codepage);
1149
1150 const int N = sectPoints.arraySize / sectPoints.arrayModulo;
1151 for (int element = 0; element < N; element++)
1152 {
1153 quint16 t16_1 = 0, t16_2, subtyp;
1154 quint8 t8_1;
1155 quint32 typ, offset = 0;
1156 bool hasLocalization = false;
1157 bool hasTextColor = false;
1158 quint8 langcode;
1159 quint8 r, g, b;
1160
1161 in.device()->seek( sectPoints.arrayOffset + (sectPoints.arrayModulo * element ) );
1162
1163 if (sectPoints.arrayModulo == 5)
1164 {
1165 in >> t16_1 >> t16_2 >> t8_1;
1166 offset = t16_2 | (t8_1 << 16);
1167 }
1168 else if (sectPoints.arrayModulo == 4)
1169 {
1170 in >> t16_1 >> t16_2;
1171 offset = t16_2;
1172 }
1173 else if (sectPoints.arrayModulo == 3)
1174 {
1175 in >> t16_1 >> t8_1;
1176 offset = t8_1;
1177 }
1178
1179 t16_2 = (t16_1 >> 5) | (( t16_1 & 0x1f) << 11);
1180 typ = t16_2 & 0x7FF;
1181 subtyp = t16_1 & 0x01F;
1182
1183 if(t16_1 & 0x2000)
1184 {
1185 typ = 0x10000 | (typ << 8) | subtyp;
1186 }
1187 else
1188 {
1189 typ = (typ << 8) + subtyp;
1190 }
1191
1192 in.device()->seek( sectPoints.dataOffset + offset );
1193
1194 int bpp = 0, wbytes = 0;
1195 quint8 w, h, ncolors, ctyp;
1196 in >> t8_1 >> w >> h >> ncolors >> ctyp;
1197
1198 hasLocalization = t8_1 & 0x04;
1199 hasTextColor = t8_1 & 0x08;
1200 t8_1 = t8_1 & 0x03;
1201 #ifdef DBG
1202 qDebug() << "Point typ:" << hex << typ << "ctyp:" << ctyp << "offset:" << (sectPoints.dataOffset + offset) << "orig data:" << t16_1;
1203 #endif
1204
1205 if(!decodeBppAndBytes(ncolors, w, ctyp, bpp, wbytes))
1206 {
1207 continue;
1208 }
1209
1210 #ifdef DBG
1211 qDebug() << " " << dec << "w" << w << "h" << h << "ncolors" << ncolors << "bpp" << bpp << "wbytes" << wbytes;
1212 #endif
1213
1214 if(ctyp == 0x20 || ctyp == 0x00)
1215 {
1216 if((ncolors == 0) && (bpp >= 16))
1217 {
1218 ncolors = w * h;
1219 }
1220 }
1221
1222 point_property& property = points[typ];
1223 QImage imgDay(w, h, QImage::Format_Indexed8 );
1224 QImage imgNight(w, h, QImage::Format_Indexed8 );
1225
1226 if(!decodeColorTable(in, imgDay, ncolors, 1 << bpp, ctyp == 0x20))
1227 {
1228 continue;
1229 }
1230
1231 if(bpp >= 16)
1232 {
1233 continue;
1234 }
1235 else
1236 {
1237 decodeBitmap(in, imgDay, w, h, bpp);
1238 property.imgDay = imgDay;
1239 }
1240
1241 if(t8_1 == 0x03)
1242 {
1243 in >> ncolors >> ctyp;
1244 if(!decodeBppAndBytes(ncolors, w, ctyp, bpp, wbytes))
1245 {
1246 continue;
1247 }
1248 if(!decodeColorTable(in, imgNight, ncolors, 1 << bpp, ctyp == 0x20))
1249 {
1250 continue;
1251 }
1252 decodeBitmap(in, imgNight, w, h, bpp);
1253 points[typ].imgNight = imgNight;
1254 }
1255 else if(t8_1 == 0x02)
1256 {
1257 in >> ncolors >> ctyp;
1258 if(!decodeBppAndBytes(ncolors, w, ctyp, bpp, wbytes))
1259 {
1260 continue;
1261 }
1262 if(!decodeColorTable(in, imgDay, ncolors, 1 << bpp, ctyp == 0x20))
1263 {
1264 continue;
1265 }
1266 property.imgNight = imgDay;
1267 }
1268 else
1269 {
1270 property.imgNight = imgDay;
1271 }
1272
1273 if(hasLocalization)
1274 {
1275 qint16 len;
1276 quint8 n = 1;
1277
1278 in >> t8_1;
1279 len = t8_1;
1280
1281 if(!(t8_1 & 0x01))
1282 {
1283 n = 2;
1284 in >> t8_1;
1285 len |= t8_1 << 8;
1286 }
1287
1288 len -= n;
1289 while(len > 0)
1290 {
1291 QByteArray str;
1292 in >> langcode;
1293 languages << langcode;
1294 len -= 2 * n;
1295 while(len > 0)
1296 {
1297 in >> t8_1;
1298 len -= 2 * n;
1299
1300 if(t8_1 == 0)
1301 {
1302 break;
1303 }
1304
1305 str += t8_1;
1306 }
1307 if(codec != nullptr)
1308 {
1309 property.strings[langcode] = codec->toUnicode(str);
1310 }
1311 #ifdef DBG
1312 qDebug() << len << langcode << property.strings[langcode];
1313 #endif
1314 }
1315 }
1316
1317 if(hasTextColor)
1318 {
1319 in >> t8_1;
1320 property.labelType = (label_type_e)(t8_1 & 0x07);
1321
1322 if(t8_1 & 0x08)
1323 {
1324 in >> r >> g >> b;
1325 property.colorLabelDay = qRgb(r, g, b);
1326 }
1327
1328 if(t8_1 & 0x10)
1329 {
1330 in >> r >> g >> b;
1331 property.colorLabelNight = qRgb(r, g, b);
1332 }
1333 #ifdef DBG
1334 qDebug() << "ext. label: type" << property.labelType << "day" << property.colorLabelDay << "night" << property.colorLabelNight;
1335 #endif
1336 }
1337 }
1338
1339 return true;
1340 }
1341