8#include <common_helpers_p.h>
9#include <ktranscript_p.h>
11#include <ktranscript_export.h>
22#include <QJSValueIterator>
25#include <QStandardPaths>
38class KTranscriptImp :
public KTranscript
42 ~KTranscriptImp()
override;
44 QString eval(
const QList<QVariant> &argv,
47 const QString &msgctxt,
48 const QHash<QString, QString> &dynctxt,
50 const QStringList &subs,
51 const QList<QVariant> &vals,
52 const QString &ftrans,
53 QList<QStringList> &mods,
55 bool &fallback)
override;
57 QStringList postCalls(
const QString &lang)
override;
60 QString currentModulePath;
63 void loadModules(
const QList<QStringList> &mods, QString &error);
64 void setupInterpreter(
const QString &lang);
68 QHash<QString, Scriptface *> m_sface;
72class Scriptface :
public QObject
76 explicit Scriptface(
const TsConfigGroup &config,
QObject *
parent =
nullptr);
83 Q_INVOKABLE QJSValue acallInternal(
const QJSValue &args);
97 Q_INVOKABLE QJSValue normKey(
const QJSValue &phrase);
98 Q_INVOKABLE QJSValue loadProps(
const QString &name);
99 Q_INVOKABLE QJSValue getProp(
const QJSValue &phrase,
const QJSValue &prop);
100 Q_INVOKABLE QJSValue setProp(
const QJSValue &phrase,
const QJSValue &prop,
const QJSValue &value);
108 QJSValue load(
const QJSValueList &names);
109 QJSValue loadProps(
const QJSValueList &names);
110 QString loadProps_text(
const QString &fpath);
111 QString loadProps_bin(
const QString &fpath);
112 QString loadProps_bin_00(
const QString &fpath);
113 QString loadProps_bin_01(
const QString &fpath);
115 void put(
const QString &propertyName,
const QJSValue &value);
118 QJSEngine *
const scriptEngine;
121 const QString *msgcontext;
122 const QHash<QString, QString> *dyncontext;
123 const QString *msgId;
124 const QStringList *subList;
125 const QList<QVariant> *valList;
126 const QString *ftrans;
130 bool *fallbackRequest;
133 QHash<QString, QJSValue> funcs;
134 QHash<QString, QJSValue> fvals;
135 QHash<QString, QString> fpaths;
138 QList<QString> nameForalls;
143 QHash<QByteArray, QHash<QByteArray, QByteArray>> phraseProps;
146 struct UnparsedPropInfo {
147 QFile *pmapFile =
nullptr;
150 QHash<QByteArray, UnparsedPropInfo> phraseUnparsedProps;
151 QHash<QByteArray, QByteArray> resolveUnparsedProps(
const QByteArray &phrase);
153 QSet<QString> loadedPmapPaths;
154 QSet<QFile *> loadedPmapHandles;
157 TsConfigGroup config;
162#define DBGP "KTranscript: "
163void dbgout(
const char *str)
166 fprintf(stderr, DBGP
"%s\n", str);
172void dbgout(
const char *str,
const T1 &a1)
175 fprintf(stderr, DBGP
"%s\n",
QString::fromUtf8(str).arg(a1).toLocal8Bit().data());
181template<
typename T1,
typename T2>
182void dbgout(
const char *str,
const T1 &a1,
const T2 &a2)
185 fprintf(stderr, DBGP
"%s\n",
QString::fromUtf8(str).arg(a1).arg(a2).toLocal8Bit().data());
192template<
typename T1,
typename T2,
typename T3>
193void dbgout(
const char *str,
const T1 &a1,
const T2 &a2,
const T3 &a3)
196 fprintf(stderr, DBGP
"%s\n",
QString::fromUtf8(str).arg(a1).arg(a2).arg(a3).toLocal8Bit().data());
205#define WARNP "KTranscript: "
206void warnout(
const char *str)
208 fprintf(stderr, WARNP
"%s\n", str);
211void warnout(
const char *str,
const T1 &a1)
213 fprintf(stderr, WARNP
"%s\n",
QString::fromUtf8(str).arg(a1).toLocal8Bit().data());
224 return QStringLiteral(
"Error: %1").arg(message.
toString());
229 return QStringLiteral(
"Caught exception: %1").
arg(strexpt);
235int countLines(
const QString &s,
int p)
239 for (
int i = 0; i < p && i < len; ++i) {
260 for (
int i = 0; i < len; ++i) {
270 key = removeAcceleratorMarker(key);
293 while (is < len && raw[is].isSpace() && raw[is] !=
QLatin1Char(
'\n')) {
301 while (ie >= 0 && raw[ie].isSpace() && raw[ie] !=
QLatin1Char(
'\n')) {
308 return raw.
mid(is + 1, ie - is - 1);
336TsConfig readConfig(
const QString &fname)
340 TsConfig::iterator configGroup;
348 while (!stream.atEnd()) {
349 QString line = stream.readLine();
371 configGroup = config.
find(group);
372 if (configGroup == config.
end()) {
374 configGroup = config.
insert(group, TsConfigGroup());
401 return engine->
evaluate(QStringLiteral(
"new Error(%1)").arg(message));
404 qCritical() <<
"Script error" << message;
408#ifdef KTRANSCRIPT_TESTBUILD
412static KTranscriptImp *s_transcriptInstance =
nullptr;
414KTranscriptImp *globalKTI()
416 return s_transcriptInstance;
419KTranscript *autotestCreateKTranscriptImp()
421 Q_ASSERT(s_transcriptInstance ==
nullptr);
422 s_transcriptInstance =
new KTranscriptImp;
423 return s_transcriptInstance;
426void autotestDestroyKTranscriptImp()
428 Q_ASSERT(s_transcriptInstance !=
nullptr);
429 delete s_transcriptInstance;
430 s_transcriptInstance =
nullptr;
437Q_GLOBAL_STATIC(KTranscriptImp, globalKTI)
439KTRANSCRIPT_EXPORT KTranscript *load_transcript()
449KTranscriptImp::KTranscriptImp()
455 tsConfigPath =
QDir::homePath() + QLatin1Char(
'/') + QLatin1String(
".transcriptrc");
457 config = readConfig(tsConfigPath);
460KTranscriptImp::~KTranscriptImp()
488 if (geteuid() == 0 && getuid() != 0) {
492 error =
"Security block: trying to execute a script in suid environment.";
499 loadModules(mods, error);
501 if (!
error.isEmpty()) {
510 if (!m_sface.contains(lang)) {
511 setupInterpreter(lang);
515 Scriptface *sface = m_sface[lang];
517 QJSEngine *engine = sface->scriptEngine;
521 sface->msgcontext = &msgctxt;
522 sface->dyncontext = &dynctxt;
523 sface->msgId = &msgid;
524 sface->subList = &subs;
525 sface->valList = &vals;
526 sface->ftrans = &ftrans;
527 sface->fallbackRequest = &fallback;
531 int argc = argv.
size();
538 QString funcName = argv[0].toString();
539 if (!sface->funcs.
contains(funcName)) {
540 error = QStringLiteral(
"Unregistered call to '%1'.").arg(funcName);
544 QJSValue func = sface->funcs[funcName];
545 QJSValue fval = sface->fvals[funcName];
549 currentModulePath = sface->fpaths[funcName];
552 QJSValueList arglist;
554 for (
int i = 1; i < argc; ++i) {
579 error = QStringLiteral(
"Non-string return value: %1").arg(strval);
585 error = expt2str(val);
595 if (!m_sface.contains(lang)) {
596 return QStringList();
600 Scriptface *sface = m_sface[lang];
602 return sface->nameForalls;
607 QList<QString> modErrors;
609 for (
const QStringList &mod : mods) {
610 QString mpath = mod[0];
611 QString mlang = mod[1];
614 if (!m_sface.contains(mlang)) {
615 setupInterpreter(mlang);
622 modErrors.
append(QStringLiteral(
"Funny module path '%1', skipping.").arg(mpath));
625 currentModulePath = mpath.
left(posls);
626 QString fname = mpath.
mid(posls + 1);
632 alist.
append(QJSValue(fname));
634 m_sface[mlang]->load(alist);
638 currentModulePath.
clear();
640 for (
const QString &merr : std::as_const(modErrors)) {
641 error.append(merr + QLatin1Char(
'\n'));
646void KTranscriptImp::setupInterpreter(
const QString &lang)
652 Scriptface *sface =
new Scriptface(config[lang]);
655 m_sface[lang] = sface;
660Scriptface::Scriptface(
const TsConfigGroup &config_,
QObject *parent)
663 , fallbackRequest(nullptr)
666 QJSValue object = scriptEngine->newQObject(
this);
667 scriptEngine->globalObject().
setProperty(QStringLiteral(SFNAME),
object);
668 scriptEngine->evaluate(QStringLiteral(
"Ts.acall = function() { return Ts.acallInternal(Array.prototype.slice.call(arguments)); };"));
671Scriptface::~Scriptface()
673 qDeleteAll(loadedPmapHandles);
674 scriptEngine->deleteLater();
677void Scriptface::put(
const QString &propertyName,
const QJSValue &value)
679 QJSValue internalObject = scriptEngine->globalObject().property(QStringLiteral(
"ScriptfaceInternal"));
681 internalObject = scriptEngine->newObject();
682 scriptEngine->globalObject().
setProperty(QStringLiteral(
"ScriptfaceInternal"), internalObject);
693#define SPREF(X) QString::fromLatin1(SFNAME "." X)
695#define SPREF(X) QStringLiteral(SFNAME "." X)
707 if (!
name.isString()) {
708 return throwError(scriptEngine, SPREF(
"setcall: expected string as first argument"));
711 return throwError(scriptEngine, SPREF(
"setcall: expected function as second argument"));
714 return throwError(scriptEngine, SPREF(
"setcall: expected object or null as third argument"));
717 QString qname =
name.toString();
722 put(QStringLiteral(
"#:f<%1>").arg(qname), func);
723 put(QStringLiteral(
"#:o<%1>").arg(qname), fval);
727 fpaths[qname] = globalKTI()->currentModulePath;
734 return QJSValue(funcs.contains(qname));
739 QJSValueIterator it(args);
742 return throwError(scriptEngine, SPREF(
"acall: expected at least one argument (call name)"));
744 if (!it.value().isString()) {
745 return throwError(scriptEngine, SPREF(
"acall: expected string as first argument (call name)"));
748 QString callname = it.value().toString();
749 if (!funcs.contains(callname)) {
750 return throwError(scriptEngine, SPREF(
"acall: unregistered call to '%1'").arg(callname));
752 QJSValue func = funcs[callname];
753 QJSValue fval = fvals[callname];
757 globalKTI()->currentModulePath = fpaths[callname];
760 QJSValueList arglist;
762 arglist.append(it.value());
778 if (!
name.isString()) {
779 return throwError(scriptEngine, SPREF(
"setcallForall: expected string as first argument"));
782 return throwError(scriptEngine, SPREF(
"setcallForall: expected function as second argument"));
785 return throwError(scriptEngine, SPREF(
"setcallForall: expected object or null as third argument"));
788 QString qname =
name.toString();
793 put(QStringLiteral(
"#:fall<%1>").arg(qname), func);
794 put(QStringLiteral(
"#:oall<%1>").arg(qname), fval);
798 fpaths[qname] = globalKTI()->currentModulePath;
801 nameForalls.append(qname);
808 if (fallbackRequest) {
809 *fallbackRequest =
true;
816 return QJSValue(
static_cast<int>(subList->size()));
822 return throwError(scriptEngine, SPREF(
"subs: expected number as first argument"));
826 if (i < 0 || i >= subList->size()) {
827 return throwError(scriptEngine, SPREF(
"subs: index out of range"));
830 return QJSValue(subList->at(i));
836 return throwError(scriptEngine, SPREF(
"vals: expected number as first argument"));
840 if (i < 0 || i >= valList->size()) {
841 return throwError(scriptEngine, SPREF(
"vals: index out of range"));
844 return scriptEngine->toScriptValue(valList->at(i));
850 return QJSValue(*msgcontext);
855 auto valIt = dyncontext->constFind(qkey);
856 if (valIt != dyncontext->constEnd()) {
857 return QJSValue(*valIt);
864 return QJSValue(*msgId);
869 return QJSValue(QString(*msgcontext + QLatin1Char(
'|') + *msgId));
874 return QJSValue(*ftrans);
877void Scriptface::dbgputs(
const QString &qstr)
879 dbgout(
"[JS-debug] %1", qstr);
882void Scriptface::warnputs(
const QString &qstr)
884 warnout(
"[JS-warning] %1", qstr);
889 return QJSValue(*ctry);
895 return throwError(scriptEngine, SPREF(
"normKey: expected string as argument"));
898 QByteArray nqphrase = normKeystr(phrase.
toString());
906 return loadProps(fnames);
909QJSValue Scriptface::loadProps(
const QJSValueList &fnames)
911 if (globalKTI()->currentModulePath.isEmpty()) {
912 return throwError(scriptEngine, SPREF(
"loadProps: no current module path, aiiie..."));
915 for (
int i = 0; i < fnames.size(); ++i) {
916 if (!fnames[i].isString()) {
917 return throwError(scriptEngine, SPREF(
"loadProps: expected string as file name"));
921 for (
int i = 0; i < fnames.size(); ++i) {
922 QString qfname = fnames[i].toString();
923 QString qfpath_base = globalKTI()->currentModulePath + QLatin1Char(
'/') + qfname;
927 QString qfpath = qfpath_base + QLatin1String(
".pmapc");
928 bool haveCompiled =
true;
929 QFile file_check(qfpath);
931 haveCompiled =
false;
932 qfpath = qfpath_base + QLatin1String(
".pmap");
933 QFile file_check(qfpath);
935 return throwError(scriptEngine, SPREF(
"loadProps: cannot read map '%1'").arg(qfpath));
941 if (!loadedPmapPaths.contains(qfpath)) {
944 errorString = loadProps_bin(qfpath);
946 errorString = loadProps_text(qfpath);
949 return throwError(scriptEngine, errorString);
951 dbgout(
"Loaded property map: %1", qfpath);
952 loadedPmapPaths.insert(qfpath);
962 return throwError(scriptEngine, SPREF(
"getProp: expected string as first argument"));
965 return throwError(scriptEngine, SPREF(
"getProp: expected string as second argument"));
968 QByteArray qphrase = normKeystr(phrase.
toString());
969 QHash<QByteArray, QByteArray> props = phraseProps.value(qphrase);
971 props = resolveUnparsedProps(qphrase);
974 QByteArray qprop = normKeystr(prop.
toString());
975 QByteArray qval = props.
value(qprop);
986 return throwError(scriptEngine, SPREF(
"setProp: expected string as first argument"));
989 return throwError(scriptEngine, SPREF(
"setProp: expected string as second argument"));
992 return throwError(scriptEngine, SPREF(
"setProp: expected string as third argument"));
995 QByteArray qphrase = normKeystr(phrase.
toString());
996 QByteArray qprop = normKeystr(prop.
toString());
999 phraseProps[qphrase][qprop] = qvalue;
1003static QString toCaseFirst(
const QString &qstr,
int qnalt,
bool toupper)
1006 static const int hlen = 2;
1011 const int len = qstr.
length();
1013 int remainingAlts = 0;
1014 bool checkCase =
true;
1020 if (qnalt && !remainingAlts &&
QStringView(qstr).mid(i, hlen) == head) {
1029 remainingAlts = qnalt;
1031 }
else if (remainingAlts && c == altSep) {
1036 }
else if (checkCase && c.
isLetter()) {
1050 if (numChcased > 0 && remainingAlts == 0) {
1064 return throwError(scriptEngine, SPREF(
"toUpperFirst: expected string as first argument"));
1067 return throwError(scriptEngine, SPREF(
"toUpperFirst: expected number as second argument"));
1073 QString qstruc = toCaseFirst(qstr, qnalt,
true);
1075 return QJSValue(qstruc);
1081 return throwError(scriptEngine, SPREF(
"toLowerFirst: expected string as first argument"));
1084 return throwError(scriptEngine, SPREF(
"toLowerFirst: expected number as second argument"));
1090 QString qstrlc = toCaseFirst(qstr, qnalt,
false);
1092 return QJSValue(qstrlc);
1098 return throwError(scriptEngine, QStringLiteral(
"getConfString: expected string as first argument"));
1101 return throwError(scriptEngine, SPREF(
"getConfString: expected string as second argument (when given)"));
1105 auto valIt = config.constFind(qkey);
1106 if (valIt != config.constEnd()) {
1107 return QJSValue(*valIt);
1116 return throwError(scriptEngine, SPREF(
"getConfBool: expected string as first argument"));
1119 return throwError(scriptEngine, SPREF(
"getConfBool: expected boolean as second argument (when given)"));
1122 static QStringList falsities;
1124 falsities.
append(QString(QLatin1Char(
'0')));
1125 falsities.
append(QStringLiteral(
"no"));
1126 falsities.
append(QStringLiteral(
"false"));
1130 auto valIt = config.constFind(qkey);
1131 if (valIt != config.constEnd()) {
1132 QString qval = valIt->
toLower();
1133 return QJSValue(!falsities.
contains(qval));
1142 return throwError(scriptEngine,
1143 SPREF(
"getConfNumber: expected string "
1144 "as first argument"));
1147 return throwError(scriptEngine,
1148 SPREF(
"getConfNumber: expected number "
1149 "as second argument (when given)"));
1153 auto valIt = config.constFind(qkey);
1154 if (valIt != config.constEnd()) {
1155 const QString &qval = *valIt;
1157 double qnum = qval.
toDouble(&convOk);
1159 return QJSValue(qnum);
1169QJSValue Scriptface::load(
const QJSValueList &fnames)
1171 if (globalKTI()->currentModulePath.isEmpty()) {
1172 return throwError(scriptEngine, SPREF(
"load: no current module path, aiiie..."));
1175 for (
int i = 0; i < fnames.size(); ++i) {
1176 if (!fnames[i].isString()) {
1177 return throwError(scriptEngine, SPREF(
"load: expected string as file name"));
1181 for (
int i = 0; i < fnames.size(); ++i) {
1182 QString qfname = fnames[i].toString();
1183 QString qfpath = globalKTI()->currentModulePath + QLatin1Char(
'/') + qfname + QLatin1String(
".js");
1187 return throwError(scriptEngine, SPREF(
"load: cannot read file '%1'").arg(qfpath));
1190 QTextStream stream(&file);
1191 QString source = stream.readAll();
1194 QJSValue comp = scriptEngine->evaluate(source, qfpath, 0);
1201 QJSValue lval = comp.
property(QStringLiteral(
"line"));
1207 return throwError(scriptEngine, QStringLiteral(
"at %1:%2: %3").arg(qfpath, line, msg));
1209 dbgout(
"Loaded module: %1", qfpath);
1218 return SPREF(
"loadProps_text: cannot read file '%1'").arg(fpath);
1220 QTextStream stream(&file);
1221 QString s = stream.readAll();
1227 enum { s_nextEntry, s_nextKey, s_nextValue };
1228 QList<QByteArray> ekeys;
1229 QHash<QByteArray, QByteArray> props;
1231 int state = s_nextEntry;
1237 int i_checkpoint = i;
1239 if (state == s_nextEntry) {
1240 while (s[i].isSpace()) {
1243 goto END_PROP_PARSE;
1246 if (i + 1 >= slen) {
1247 return SPREF(
"loadProps_text: unexpected end of file in %1").arg(fpath);
1249 if (s[i] != QLatin1Char(
'#')) {
1252 prop_sep = s[i + 1];
1254 return SPREF(
"loadProps_text: separator characters must not be letters at %1:%2").arg(fpath).arg(countLines(s, i));
1266 while (s[i] != QLatin1Char(
'\n')) {
1269 goto END_PROP_PARSE;
1273 }
else if (state == s_nextKey) {
1276 while (s[i] != key_sep && s[i] != prop_sep) {
1279 goto END_PROP_PARSE;
1282 if (s[i] == key_sep) {
1285 pkey = normKeystr(s.
mid(ip, i - ip),
false);
1288 state = s_nextValue;
1291 QByteArray ekey = normKeystr(s.
mid(ip, i - ip),
false);
1300 if (ekeys.
size() < 1) {
1301 return SPREF(
"loadProps_text: no entry key for entry ending at %1:%2").arg(fpath).arg(countLines(s, i));
1306 for (
const QByteArray &ekey : std::as_const(ekeys)) {
1307 phraseProps[ekey] = props;
1311 state = s_nextEntry;
1314 }
else if (state == s_nextValue) {
1317 while (s[i] != prop_sep) {
1320 goto END_PROP_PARSE;
1322 if (s[i] == key_sep) {
1323 return SPREF(
"loadProps_text: property separator inside property value at %1:%2").arg(fpath).arg(countLines(s, i));
1327 QByteArray pval = trimSmart(s.
mid(ip, i - ip)).
toUtf8();
1333 return SPREF(
"loadProps: internal error 10 at %1:%2").arg(fpath).arg(countLines(s, i));
1337 if (i == i_checkpoint || i >= slen) {
1338 return SPREF(
"loadProps: internal error 20 at %1:%2").arg(fpath).arg(countLines(s, i));
1344 if (state != s_nextEntry) {
1345 return SPREF(
"loadProps: unexpected end of file in %1").arg(fpath);
1356static int bin_read_int_nbytes(
const char *fc, qlonglong len, qlonglong &pos,
int nbytes)
1358 if (pos + nbytes > len) {
1362 T num = qFromBigEndian<T>((uchar *)fc + pos);
1368static quint64 bin_read_int64(
const char *fc, qlonglong len, qlonglong &pos)
1370 return bin_read_int_nbytes<quint64>(fc, len, pos, 8);
1374static quint32 bin_read_int(
const char *fc, qlonglong len, qlonglong &pos)
1376 return bin_read_int_nbytes<quint32>(fc, len, pos, 4);
1383static QByteArray bin_read_string(
const char *fc, qlonglong len, qlonglong &pos)
1387 int nbytes = bin_read_int(fc, len, pos);
1391 if (nbytes < 0 || pos + nbytes > len) {
1404 return SPREF(
"loadProps: cannot read file '%1'").arg(fpath);
1407 QByteArray head(8,
'0');
1408 file.read(head.data(), head.size());
1412 if (head ==
"TSPMAP00") {
1413 return loadProps_bin_00(fpath);
1414 }
else if (head ==
"TSPMAP01") {
1415 return loadProps_bin_01(fpath);
1417 return SPREF(
"loadProps: unknown version of compiled map '%1'").arg(fpath);
1425 return SPREF(
"loadProps: cannot read file '%1'").arg(fpath);
1427 QByteArray fctmp = file.readAll();
1429 const char *fc = fctmp.
data();
1430 const int fclen = fctmp.
size();
1436 QByteArray head(fc, 8);
1438 if (head !=
"TSPMAP00") {
1439 goto END_PROP_PARSE;
1444 nentries = bin_read_int(fc, fclen, pos);
1446 goto END_PROP_PARSE;
1450 for (
int i = 0; i < nentries; ++i) {
1452 QList<QByteArray> ekeys;
1453 int nekeys = bin_read_int(fc, fclen, pos);
1455 goto END_PROP_PARSE;
1458 for (
int j = 0; j < nekeys; ++j) {
1459 QByteArray ekey = bin_read_string(fc, fclen, pos);
1461 goto END_PROP_PARSE;
1468 QHash<QByteArray, QByteArray> props;
1469 int nprops = bin_read_int(fc, fclen, pos);
1471 goto END_PROP_PARSE;
1473 for (
int j = 0; j < nprops; ++j) {
1474 QByteArray pkey = bin_read_string(fc, fclen, pos);
1476 goto END_PROP_PARSE;
1478 QByteArray pval = bin_read_string(fc, fclen, pos);
1480 goto END_PROP_PARSE;
1487 for (
const QByteArray &ekey : std::as_const(ekeys)) {
1488 phraseProps[ekey] = props;
1495 return SPREF(
"loadProps: corrupt compiled map '%1'").arg(fpath);
1503 QFile *file =
new QFile(fpath);
1505 return SPREF(
"loadProps: cannot read file '%1'").arg(fpath);
1512 fstr = file->
read(8 + 4 + 8);
1514 QByteArray head = fstr.
left(8);
1516 if (head !=
"TSPMAP01") {
1517 return SPREF(
"loadProps: corrupt compiled map '%1'").arg(fpath);
1519 quint32 numekeys = bin_read_int(fstr, fstr.
size(), pos);
1520 quint64 lenekeys = bin_read_int64(fstr, fstr.
size(), pos);
1523 fstr = file->
read(lenekeys);
1525 for (quint32 i = 0; i < numekeys; ++i) {
1526 QByteArray ekey = bin_read_string(fstr, lenekeys, pos);
1527 quint64 offset = bin_read_int64(fstr, lenekeys, pos);
1528 phraseUnparsedProps[ekey] = {file, offset};
1534 loadedPmapHandles.
insert(file);
1540 auto [file, offset] = phraseUnparsedProps.
value(phrase);
1541 QHash<QByteArray, QByteArray> props;
1542 if (file && file->
seek(offset)) {
1543 QByteArray fstr = file->
read(4 + 4);
1545 quint32 numpkeys = bin_read_int(fstr, fstr.
size(), pos);
1546 quint32 lenpkeys = bin_read_int(fstr, fstr.
size(), pos);
1547 fstr = file->
read(lenpkeys);
1549 for (quint32 i = 0; i < numpkeys; ++i) {
1550 QByteArray pkey = bin_read_string(fstr, lenpkeys, pos);
1551 QByteArray pval = bin_read_string(fstr, lenpkeys, pos);
1554 phraseProps[phrase] = props;
1555 phraseUnparsedProps.
remove(phrase);
1560#include "ktranscript.moc"
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
QString name(StandardAction id)
QCA_EXPORT void setProperty(const QString &name, const QVariant &value)
QByteArray & insert(qsizetype i, QByteArrayView data)
bool isEmpty() const const
QByteArray left(qsizetype len) const const
qsizetype size() const const
QByteArray toLower() const const
bool isLetter(char32_t ucs4)
bool isSpace(char32_t ucs4)
char32_t toLower(char32_t ucs4)
char32_t toUpper(char32_t ucs4)
bool open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags)
virtual bool seek(qint64 pos) override
bool contains(const Key &key) const const
iterator find(const Key &key)
iterator insert(const Key &key, const T &value)
bool isEmpty() const const
bool remove(const Key &key)
void reserve(qsizetype size)
T value(const Key &key) const const
QByteArray read(qint64 maxSize)
QJSValue evaluate(const QString &program, const QString &fileName, int lineNumber, QStringList *exceptionStackTrace)
QJSValue globalObject() const const
QJSValue toScriptValue(const T &value)
QJSValue callWithInstance(const QJSValue &instance, const QJSValueList &args) const const
bool isBool() const const
bool isCallable() const const
bool isError() const const
bool isNull() const const
bool isNumber() const const
bool isObject() const const
bool isString() const const
bool isUndefined() const const
QJSValue property(const QString &name) const const
void setProperty(const QString &name, const QJSValue &value)
qint32 toInt() const const
double toNumber() const const
QString toString() const const
void append(QList< T > &&value)
bool isEmpty() const const
void reserve(qsizetype size)
qsizetype size() const const
QObject * parent() const const
QString locate(StandardLocation type, const QString &fileName, LocateOptions options)
QString & append(QChar ch)
QString arg(Args &&... args) const const
QString fromUtf8(QByteArrayView str)
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
qsizetype lastIndexOf(QChar ch, Qt::CaseSensitivity cs) const const
QString left(qsizetype n) const const
qsizetype length() const const
QString mid(qsizetype position, qsizetype n) const const
QString number(double n, char format, int precision)
double toDouble(bool *ok) const const
QString toLower() const const
QByteArray toUtf8() const const
QString trimmed() const const
void truncate(qsizetype position)
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
QStringView left(qsizetype length) const const
QStringView mid(qsizetype start, qsizetype length) const const
bool isEmpty() const const
QString toString() const const
QStringView trimmed() const const
bool toBool() const const
double toDouble(bool *ok) const const
QString toString() const const
int userType() const const