2019-05-10 18:56:19 +02:00
|
|
|
#include <QTextCodec>
|
|
|
|
#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', '~', '~', '~', '~', '~', '~'
|
|
|
|
};
|
|
|
|
|
|
|
|
static QString capitalize(const QString &str)
|
|
|
|
{
|
|
|
|
if (str.isEmpty())
|
|
|
|
return str;
|
|
|
|
for (int i = 0; i < str.size(); i++)
|
2019-07-28 10:31:03 +02:00
|
|
|
if (str.at(i).isLetter() && !(str.at(i).isUpper()
|
|
|
|
|| str.at(i) == QChar(0x00DF)))
|
2019-05-10 18:56:19 +02:00
|
|
|
return str;
|
|
|
|
|
|
|
|
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
|
|
|
|
2020-01-11 23:41:04 +01:00
|
|
|
bool LBLFile::init(Handle &hdl)
|
2019-05-10 18:56:19 +02:00
|
|
|
{
|
|
|
|
quint16 codepage;
|
2019-08-12 22:20:12 +02:00
|
|
|
quint8 multiplier, poiMultiplier;
|
2019-05-10 18:56:19 +02:00
|
|
|
|
2019-09-05 22:31:13 +02:00
|
|
|
if (!(seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset)
|
2020-01-21 21:50:13 +01:00
|
|
|
&& readUInt32(hdl, _size) && readUInt8(hdl, multiplier)
|
|
|
|
&& readUInt8(hdl, _encoding) && seek(hdl, _gmpOffset + 0x57)
|
2019-05-10 18:56:19 +02:00
|
|
|
&& readUInt32(hdl, _poiOffset) && readUInt32(hdl, _poiSize)
|
2020-01-21 21:50:13 +01:00
|
|
|
&& readUInt8(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;
|
|
|
|
|
2019-08-12 22:20:12 +02:00
|
|
|
_multiplier = 1<<multiplier;
|
|
|
|
_poiMultiplier = 1<<poiMultiplier;
|
2019-05-10 18:56:19 +02:00
|
|
|
|
|
|
|
if (codepage == 65001)
|
|
|
|
_codec = QTextCodec::codecForName("UTF-8");
|
|
|
|
else if (codepage == 0)
|
|
|
|
_codec = 0;
|
|
|
|
else
|
|
|
|
_codec = QTextCodec::codecForName(QString("CP%1").arg(codepage)
|
|
|
|
.toLatin1());
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-06-30 20:39:22 +02:00
|
|
|
Label LBLFile::label6b(Handle &hdl, quint32 offset) 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) {
|
2020-01-21 21:50:13 +01:00
|
|
|
if (!(readUInt8(hdl, b1) && readUInt8(hdl, b2) && readUInt8(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++) {
|
2019-06-30 20:39:22 +02:00
|
|
|
if (c[cpt] > 0x2f || (curCharSet == Normal && c[cpt] == 0x1d))
|
|
|
|
return Label(capitalize(QString::fromLatin1(label)),
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-30 20:39:22 +02:00
|
|
|
Label LBLFile::label8b(Handle &hdl, quint32 offset) 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
|
|
|
quint8 c;
|
|
|
|
|
|
|
|
if (!seek(hdl, offset))
|
2019-06-30 20:39:22 +02:00
|
|
|
return Label();
|
2019-05-10 18:56:19 +02:00
|
|
|
|
|
|
|
while (true) {
|
2020-01-21 21:50:13 +01:00
|
|
|
if (!readUInt8(hdl, c))
|
2019-06-30 20:39:22 +02:00
|
|
|
return Label();
|
|
|
|
if (!c || c == 0x1d)
|
2019-05-10 18:56:19 +02:00
|
|
|
break;
|
|
|
|
|
2019-06-30 23:18:30 +02:00
|
|
|
if ((c >= 0x1e && c <= 0x1f)) {
|
|
|
|
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 && QChar(c).isSpace()) {
|
|
|
|
bap = &label;
|
|
|
|
} else
|
|
|
|
bap->append(c);
|
2019-05-10 18:56:19 +02:00
|
|
|
}
|
|
|
|
|
2019-06-30 20:39:22 +02:00
|
|
|
return Label(capitalize(_codec ? _codec->toUnicode(label)
|
|
|
|
: QString::fromLatin1(label)), Label::Shield(shieldType, _codec
|
|
|
|
? _codec->toUnicode(shieldLabel) : QString::fromLatin1(shieldLabel)));
|
2019-05-10 18:56:19 +02:00
|
|
|
}
|
|
|
|
|
2019-06-30 20:39:22 +02:00
|
|
|
Label LBLFile::label(Handle &hdl, quint32 offset, bool poi)
|
2019-05-10 18:56:19 +02:00
|
|
|
{
|
2020-01-11 23:41:04 +01:00
|
|
|
if (!_multiplier && !init(hdl))
|
2019-07-04 09:05:30 +02:00
|
|
|
return QString();
|
2019-05-10 18:56:19 +02:00
|
|
|
|
|
|
|
quint32 labelOffset;
|
|
|
|
if (poi) {
|
|
|
|
quint32 poiOffset;
|
2019-08-12 22:20:12 +02:00
|
|
|
if (!(_poiSize >= offset * _poiMultiplier
|
|
|
|
&& seek(hdl, _poiOffset + offset * _poiMultiplier)
|
|
|
|
&& readUInt24(hdl, poiOffset) && (poiOffset & 0x3FFFFF)))
|
2019-05-10 18:56:19 +02:00
|
|
|
return QString();
|
|
|
|
labelOffset = _offset + (poiOffset & 0x3FFFFF) * _multiplier;
|
|
|
|
} else
|
|
|
|
labelOffset = _offset + offset * _multiplier;
|
|
|
|
|
|
|
|
if (labelOffset > _offset + _size)
|
|
|
|
return QString();
|
|
|
|
|
|
|
|
switch (_encoding) {
|
|
|
|
case 6:
|
2019-06-30 20:39:22 +02:00
|
|
|
return label6b(hdl, labelOffset);
|
2019-05-10 18:56:19 +02:00
|
|
|
case 9:
|
|
|
|
case 10:
|
2019-06-30 20:39:22 +02:00
|
|
|
return label8b(hdl, labelOffset);
|
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
|
|
|
}
|
|
|
|
}
|