1 #include "huffmantext.h"
5 using namespace Garmin
;
8 enum Charset
{Normal
, Symbol
, Special
};
10 static quint8 NORMAL_CHARS
[] = {
11 ' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
12 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
13 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
14 'X', 'Y', 'Z', '~', '~', '~', ' ', ' ',
15 '0', '1', '2', '3', '4', '5', '6', '7',
16 '8', '9', '~', '~', '~', '~', '~', '~'
19 static quint8 SYMBOL_CHARS
[] = {
20 '@', '!', '"', '#', '$', '%', '&', '\'',
21 '(', ')', '*', '+', ',', '-', '.', '/',
22 '~', '~', '~', '~', '~', '~', '~', '~',
23 '~', '~', ':', ';', '<', '=', '>', '?',
24 '~', '~', '~', '~', '~', '~', '~', '~',
25 '~', '~', '~', '[', '\\', ']', '^', '_'
28 static quint8 SPECIAL_CHARS
[] = {
29 '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
30 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
31 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
32 'x', 'y', 'z', '~', '~', '~', '~', '~',
33 '0', '1', '2', '3', '4', '5', '6', '7',
34 '8', '9', '~', '~', '~', '~', '~', '~'
37 static bool isAllUpperCase(const QString
&str
)
42 for (int i
= 0; i
< str
.size(); i
++) {
44 if (c
.isLetter() && !(c
.isUpper() || c
== QChar(0x00DF)))
51 static QString
capitalized(const QString
&str
)
55 ret
.resize(str
.size());
60 for (int i
= 1; i
< str
.size(); i
++) {
61 QChar
last(str
.at(i
-1));
62 QChar
current(str
.at(i
));
64 if (!(last
.isSpace() || last
== '('))
65 ret
[i
] = current
.toLower();
73 static QByteArray
ft2m(const QByteArray
&str
)
76 int number
= str
.toInt(&ok
);
77 return ok
? QByteArray::number(qRound(number
* 0.3048)) : str
;
87 bool LBLFile::load(Handle
&hdl
, const RGNFile
*rgn
, Handle
&rgnHdl
)
89 quint16 hdrLen
, codepage
;
91 if (!(seek(hdl
, _gmpOffset
) && readUInt16(hdl
, hdrLen
)
92 && seek(hdl
, _gmpOffset
+ 0x15) && readUInt32(hdl
, _base
.offset
)
93 && readUInt32(hdl
, _base
.size
) && readByte(hdl
, &_shift
)
94 && readByte(hdl
, &_encoding
) && seek(hdl
, _gmpOffset
+ 0x57)
95 && readUInt32(hdl
, _poi
.offset
) && readUInt32(hdl
, _poi
.size
)
96 && readByte(hdl
, &_poiShift
) && seek(hdl
, _gmpOffset
+ 0xAA)
97 && readUInt16(hdl
, codepage
)))
100 if (hdrLen
>= 0x132) {
101 quint32 offset
, size
;
103 if (!(seek(hdl
, _gmpOffset
+ 0x124) && readUInt32(hdl
, offset
)
104 && readUInt32(hdl
, size
) && readUInt16(hdl
, recordSize
)))
107 if (size
&& recordSize
) {
108 _table
= new quint32
[size
/ recordSize
];
109 if (!seek(hdl
, offset
))
111 for (quint32 i
= 0; i
< size
/ recordSize
; i
++) {
112 if (!readVUInt32(hdl
, recordSize
, _table
[i
]))
118 if (hdrLen
>= 0x19A) {
119 quint32 offset
, recordSize
, size
, flags
;
120 if (!(seek(hdl
, _gmpOffset
+ 0x184) && readUInt32(hdl
, offset
)
121 && readUInt32(hdl
, size
) && readUInt16(hdl
, recordSize
)
122 && readUInt32(hdl
, flags
) && readUInt32(hdl
, _img
.offset
)
123 && readUInt32(hdl
, _img
.size
)))
126 if (size
&& recordSize
)
127 if (!loadRasterTable(hdl
, offset
, size
, recordSize
))
131 if (_encoding
== 11) {
132 _huffmanText
= new HuffmanText();
133 if (!_huffmanText
->load(rgn
, rgnHdl
))
137 _codec
= TextCodec(codepage
);
142 void LBLFile::clear()
152 Label
LBLFile::str2label(const QVector
<quint8
> &str
, bool capitalize
,
155 Shield::Type shieldType
= Shield::None
;
156 QByteArray label
, shieldLabel
;
157 QByteArray
*bap
= &label
;
160 for (int i
= 0; i
< str
.size(); i
++) {
161 const quint8
&c
= str
.at(i
);
163 if (c
== 0 || c
== 0x1d || c
== 0x07)
168 else if ((c
>= 0x1e && c
<= 0x1f)) {
169 if (bap
== &shieldLabel
)
174 if (c
== 0x1f && split
< 0)
177 } else if (c
< 0x07) {
178 shieldType
= static_cast<Shield::Type
>(c
);
180 } else if (bap
== &shieldLabel
&& c
== 0x20) {
187 label
= label
.left(split
) + ft2m(label
.mid(split
));
190 QString
text(_codec
.toString(label
));
191 return Label(capitalize
&& isAllUpperCase(text
) ? capitalized(text
) : text
,
192 Shield(shieldType
, _codec
.toString(shieldLabel
)));
195 Label
LBLFile::label6b(const SubFile
*file
, Handle
&fileHdl
, quint32 size
,
196 bool capitalize
, bool convert
) const
198 Shield::Type shieldType
= Shield::None
;
199 QByteArray label
, shieldLabel
;
200 QByteArray
*bap
= &label
;
201 Charset curCharSet
= Normal
;
205 for (quint32 i
= 0; i
< size
; i
= i
+ 3) {
206 if (!(file
->readByte(fileHdl
, &b1
) && file
->readByte(fileHdl
, &b2
)
207 && file
->readByte(fileHdl
, &b3
)))
210 int c
[]= {b1
>>2, (b1
&0x3)<<4|b2
>>4, (b2
&0xF)<<2|b3
>>6, b3
&0x3F};
212 for (int cpt
= 0; cpt
< 4; cpt
++) {
213 if (c
[cpt
] > 0x2f || (curCharSet
== Normal
&& c
[cpt
] == 0x1d)) {
215 label
= label
.left(split
) + ft2m(label
.mid(split
));
218 QString
text(QString::fromLatin1(label
));
219 return Label(capitalize
&& isAllUpperCase(text
)
220 ? capitalized(text
) : text
, Shield(shieldType
, shieldLabel
));
222 switch (curCharSet
) {
226 else if (c
[cpt
] == 0x1b)
227 curCharSet
= Special
;
228 else if (c
[cpt
] >= 0x1e && c
[cpt
] <= 0x1f) {
229 if (bap
== &shieldLabel
)
234 if (c
[cpt
] == 0x1f && split
< 0)
237 } else if (c
[cpt
] >= 0x2a && c
[cpt
] <= 0x2f) {
238 shieldType
= static_cast<Shield::Type
>(c
[cpt
] - 0x29);
240 } else if (bap
== &shieldLabel
241 && NORMAL_CHARS
[c
[cpt
]] == ' ')
244 bap
->append(NORMAL_CHARS
[c
[cpt
]]);
247 bap
->append(SYMBOL_CHARS
[c
[cpt
]]);
251 bap
->append(SPECIAL_CHARS
[c
[cpt
]]);
261 Label
LBLFile::label8b(const SubFile
*file
, Handle
&fileHdl
, quint32 size
,
262 bool capitalize
, bool convert
)
267 for (quint32 i
= 0; i
< size
; i
++) {
268 if (!file
->readByte(fileHdl
, &c
))
272 return str2label(str
, capitalize
, convert
);
278 Label
LBLFile::labelHuffman(Handle
&hdl
, const SubFile
*file
, Handle
&fileHdl
,
279 quint32 size
, bool capitalize
, bool convert
)
283 if (!_huffmanText
->decode(file
, fileHdl
, size
, str
))
286 return str2label(str
, capitalize
, convert
);
289 QVector
<quint8
> str2
;
290 for (int i
= 0; i
< str
.size(); i
++) {
291 quint32 val
= _table
[str
.at(i
)];
293 quint32 off
= _base
.offset
+ ((val
& 0x7fffff) << _shift
);
297 if (str2
.size() && str2
.back() == '\0')
298 str2
[str2
.size() - 1] = ' ';
299 else if (str2
.size())
302 if (!_huffmanText
->decode(this, hdl
, _base
.offset
+ _base
.size
- off
,
306 if (str
.at(i
) == 7) {
310 if (str2
.size() && str2
.back() == '\0')
311 str2
[str2
.size() - 1] = ' ';
312 str2
.append(str
.at(i
));
316 return str2label(str2
, capitalize
, convert
);
319 Label
LBLFile::label(Handle
&hdl
, quint32 offset
, bool poi
, bool capitalize
,
325 if (!(_poi
.size
>= (offset
<< _poiShift
)
326 && seek(hdl
, _poi
.offset
+ (offset
<< _poiShift
))
327 && readUInt24(hdl
, poiOffset
) && (poiOffset
& 0x3FFFFF)))
329 labelOffset
= _base
.offset
+ ((poiOffset
& 0x3FFFFF) << _shift
);
331 labelOffset
= _base
.offset
+ (offset
<< _shift
);
333 if (labelOffset
> _base
.offset
+ _base
.size
)
335 if (!seek(hdl
, labelOffset
))
338 return label(hdl
, this, hdl
, _base
.offset
+ _base
.size
- labelOffset
,
339 capitalize
, convert
);
342 Label
LBLFile::label(Handle
&hdl
, const SubFile
*file
, Handle
&fileHdl
,
343 quint32 size
, bool capitalize
, bool convert
)
347 return label6b(file
, fileHdl
, size
, capitalize
, convert
);
350 return label8b(file
, fileHdl
, size
, capitalize
, convert
);
352 return labelHuffman(hdl
, file
, fileHdl
, size
, capitalize
, convert
);
358 bool LBLFile::loadRasterTable(Handle
&hdl
, quint32 offset
, quint32 size
,
363 _imgCount
= size
/ recordSize
;
364 _imgIdSize
= byteSize(_imgCount
- 1);
365 _rasters
= new Image
[_imgCount
];
367 if (!(seek(hdl
, offset
) && readVUInt32(hdl
, recordSize
, prev
)))
370 for (quint32 i
= 1; i
< _imgCount
; i
++) {
371 if (!readVUInt32(hdl
, recordSize
, cur
))
374 _rasters
[i
-1].offset
= prev
;
375 _rasters
[i
-1].size
= cur
- prev
;
380 _rasters
[_imgCount
-1].offset
= prev
;
381 _rasters
[_imgCount
-1].size
= _img
.size
- prev
;
386 QPixmap
LBLFile::image(Handle
&hdl
, quint32 id
) const
393 if (!seek(hdl
, _img
.offset
+ _rasters
[id
].offset
))
396 ba
.resize(_rasters
[id
].size
);
397 if (!read(hdl
, ba
.data(), _rasters
[id
].size
))
400 pm
.loadFromData(ba
, "jpeg");