1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-10-07 23:33:21 +02:00
GPXSee/src/map/IMG/lblfile.cpp

346 lines
8.2 KiB
C++
Raw Normal View History

#include "huffmantext.h"
#include "rgnfile.h"
2019-05-10 18:56:19 +02:00
#include "lblfile.h"
enum Charset {Normal, Symbol, Special};
static quint8 NORMAL_CHARS[] = {
' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
2019-06-30 20:39:22 +02:00
'X', 'Y', 'Z', '~', '~', '~', ' ', ' ',
2019-05-10 18:56:19 +02:00
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '~', '~', '~', '~', '~', '~'
};
static quint8 SYMBOL_CHARS[] = {
'@', '!', '"', '#', '$', '%', '&', '\'',
'(', ')', '*', '+', ',', '-', '.', '/',
'~', '~', '~', '~', '~', '~', '~', '~',
'~', '~', ':', ';', '<', '=', '>', '?',
'~', '~', '~', '~', '~', '~', '~', '~',
'~', '~', '~', '[', '\\', ']', '^', '_'
};
static quint8 SPECIAL_CHARS[] = {
'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
'x', 'y', 'z', '~', '~', '~', '~', '~',
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '~', '~', '~', '~', '~', '~'
};
2020-02-16 12:57:40 +01:00
static bool isAllUpperCase(const QString &str)
2019-05-10 18:56:19 +02:00
{
if (str.isEmpty())
2020-02-16 12:57:40 +01:00
return false;
2019-05-10 18:56:19 +02:00
for (int i = 0; i < str.size(); i++)
if (str.at(i).isLetter() && !(str.at(i).isUpper()
|| str.at(i) == QChar(0x00DF)))
2020-02-16 12:57:40 +01:00
return false;
return true;
}
2019-05-10 18:56:19 +02:00
2020-02-16 12:57:40 +01:00
static QString capitalized(const QString &str)
{
2019-05-10 18:56:19 +02:00
QString ret(str);
for (int i = 0; i < str.size(); i++)
if (i && !str.at(i-1).isSpace())
ret[i] = str.at(i).toLower();
else
ret[i] = str.at(i);
return ret;
}
2019-06-30 20:39:22 +02:00
LBLFile::~LBLFile()
2019-05-10 18:56:19 +02:00
{
delete _huffmanText;
2021-02-01 20:06:05 +01:00
delete[] _table;
}
bool LBLFile::load(Handle &hdl, const RGNFile *rgn, Handle &rgnHdl)
{
quint16 hdrLen, codepage;
2019-05-10 18:56:19 +02:00
if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen)
&& seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset)
2021-02-01 20:06:05 +01:00
&& readUInt32(hdl, _size) && readByte(hdl, &_multiplier)
&& readByte(hdl, &_encoding) && seek(hdl, _gmpOffset + 0x57)
2019-05-10 18:56:19 +02:00
&& readUInt32(hdl, _poiOffset) && readUInt32(hdl, _poiSize)
2021-02-01 20:06:05 +01:00
&& readByte(hdl, &_poiMultiplier) && seek(hdl, _gmpOffset + 0xAA)
2019-08-12 22:20:12 +02:00
&& readUInt16(hdl, codepage)))
2019-05-10 18:56:19 +02:00
return false;
if (hdrLen >= 0x132) {
quint32 offset, size;
quint16 recordSize;
if (!(seek(hdl, _gmpOffset + 0x124) && readUInt32(hdl, offset)
&& readUInt32(hdl, size) && readUInt16(hdl, recordSize)))
return false;
if (size && recordSize) {
_table = new quint32[size / recordSize];
if (!seek(hdl, offset))
return false;
for (quint32 i = 0; i < size / recordSize; i++) {
if (!readVUInt32(hdl, recordSize, _table[i]))
return false;
}
}
}
if (hdrLen >= 0x19A) {
2021-01-27 21:18:06 +01:00
quint32 offset, recordSize, size, flags;
if (!(seek(hdl, _gmpOffset + 0x184) && readUInt32(hdl, offset)
&& readUInt32(hdl, size) && readUInt16(hdl, recordSize)
2021-01-25 23:01:36 +01:00
&& readUInt32(hdl, flags) && readUInt32(hdl, _imgOffset)
&& readUInt32(hdl, _imgSize)))
return false;
2021-01-27 21:18:06 +01:00
quint32 count = size ? size / recordSize : 0;
2021-01-27 21:18:06 +01:00
quint32 maxId = count - 1;
_imgOffsetIdSize = 0;
do {
_imgOffsetIdSize++;
maxId = maxId >> 8;
} while (maxId != 0);
2021-01-27 21:18:06 +01:00
if (!loadFiles(hdl, count, offset, recordSize))
return false;
}
if (_encoding == 11) {
_huffmanText = new HuffmanText();
if (!_huffmanText->load(rgn, rgnHdl))
return false;
}
2019-05-10 18:56:19 +02:00
_codec = TextCodec(codepage);
2019-05-10 18:56:19 +02:00
return true;
}
void LBLFile::clear()
{
delete _huffmanText;
2021-02-01 20:06:05 +01:00
delete[] _table;
_huffmanText = 0;
_table = 0;
}
2020-02-16 12:57:40 +01:00
Label LBLFile::label6b(Handle &hdl, quint32 offset, bool capitalize) const
2019-05-10 18:56:19 +02:00
{
2019-06-30 20:39:22 +02:00
Label::Shield::Type shieldType = Label::Shield::None;
QByteArray label, shieldLabel;
QByteArray *bap = &label;
2019-05-10 18:56:19 +02:00
Charset curCharSet = Normal;
quint8 b1, b2, b3;
if (!seek(hdl, offset))
2019-06-30 20:39:22 +02:00
return Label();
2019-05-10 18:56:19 +02:00
while (true) {
2021-02-01 20:06:05 +01:00
if (!(readByte(hdl, &b1) && readByte(hdl, &b2) && readByte(hdl, &b3)))
2019-06-30 20:39:22 +02:00
return Label();
2019-05-10 18:56:19 +02:00
int c[]= {b1>>2, (b1&0x3)<<4|b2>>4, (b2&0xF)<<2|b3>>6, b3&0x3F};
for (int cpt = 0; cpt < 4; cpt++) {
2020-02-16 12:57:40 +01:00
if (c[cpt] > 0x2f || (curCharSet == Normal && c[cpt] == 0x1d)) {
QString text(QString::fromLatin1(label));
2020-02-16 13:59:19 +01:00
return Label(capitalize && isAllUpperCase(text)
2020-02-16 12:57:40 +01:00
? capitalized(text) : text, Label::Shield(shieldType,
shieldLabel));
}
2019-05-10 18:56:19 +02:00
switch (curCharSet) {
case Normal:
if (c[cpt] == 0x1c)
curCharSet = Symbol;
else if (c[cpt] == 0x1b)
curCharSet = Special;
2019-06-30 20:39:22 +02:00
else if (c[cpt] >= 0x2a && c[cpt] <= 0x2f) {
2019-07-10 21:37:03 +02:00
shieldType = static_cast<Label::Shield::Type>
(c[cpt] - 0x29);
2019-06-30 20:39:22 +02:00
bap = &shieldLabel;
} else if (bap == &shieldLabel
&& NORMAL_CHARS[c[cpt]] == ' ')
bap = &label;
2019-05-10 18:56:19 +02:00
else
2019-06-30 20:39:22 +02:00
bap->append(NORMAL_CHARS[c[cpt]]);
2019-05-10 18:56:19 +02:00
break;
case Symbol:
2019-06-30 20:39:22 +02:00
bap->append(SYMBOL_CHARS[c[cpt]]);
2019-05-10 18:56:19 +02:00
curCharSet = Normal;
break;
case Special:
2019-06-30 20:39:22 +02:00
bap->append(SPECIAL_CHARS[c[cpt]]);
2019-05-10 18:56:19 +02:00
curCharSet = Normal;
break;
}
}
}
}
Label LBLFile::str2label(const QVector<quint8> &str, bool capitalize) const
2019-05-10 18:56:19 +02:00
{
2019-06-30 20:39:22 +02:00
Label::Shield::Type shieldType = Label::Shield::None;
QByteArray label, shieldLabel;
QByteArray *bap = &label;
2019-05-10 18:56:19 +02:00
for (int i = 0; i < str.size(); i++) {
const quint8 &c = str.at(i);
2019-05-10 18:56:19 +02:00
if (c == 0 || c == 0x1d)
2019-05-10 18:56:19 +02:00
break;
2020-04-18 00:00:48 +02:00
if (c == 0x1c)
capitalize = false;
else if ((c >= 0x1e && c <= 0x1f)) {
2019-06-30 23:18:30 +02:00
if (bap == &shieldLabel)
bap = &label;
else
bap->append(' ');
} else if (c < 0x07) {
2019-07-10 21:37:03 +02:00
shieldType = static_cast<Label::Shield::Type>(c);
2019-06-30 20:39:22 +02:00
bap = &shieldLabel;
} else if (bap == &shieldLabel && c == 0x20) {
2019-06-30 20:39:22 +02:00
bap = &label;
} else
bap->append(c);
2019-05-10 18:56:19 +02:00
}
QString text(_codec.toString(label));
2020-02-16 12:57:40 +01:00
return Label(capitalize && isAllUpperCase(text) ? capitalized(text) : text,
Label::Shield(shieldType, _codec.toString(shieldLabel)));
2019-05-10 18:56:19 +02:00
}
Label LBLFile::label8b(Handle &hdl, quint32 offset, bool capitalize) const
2019-05-10 18:56:19 +02:00
{
QVector<quint8> str;
quint8 c;
2019-05-10 18:56:19 +02:00
if (!seek(hdl, offset))
return Label();
do {
2021-02-01 20:06:05 +01:00
if (!readByte(hdl, &c))
return Label();
str.append(c);
} while (c);
return str2label(str, capitalize);
}
Label LBLFile::labelHuffman(Handle &hdl, quint32 offset, bool capitalize) const
{
QVector<quint8> str;
if (!seek(hdl, offset))
return Label();
if (!_huffmanText->decode(this, hdl, str))
return Label();
if (!_table)
return str2label(str, capitalize);
QVector<quint8> str2;
for (int i = 0; i < str.size(); i++) {
quint32 val = _table[str.at(i)];
if (val) {
if (!seek(hdl, _offset + ((val & 0x7fffff) << _multiplier)))
return Label();
if (str2.size() && str2.back() == '\0')
str2[str2.size() - 1] = ' ';
else if (str2.size())
str2.append(' ');
if (!_huffmanText->decode(this, hdl, str2))
return Label();
} else {
if (str.at(i) == 7) {
str2.append(0);
break;
}
if (str2.size() && str2.back() == '\0')
str2[str2.size() - 1] = ' ';
str2.append(str.at(i));
}
}
return str2label(str2, capitalize);
}
Label LBLFile::label(Handle &hdl, quint32 offset, bool poi, bool capitalize) const
{
2019-05-10 18:56:19 +02:00
quint32 labelOffset;
if (poi) {
quint32 poiOffset;
if (!(_poiSize >= (offset << _poiMultiplier)
&& seek(hdl, _poiOffset + (offset << _poiMultiplier))
2019-08-12 22:20:12 +02:00
&& readUInt24(hdl, poiOffset) && (poiOffset & 0x3FFFFF)))
2019-05-10 18:56:19 +02:00
return QString();
labelOffset = _offset + ((poiOffset & 0x3FFFFF) << _multiplier);
2019-05-10 18:56:19 +02:00
} else
labelOffset = _offset + (offset << _multiplier);
2019-05-10 18:56:19 +02:00
if (labelOffset > _offset + _size)
return QString();
switch (_encoding) {
case 6:
2020-02-16 12:57:40 +01:00
return label6b(hdl, labelOffset, capitalize);
2019-05-10 18:56:19 +02:00
case 9:
case 10:
2020-02-16 12:57:40 +01:00
return label8b(hdl, labelOffset, capitalize);
case 11:
return labelHuffman(hdl, labelOffset, capitalize);
2019-05-10 18:56:19 +02:00
default:
2019-06-30 20:39:22 +02:00
return Label();
2019-05-10 18:56:19 +02:00
}
}
2021-01-27 21:18:06 +01:00
bool LBLFile::loadFiles(Handle &hdl, quint32 count, quint32 offset,
quint32 recordSize)
{
2021-01-27 21:18:06 +01:00
_rasters.resize(count);
for (quint32 i = 0; i < count; i++) {
quint32 currentOffset, nextOffset, size;
if (!(seek(hdl, offset + i * recordSize)
&& readVUInt32(hdl, recordSize, currentOffset)))
return false;
if (i == count - 1)
nextOffset = _imgSize;
else {
if (!readVUInt32(hdl, recordSize, nextOffset))
return false;
}
size = nextOffset - currentOffset;
_rasters[i] = File(currentOffset, size);
}
2021-01-27 21:18:06 +01:00
return true;
}
QImage LBLFile::readImage(Handle &hdl, quint32 id) const
{
if (id >= (quint32)_rasters.size())
return QImage();
if (!seek(hdl, _imgOffset + _rasters.at(id).offset))
return QImage();
QByteArray ba;
2021-01-27 21:18:06 +01:00
ba.resize(_rasters.at(id).size);
2021-02-03 22:56:30 +01:00
if (!read(hdl, ba.data(), _rasters.at(id).size))
2021-02-03 22:16:00 +01:00
return QImage();
2021-01-27 21:18:06 +01:00
return QImage::fromData(ba);
}