15 #include <QRegularExpression>
16 #include <QRegularExpressionMatch>
19 #include "../../util/btassert.h"
20 #include "../config/btconfig.h"
21 #include "../drivers/cswordmoduleinfo.h"
22 #include "../managers/cswordbackend.h"
23 #include "../managers/referencemanager.h"
26 #pragma GCC diagnostic push
27 #pragma GCC diagnostic ignored "-Wextra-semi"
28 #pragma GCC diagnostic ignored "-Wsuggest-override"
29 #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
31 #pragma clang diagnostic push
32 #pragma clang diagnostic ignored "-Wsuggest-destructor-override"
39 #pragma clang diagnostic pop
41 #pragma GCC diagnostic pop
47 setEscapeStringCaseSensitive(
true);
48 setPassThruUnknownEscapeString(
true);
52 setTokenCaseSensitive(
true);
54 addTokenSubstitute(
"/foreign",
"</span>");
56 removeTokenSubstitute(
"note");
57 removeTokenSubstitute(
"/note");
61 const sword::SWModule *module)
63 sword::ThMLHTML::processText(buf, key, module);
76 auto t = QString::fromUtf8(buf.c_str());
78 static QRegularExpression
const tag(
79 QStringLiteral(R
"PCRE(([.,;]?<sync[^>]+(type|value)=)PCRE"
80 R"PCRE("([^"]+)"[^>]+(type|value)=)PCRE"
81 R"PCRE("([^"]+)"([^<]*)>)+)PCRE"));
82 QRegularExpressionMatch match;
83 auto pos = t.indexOf(tag, 0, &match);
87 auto const partLength = pos + match.capturedLength();
88 list.append(t.left(partLength));
89 t.remove(0, partLength);
90 pos = t.indexOf(tag, 0, &match);
96 list.append(std::move(t));
99 static QRegularExpression
const tag(
100 QStringLiteral(R
"PCRE(<sync[^>]+(type|value|class)="([^"]+)"[^>]+)PCRE"
101 R"PCRE((type|value|class)="([^"]+)"[^>]+)PCRE"
102 R"PCRE(((type|value|class)="([^"]+)")*([^<]*)>)PCRE"));
104 for (
auto & e : list) {
107 if (
auto const pos = e.indexOf(tag); pos > 0) {
108 result.append(e.left(pos));
113 bool hasLemmaAttr =
false;
114 bool hasMorphAttr =
false;
116 QRegularExpressionMatch match;
117 auto pos = e.indexOf(tag, 0, &match);
118 bool insertedTag =
false;
121 bool isMorph =
false;
122 bool isStrongs =
false;
128 for (
int i = 1; i < 6; i += 2) {
132 auto const attrName = match.captured(i);
133 auto const attrValue = match.captured(i + 1);
134 if (attrName == QStringLiteral(
"type")) {
135 isMorph = (attrValue == QStringLiteral(
"morph"));
136 isStrongs = (attrValue == QStringLiteral(
"Strongs"));
137 }
else if (attrName == QStringLiteral(
"value")) {
139 }
else if (attrName == QStringLiteral(
"class")) {
140 valueClass = attrValue;
147 if (!valueClass.isEmpty())
148 value = QStringLiteral(
"%1:%2").arg(valueClass, value);
150 if (value.isEmpty()) {
156 e.replace(pos, match.capturedLength(), QStringLiteral(
"</span>"));
159 auto rep = QStringLiteral(
"<span lemma=\"%1\">").arg(value);
161 QChar c = e[startPos];
163 while ((startPos < pos) && (c.isSpace() || c.isPunct())) {
168 hasLemmaAttr = isStrongs;
169 hasMorphAttr = isMorph;
172 e.insert(startPos, std::move(rep));
175 e.remove(pos, match.capturedLength());
177 if ((!isMorph && hasLemmaAttr) || (isMorph && hasMorphAttr)) {
179 auto const & attrRegExp =
182 static QRegularExpression
const re(
183 QStringLiteral(
"morph=\".+?(?=\")"));
186 static QRegularExpression
const re(
187 QStringLiteral(
"lemma=\".+?(?=\")"));
191 QRegularExpressionMatch match;
192 const int foundAttrPos = e.indexOf(attrRegExp, pos, &match);
194 if (foundAttrPos != -1) {
195 e.insert(foundAttrPos + match.capturedLength(),
196 QStringLiteral(
"|%1").arg(value));
197 pos += value.length() + 1;
199 hasLemmaAttr = !isMorph;
200 hasMorphAttr = isMorph;
204 static QRegularExpression
const re(
205 QStringLiteral(
"morph=|lemma="));
206 const int attrPos = e.indexOf(re, 0);
209 hasMorphAttr = isMorph;
210 hasLemmaAttr = !isMorph;
212 auto attr = QStringLiteral(
"%1=\"%2\" ")
214 ? QStringLiteral(
"morph")
215 : QStringLiteral(
"lemma"),
217 pos += attr.length();
218 e.insert(attrPos, std::move(attr));
224 pos = e.indexOf(tag, pos, &match);
227 result.append(std::move(e));
231 buf = result.toUtf8();
238 sword::BasicFilterUserData *userData)
240 if (!substituteToken(buf, token) && !substituteEscapeString(buf, token)) {
241 sword::XMLTag
const tag(token);
245 sword::SWModule
const *
const myModule =
246 const_cast<sword::SWModule *
>(myUserData->module);
247 char const *
const tagName = tag.getName();
249 return sword::ThMLHTML::handleToken(buf, token, userData);
250 if (!sword::stricmp(tagName,
"foreign")) {
253 if (
const char *
const tagLang = tag.getAttribute(
"lang"))
254 buf.append(
"<span class=\"foreign\" lang=\"")
257 }
else if (!sword::stricmp(tagName,
"sync")) {
259 if (
const char *
const tagType = tag.getAttribute(
"type"))
260 if (!sword::stricmp(tagType,
"morph")
261 || !sword::stricmp(tagType,
"Strongs")
262 || !sword::stricmp(tagType,
"lemma"))
263 buf.append(
'<').append(token).append(
'>');
264 }
else if (!sword::stricmp(tagName,
"note")) {
265 if (!tag.isEmpty()) {
266 if (!tag.isEndTag()) {
267 buf.append(
" <span class=\"footnote\" note=\"")
268 .append(myModule->getName())
270 .append(myUserData->key->getShortText())
272 .append(QString::number(myUserData->
swordFootnote).toUtf8().constData())
273 .append(
"\">*</span> ");
276 myUserData->suspendTextPassThru =
true;
278 }
else if (tag.isEndTag()) {
280 myUserData->suspendTextPassThru =
false;
284 }
else if (!sword::stricmp(tagName,
"scripRef")) {
288 if (tag.isEndTag()) {
290 buf.append(
"</a></span>");
293 myUserData->suspendTextPassThru =
false;
296 btConfig().getDefaultSwordModuleByType(
302 QString::fromUtf8(myUserData->key->getText()),
303 myModule->getLanguage()};
306 bool insertSemicolon =
false;
307 buf.append(
"<span class=\"crossreference\">");
308 QStringList
const refs(
310 myUserData->lastTextNode.c_str()).split(
313 for (
auto const & ref : refs) {
314 if (!oldRef.isEmpty())
315 options.refBase = oldRef;
326 buf.append(
"<a href=\"")
331 ).toUtf8().constData()
333 .append(
"\" crossrefs=\"")
334 .append(oldRef.toUtf8().constData())
336 .append(ref.toUtf8().constData())
338 insertSemicolon =
true;
340 buf.append(
"</span>");
342 myUserData->suspendTextPassThru =
false;
344 }
else if (tag.getAttribute(
"passage") ) {
347 myUserData->suspendTextPassThru =
false;
350 QStringLiteral(
"standardBible"));
356 QString
const completeRef(
359 tag.getAttribute(
"passage")),
363 myUserData->key->getText()),
364 myModule->getLanguage()}));
365 buf.append(
"<span class=\"crossreference\">")
366 .append(
"<a href=\"")
371 ).toUtf8().constData()
373 .append(
"\" crossrefs=\"")
374 .append(completeRef.toUtf8().constData())
377 buf.append(
"<span><a>");
383 myUserData->suspendTextPassThru =
true;
386 }
else if (!sword::stricmp(tagName,
"div")) {
387 if (tag.isEndTag()) {
388 buf.append(
"</div>");
389 }
else if (
char const *
const tagClass = tag.getAttribute(
"class")){
390 if (!sword::stricmp(tagClass,
"sechead") ) {
391 buf.append(
"<div class=\"sectiontitle\">");
392 }
else if (!sword::stricmp(tagClass,
"title")) {
393 buf.append(
"<div class=\"booktitle\">");
396 }
else if (!sword::stricmp(tagName,
"img") && tag.getAttribute(
"src")) {
397 const char * value = tag.getAttribute(
"src");
403 auto const *
const absoluteDataPath =
404 myUserData->module->getConfigEntry(
"AbsoluteDataPath");
406 myUserData->module->isUnicode()
407 ? QString::fromUtf8(absoluteDataPath)
408 : QString::fromLatin1(absoluteDataPath));
411 buf.append(
"<img src=\"")
414 QStringLiteral(
"%1/%2").arg(
416 QString::fromUtf8(value))
417 ).toString().toUtf8().constData())
420 return sword::ThMLHTML::handleToken(buf, token, userData);
BtConfig & btConfig()
This is a shortchand for BtConfig::getInstance().
CSwordModuleInfo * getDefaultSwordModuleByType(const QString &moduleType)
Returns default sword module info class for a given module type.
CSwordModuleInfo * findFirstAvailableModule(CSwordModuleInfo::ModuleType type)
static CSwordBackend & instance() noexcept
static FilterOption const strongNumbers
static FilterOption const lemmas
std::optional< QString > absolutePath
unsigned short int swordFootnote
bool handleToken(sword::SWBuf &buf, const char *token, sword::BasicFilterUserData *userData) override
char processText(sword::SWBuf &buf, const sword::SWKey *key, const sword::SWModule *module=nullptr) override
QString parseVerseReference(QString const &ref, ParseOptions const &options)
QString encodeHyperlink(CSwordModuleInfo const &module, QString const &key)