Qt 6.x
The Qt SDK
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
rcc.cpp
Go to the documentation of this file.
1// Copyright (C) 2018 The Qt Company Ltd.
2// Copyright (C) 2018 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
4
5#include "rcc.h"
6
7#include <qbytearray.h>
8#include <qdatetime.h>
9#include <qdebug.h>
10#include <qdir.h>
11#include <qdiriterator.h>
12#include <qfile.h>
13#include <qiodevice.h>
14#include <qlocale.h>
15#include <qstack.h>
16#include <qxmlstream.h>
17
18#include <algorithm>
19
20#if QT_CONFIG(zstd)
21# include <zstd.h>
22#endif
23
24// Note: A copy of this file is used in Qt Designer (qttools/src/designer/src/lib/shared/rcc.cpp)
25
27
28using namespace Qt::StringLiterals;
29
30enum {
33 CONSTANT_ZSTDCOMPRESSLEVEL_CHECK = 1, // Zstd level to check if compressing is a good idea
34 CONSTANT_ZSTDCOMPRESSLEVEL_STORE = 14, // Zstd level to actually store the data
36};
37
38void RCCResourceLibrary::write(const char *str, int len)
39{
40 int n = m_out.size();
41 m_out.resize(n + len);
42 memcpy(m_out.data() + n, str, len);
43}
44
45void RCCResourceLibrary::writeByteArray(const QByteArray &other)
46{
47 if (m_format == Pass2) {
48 m_outDevice->write(other);
49 } else {
50 m_out.append(other);
51 }
52}
53
54static inline QString msgOpenReadFailed(const QString &fname, const QString &why)
55{
56 return QString::fromLatin1("Unable to open %1 for reading: %2\n").arg(fname, why);
57}
58
59
61//
62// RCCFileInfo
63//
65
67{
68public:
69 enum Flags
70 {
71 // must match qresource.cpp
72 NoFlags = 0x00,
73 Compressed = 0x01,
74 Directory = 0x02,
75 CompressedZstd = 0x04
76 };
77
78
79 RCCFileInfo() = default;
81 QLocale::Territory territory, uint flags,
82 RCCResourceLibrary::CompressionAlgorithm compressAlgo, int compressLevel,
83 int compressThreshold, bool noZstd, bool isEmpty);
84
86 RCCFileInfo(const RCCFileInfo &) = delete;
87 RCCFileInfo &operator=(const RCCFileInfo &) = delete;
88 RCCFileInfo(RCCFileInfo &&) = default;
90
91 QString resourceName() const;
92
93public:
97
105
109 bool m_noZstd = false;
110 bool m_isEmpty = false;
111
115};
116
118 QLocale::Territory territory, uint flags,
119 RCCResourceLibrary::CompressionAlgorithm compressAlgo, int compressLevel,
120 int compressThreshold, bool noZstd, bool isEmpty)
121 : m_flags(flags),
122 m_language(language),
123 m_territory(territory),
124 m_name(name),
125 m_fileInfo(fileInfo),
126 m_compressAlgo(compressAlgo),
127 m_compressLevel(compressLevel),
128 m_compressThreshold(compressThreshold),
129 m_noZstd(noZstd),
130 m_isEmpty(isEmpty)
131{
132}
133
135{
137}
138
140{
141 QString resource = m_name;
142 for (RCCFileInfo *p = m_parent; p; p = p->m_parent)
143 resource = resource.prepend(p->m_name + u'/');
144 resource.prepend(u':');
145 return resource;
146}
147
149{
150 const bool text = lib.m_format == RCCResourceLibrary::C_Code;
151 const bool pass1 = lib.m_format == RCCResourceLibrary::Pass1;
152 const bool python = lib.m_format == RCCResourceLibrary::Python_Code;
153 //some info
154 if (text || pass1) {
155 if (m_language != QLocale::C) {
156 lib.writeString(" // ");
157 lib.writeByteArray(resourceName().toLocal8Bit());
158 lib.writeString(" [");
159 lib.writeByteArray(QByteArray::number(m_territory));
160 lib.writeString("::");
161 lib.writeByteArray(QByteArray::number(m_language));
162 lib.writeString("[\n ");
163 } else {
164 lib.writeString(" // ");
165 lib.writeByteArray(resourceName().toLocal8Bit());
166 lib.writeString("\n ");
167 }
168 }
169
170 //pointer data
172 // name offset
173 lib.writeNumber4(m_nameOffset);
174
175 // flags
176 lib.writeNumber2(m_flags);
177
178 // child count
179 lib.writeNumber4(m_children.size());
180
181 // first child offset
182 lib.writeNumber4(m_childOffset);
183 } else {
184 // name offset
185 lib.writeNumber4(m_nameOffset);
186
187 // flags
188 lib.writeNumber2(m_flags);
189
190 // locale
191 lib.writeNumber2(m_territory);
192 lib.writeNumber2(m_language);
193
194 //data offset
195 lib.writeNumber4(m_dataOffset);
196 }
197 if (text || pass1)
198 lib.writeChar('\n');
199 else if (python)
200 lib.writeString("\\\n");
201
202 if (lib.formatVersion() >= 2) {
203 // last modified time stamp
204 const QDateTime lastModified = m_fileInfo.lastModified(QTimeZone::UTC);
205 quint64 lastmod = quint64(lastModified.isValid() ? lastModified.toMSecsSinceEpoch() : 0);
206 static const quint64 sourceDate = 1000 * qgetenv("QT_RCC_SOURCE_DATE_OVERRIDE").toULongLong();
207 if (sourceDate != 0)
208 lastmod = sourceDate;
209 static const quint64 sourceDate2 = 1000 * qgetenv("SOURCE_DATE_EPOCH").toULongLong();
210 if (sourceDate2 != 0)
211 lastmod = sourceDate2;
212 lib.writeNumber8(lastmod);
213 if (text || pass1)
214 lib.writeChar('\n');
215 else if (python)
216 lib.writeString("\\\n");
217 }
218}
219
222{
223 const bool text = lib.m_format == RCCResourceLibrary::C_Code;
224 const bool pass1 = lib.m_format == RCCResourceLibrary::Pass1;
225 const bool pass2 = lib.m_format == RCCResourceLibrary::Pass2;
226 const bool binary = lib.m_format == RCCResourceLibrary::Binary;
227 const bool python = lib.m_format == RCCResourceLibrary::Python_Code;
228
229 //capture the offset
232
233 if (!m_isEmpty) {
234 //find the data to be written
236 if (!file.open(QFile::ReadOnly)) {
238 return 0;
239 }
240
241 data = file.readAll();
242 }
243
244 // Check if compression is useful for this file
245 if (data.size() != 0) {
246#if QT_CONFIG(zstd)
249 m_compressLevel = 19; // not ZSTD_maxCLevel(), as 20+ are experimental
250 }
252 if (lib.m_zstdCCtx == nullptr)
253 lib.m_zstdCCtx = ZSTD_createCCtx();
254 qsizetype size = data.size();
255 size = ZSTD_COMPRESSBOUND(size);
256
257 int compressLevel = m_compressLevel;
258 if (compressLevel < 0)
259 compressLevel = CONSTANT_ZSTDCOMPRESSLEVEL_CHECK;
260
262 char *dst = const_cast<char *>(compressed.constData());
263 size_t n = ZSTD_compressCCtx(lib.m_zstdCCtx, dst, size,
264 data.constData(), data.size(),
265 compressLevel);
266 if (n * 100.0 < data.size() * 1.0 * (100 - m_compressThreshold) ) {
267 // compressing is worth it
268 if (m_compressLevel < 0) {
269 // heuristic compression, so recompress
270 n = ZSTD_compressCCtx(lib.m_zstdCCtx, dst, size,
271 data.constData(), data.size(),
273 }
274 if (ZSTD_isError(n)) {
275 QString msg = QString::fromLatin1("%1: error: compression with zstd failed: %2\n")
276 .arg(m_name, QString::fromUtf8(ZSTD_getErrorName(n)));
277 lib.m_errorDevice->write(msg.toUtf8());
278 } else if (lib.verbose()) {
279 QString msg = QString::fromLatin1("%1: note: compressed using zstd (%2 -> %3)\n")
280 .arg(m_name).arg(data.size()).arg(n);
281 lib.m_errorDevice->write(msg.toUtf8());
282 }
283
284 lib.m_overallFlags |= CompressedZstd;
286 data = std::move(compressed);
287 data.truncate(n);
288 } else if (lib.verbose()) {
289 QString msg = QString::fromLatin1("%1: note: not compressed\n").arg(m_name);
290 lib.m_errorDevice->write(msg.toUtf8());
291 }
292 }
293#endif
294#ifndef QT_NO_COMPRESS
297 m_compressLevel = 9;
298 }
301 qCompress(reinterpret_cast<uchar *>(data.data()), data.size(), m_compressLevel);
302
303 int compressRatio = int(100.0 * (data.size() - compressed.size()) / data.size());
304 if (compressRatio >= m_compressThreshold) {
305 if (lib.verbose()) {
306 QString msg = QString::fromLatin1("%1: note: compressed using zlib (%2 -> %3)\n")
307 .arg(m_name).arg(data.size()).arg(compressed.size());
308 lib.m_errorDevice->write(msg.toUtf8());
309 }
311 lib.m_overallFlags |= Compressed;
313 } else if (lib.verbose()) {
314 QString msg = QString::fromLatin1("%1: note: not compressed\n").arg(m_name);
315 lib.m_errorDevice->write(msg.toUtf8());
316 }
317 }
318#endif // QT_NO_COMPRESS
319 }
320
321 // some info
322 if (text || pass1) {
323 lib.writeString(" // ");
324 lib.writeByteArray(m_fileInfo.absoluteFilePath().toLocal8Bit());
325 lib.writeString("\n ");
326 }
327
328 // write the length
329 if (text || binary || pass2 || python)
330 lib.writeNumber4(data.size());
331 if (text || pass1)
332 lib.writeString("\n ");
333 else if (python)
334 lib.writeString("\\\n");
335 offset += 4;
336
337 // write the payload
338 const char *p = data.constData();
339 if (text || python) {
340 for (int i = data.size(), j = 0; --i >= 0; --j) {
341 lib.writeHex(*p++);
342 if (j == 0) {
343 if (text)
344 lib.writeString("\n ");
345 else
346 lib.writeString("\\\n");
347 j = 16;
348 }
349 }
350 } else if (binary || pass2) {
351 lib.writeByteArray(data);
352 }
353 offset += data.size();
354
355 // done
356 if (text || pass1)
357 lib.writeString("\n ");
358 else if (python)
359 lib.writeString("\\\n");
360
361 return offset;
362}
363
365{
366 const bool text = lib.m_format == RCCResourceLibrary::C_Code;
367 const bool pass1 = lib.m_format == RCCResourceLibrary::Pass1;
368 const bool python = lib.m_format == RCCResourceLibrary::Python_Code;
369
370 // capture the offset
372
373 // some info
374 if (text || pass1) {
375 lib.writeString(" // ");
376 lib.writeByteArray(m_name.toLocal8Bit());
377 lib.writeString("\n ");
378 }
379
380 // write the length
381 lib.writeNumber2(m_name.size());
382 if (text || pass1)
383 lib.writeString("\n ");
384 else if (python)
385 lib.writeString("\\\n");
386 offset += 2;
387
388 // write the hash
389 lib.writeNumber4(qt_hash(m_name));
390 if (text || pass1)
391 lib.writeString("\n ");
392 else if (python)
393 lib.writeString("\\\n");
394 offset += 4;
395
396 // write the m_name
397 const QChar *unicode = m_name.unicode();
398 for (int i = 0; i < m_name.size(); ++i) {
399 lib.writeNumber2(unicode[i].unicode());
400 if ((text || pass1) && i % 16 == 0)
401 lib.writeString("\n ");
402 else if (python && i % 16 == 0)
403 lib.writeString("\\\n");
404 }
405 offset += m_name.size()*2;
406
407 // done
408 if (text || pass1)
409 lib.writeString("\n ");
410 else if (python)
411 lib.writeString("\\\n");
412
413 return offset;
414}
415
416
418//
419// RCCResourceLibrary
420//
422
423RCCResourceLibrary::Strings::Strings() :
424 TAG_RCC("RCC"_L1),
425 TAG_RESOURCE("qresource"_L1),
426 TAG_FILE("file"_L1),
427 ATTRIBUTE_LANG("lang"_L1),
428 ATTRIBUTE_PREFIX("prefix"_L1),
429 ATTRIBUTE_ALIAS("alias"_L1),
430 ATTRIBUTE_EMPTY("empty"_L1),
431 ATTRIBUTE_THRESHOLD("threshold"_L1),
432 ATTRIBUTE_COMPRESS("compress"_L1),
433 ATTRIBUTE_COMPRESSALGO(QStringLiteral("compression-algorithm"))
434{
435}
436
437RCCResourceLibrary::RCCResourceLibrary(quint8 formatVersion)
438 : m_root(nullptr),
439 m_format(C_Code),
440 m_verbose(false),
441 m_compressionAlgo(CompressionAlgorithm::Best),
442 m_compressLevel(CONSTANT_COMPRESSLEVEL_DEFAULT),
443 m_compressThreshold(CONSTANT_COMPRESSTHRESHOLD_DEFAULT),
444 m_treeOffset(0),
445 m_namesOffset(0),
446 m_dataOffset(0),
447 m_overallFlags(0),
448 m_useNameSpace(CONSTANT_USENAMESPACE),
449 m_errorDevice(nullptr),
450 m_outDevice(nullptr),
451 m_formatVersion(formatVersion),
452 m_noZstd(false)
453{
454 m_out.reserve(30 * 1000 * 1000);
455#if QT_CONFIG(zstd)
456 m_zstdCCtx = nullptr;
457#endif
458}
459
461{
462 delete m_root;
463#if QT_CONFIG(zstd)
464 ZSTD_freeCCtx(m_zstdCCtx);
465#endif
466}
467
471 FileTag
474
475static bool parseBoolean(QStringView value, QString *errorMsg)
476{
477 if (value.compare("true"_L1, Qt::CaseInsensitive) == 0)
478 return true;
479 if (value.compare("false"_L1, Qt::CaseInsensitive) == 0)
480 return false;
481
482 *errorMsg = QString::fromLatin1("Invalid value for boolean attribute: '%1'").arg(value);
483 return false;
484}
485
486bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice,
487 const QString &fname, QString currentPath, bool listMode)
488{
489 Q_ASSERT(m_errorDevice);
490 const QChar slash = u'/';
491 if (!currentPath.isEmpty() && !currentPath.endsWith(slash))
492 currentPath += slash;
493
494 QXmlStreamReader reader(inputDevice);
495 QStack<RCCXmlTag> tokens;
496
497 QString prefix;
500 QString alias;
501 bool empty = false;
502 auto compressAlgo = m_compressionAlgo;
503 int compressLevel = m_compressLevel;
504 int compressThreshold = m_compressThreshold;
505
506 while (!reader.atEnd()) {
507 QXmlStreamReader::TokenType t = reader.readNext();
508 switch (t) {
509 case QXmlStreamReader::StartElement:
510 if (reader.name() == m_strings.TAG_RCC) {
511 if (!tokens.isEmpty())
512 reader.raiseError("expected <RCC> tag"_L1);
513 else
514 tokens.push(RccTag);
515 } else if (reader.name() == m_strings.TAG_RESOURCE) {
516 if (tokens.isEmpty() || tokens.top() != RccTag) {
517 reader.raiseError("unexpected <RESOURCE> tag"_L1);
518 } else {
519 tokens.push(ResourceTag);
520
521 QXmlStreamAttributes attributes = reader.attributes();
523 territory = QLocale::c().territory();
524
525 if (attributes.hasAttribute(m_strings.ATTRIBUTE_LANG)) {
526 QString attribute = attributes.value(m_strings.ATTRIBUTE_LANG).toString();
527 QLocale lang = QLocale(attribute);
528 language = lang.language();
529 if (2 == attribute.size()) {
530 // Language only
531 territory = QLocale::AnyTerritory;
532 } else {
533 territory = lang.territory();
534 }
535 }
536
537 prefix.clear();
538 if (attributes.hasAttribute(m_strings.ATTRIBUTE_PREFIX))
539 prefix = attributes.value(m_strings.ATTRIBUTE_PREFIX).toString();
540 if (!prefix.startsWith(slash))
541 prefix.prepend(slash);
542 if (!prefix.endsWith(slash))
543 prefix += slash;
544 }
545 } else if (reader.name() == m_strings.TAG_FILE) {
546 if (tokens.isEmpty() || tokens.top() != ResourceTag) {
547 reader.raiseError("unexpected <FILE> tag"_L1);
548 } else {
549 tokens.push(FileTag);
550
551 QXmlStreamAttributes attributes = reader.attributes();
552 alias.clear();
553 if (attributes.hasAttribute(m_strings.ATTRIBUTE_ALIAS))
554 alias = attributes.value(m_strings.ATTRIBUTE_ALIAS).toString();
555
556 compressAlgo = m_compressionAlgo;
557 compressLevel = m_compressLevel;
558 compressThreshold = m_compressThreshold;
559
561 if (attributes.hasAttribute(m_strings.ATTRIBUTE_EMPTY))
562 empty = parseBoolean(attributes.value(m_strings.ATTRIBUTE_EMPTY), &errorString);
563 else
564 empty = false;
565
566 if (attributes.hasAttribute(m_strings.ATTRIBUTE_COMPRESSALGO))
567 compressAlgo = parseCompressionAlgorithm(attributes.value(m_strings.ATTRIBUTE_COMPRESSALGO), &errorString);
568 if (errorString.isEmpty() && attributes.hasAttribute(m_strings.ATTRIBUTE_COMPRESS)) {
569 QString value = attributes.value(m_strings.ATTRIBUTE_COMPRESS).toString();
570 compressLevel = parseCompressionLevel(compressAlgo, value, &errorString);
571 }
572
573 // Special case for -no-compress
574 if (m_compressLevel == -2)
575 compressAlgo = CompressionAlgorithm::None;
576
577 if (attributes.hasAttribute(m_strings.ATTRIBUTE_THRESHOLD))
578 compressThreshold = attributes.value(m_strings.ATTRIBUTE_THRESHOLD).toString().toInt();
579
580 if (!errorString.isEmpty())
581 reader.raiseError(errorString);
582 }
583 } else {
584 reader.raiseError("unexpected tag: %1"_L1.arg(reader.name().toString()));
585 }
586 break;
587
588 case QXmlStreamReader::EndElement:
589 if (reader.name() == m_strings.TAG_RCC) {
590 if (!tokens.isEmpty() && tokens.top() == RccTag)
591 tokens.pop();
592 else
593 reader.raiseError("unexpected closing tag"_L1);
594 } else if (reader.name() == m_strings.TAG_RESOURCE) {
595 if (!tokens.isEmpty() && tokens.top() == ResourceTag)
596 tokens.pop();
597 else
598 reader.raiseError("unexpected closing tag"_L1);
599 } else if (reader.name() == m_strings.TAG_FILE) {
600 if (!tokens.isEmpty() && tokens.top() == FileTag)
601 tokens.pop();
602 else
603 reader.raiseError("unexpected closing tag"_L1);
604 }
605 break;
606
607 case QXmlStreamReader::Characters:
608 if (reader.isWhitespace())
609 break;
610 if (tokens.isEmpty() || tokens.top() != FileTag) {
611 reader.raiseError("unexpected text"_L1);
612 } else {
613 QString fileName = reader.text().toString();
614 if (fileName.isEmpty()) {
615 const QString msg = QString::fromLatin1("RCC: Warning: Null node in XML of '%1'\n").arg(fname);
616 m_errorDevice->write(msg.toUtf8());
617 }
618
619 if (alias.isNull())
620 alias = fileName;
621
622 alias = QDir::cleanPath(alias);
623 while (alias.startsWith("../"_L1))
624 alias.remove(0, 3);
625 alias = QDir::cleanPath(m_resourceRoot) + prefix + alias;
626
627 QString absFileName = fileName;
628 if (QDir::isRelativePath(absFileName))
629 absFileName.prepend(currentPath);
630 QFileInfo file(absFileName);
631 if (file.isDir()) {
632 QDir dir(file.filePath());
633 if (!alias.endsWith(slash))
634 alias += slash;
635
636 QStringList filePaths;
638 while (it.hasNext()) {
639 it.next();
640 if (it.fileName() == "."_L1 || it.fileName() == ".."_L1)
641 continue;
642 filePaths.append(it.filePath());
643 }
644
645 // make rcc output deterministic
646 std::sort(filePaths.begin(), filePaths.end());
647
648 for (const QString &filePath : filePaths) {
649 QFileInfo child(filePath);
650 const bool arc =
651 addFile(alias + child.fileName(),
652 RCCFileInfo(child.fileName(), child, language, territory,
655 compressAlgo, compressLevel, compressThreshold,
656 m_noZstd, empty));
657 if (!arc)
658 m_failedResources.push_back(child.fileName());
659 }
660 } else if (listMode || file.isFile()) {
661 const bool arc =
662 addFile(alias,
663 RCCFileInfo(alias.section(slash, -1),
664 file,
665 language,
666 territory,
668 compressAlgo,
671 m_noZstd, empty)
672 );
673 if (!arc)
674 m_failedResources.push_back(absFileName);
675 } else if (file.exists()) {
676 m_failedResources.push_back(absFileName);
677 const QString msg = QString::fromLatin1("RCC: Error in '%1': Entry '%2' is neither a file nor a directory\n")
678 .arg(fname, fileName);
679 m_errorDevice->write(msg.toUtf8());
680 return false;
681 } else {
682 m_failedResources.push_back(absFileName);
683 const QString msg = QString::fromLatin1("RCC: Error in '%1': Cannot find file '%2'\n")
684 .arg(fname, fileName);
685 m_errorDevice->write(msg.toUtf8());
686 return false;
687 }
688 }
689 break;
690
691 default:
692 break;
693 }
694 }
695
696 if (reader.hasError()) {
697 int errorLine = reader.lineNumber();
698 int errorColumn = reader.columnNumber();
700 QString msg = QString::fromLatin1("RCC Parse Error: '%1' Line: %2 Column: %3 [%4]\n").arg(fname).arg(errorLine).arg(errorColumn).arg(errorMessage);
701 m_errorDevice->write(msg.toUtf8());
702 return false;
703 }
704
705 if (m_root == nullptr) {
706 const QString msg = QString::fromLatin1("RCC: Warning: No resources in '%1'.\n").arg(fname);
707 m_errorDevice->write(msg.toUtf8());
708 if (!listMode && m_format == Binary) {
709 // create dummy entry, otherwise loading with QResource will crash
710 m_root = new RCCFileInfo{};
712 }
713 }
714
715 return true;
716}
717
718bool RCCResourceLibrary::addFile(const QString &alias, RCCFileInfo file)
719{
720 Q_ASSERT(m_errorDevice);
721 if (file.m_fileInfo.size() > 0xffffffff) {
722 const QString msg = QString::fromLatin1("File too big: %1\n").arg(file.m_fileInfo.absoluteFilePath());
723 m_errorDevice->write(msg.toUtf8());
724 return false;
725 }
726 if (!m_root) {
727 m_root = new RCCFileInfo{};
729 }
730
731 RCCFileInfo *parent = m_root;
732 const QStringList nodes = alias.split(u'/');
733 for (int i = 1; i < nodes.size()-1; ++i) {
734 const QString node = nodes.at(i);
735 if (node.isEmpty())
736 continue;
737 if (!parent->m_children.contains(node)) {
738 RCCFileInfo *s = new RCCFileInfo{};
739 s->m_name = node;
740 s->m_flags = RCCFileInfo::Directory;
741 s->m_parent = parent;
742 parent->m_children.insert(node, s);
743 parent = s;
744 } else {
745 parent = *parent->m_children.constFind(node);
746 }
747 }
748
749 const QString filename = nodes.at(nodes.size()-1);
750 RCCFileInfo *s = new RCCFileInfo(std::move(file));
751 s->m_parent = parent;
752 auto cbegin = parent->m_children.constFind(filename);
753 auto cend = parent->m_children.constEnd();
754 for (auto it = cbegin; it != cend; ++it) {
755 if (it.key() == filename && it.value()->m_language == s->m_language &&
756 it.value()->m_territory == s->m_territory) {
757 for (const QString &name : std::as_const(m_fileNames)) {
758 qWarning("%s: Warning: potential duplicate alias detected: '%s'",
759 qPrintable(name), qPrintable(filename));
760 }
761 break;
762 }
763 }
764 parent->m_children.insert(filename, s);
765 return true;
766}
767
768void RCCResourceLibrary::reset()
769{
770 if (m_root) {
771 delete m_root;
772 m_root = nullptr;
773 }
774 m_errorDevice = nullptr;
775 m_failedResources.clear();
776}
777
778
779bool RCCResourceLibrary::readFiles(bool listMode, QIODevice &errorDevice)
780{
781 reset();
782 m_errorDevice = &errorDevice;
783 //read in data
784 if (m_verbose) {
785 const QString msg = QString::fromLatin1("Processing %1 files [listMode=%2]\n")
786 .arg(m_fileNames.size()).arg(static_cast<int>(listMode));
787 m_errorDevice->write(msg.toUtf8());
788 }
789 for (int i = 0; i < m_fileNames.size(); ++i) {
790 QFile fileIn;
791 QString fname = m_fileNames.at(i);
792 QString pwd;
793 if (fname == "-"_L1) {
794 fname = "(stdin)"_L1;
795 pwd = QDir::currentPath();
796 fileIn.setFileName(fname);
797 if (!fileIn.open(stdin, QIODevice::ReadOnly)) {
798 m_errorDevice->write(msgOpenReadFailed(fname, fileIn.errorString()).toUtf8());
799 return false;
800 }
801 } else {
802 pwd = QFileInfo(fname).path();
803 fileIn.setFileName(fname);
804 if (!fileIn.open(QIODevice::ReadOnly)) {
805 m_errorDevice->write(msgOpenReadFailed(fname, fileIn.errorString()).toUtf8());
806 return false;
807 }
808 }
809 if (m_verbose) {
810 const QString msg = QString::fromLatin1("Interpreting %1\n").arg(fname);
811 m_errorDevice->write(msg.toUtf8());
812 }
813
814 if (!interpretResourceFile(&fileIn, fname, pwd, listMode))
815 return false;
816 }
817 return true;
818}
819
821{
824
825 if (!m_root)
826 return ret;
827 pending.push(m_root);
828 while (!pending.isEmpty()) {
829 RCCFileInfo *file = pending.pop();
830 for (auto it = file->m_children.begin();
831 it != file->m_children.end(); ++it) {
832 RCCFileInfo *child = it.value();
833 if (child->m_flags & RCCFileInfo::Directory)
834 pending.push(child);
835 else
836 ret.append(child->m_fileInfo.filePath());
837 }
838 }
839 return ret;
840}
841
842// Determine map of resource identifier (':/newPrefix/images/p1.png') to file via recursion
844{
845 const QChar slash = u'/';
846 const auto cend = m_root->m_children.constEnd();
847 for (auto it = m_root->m_children.constBegin(); it != cend; ++it) {
848 const RCCFileInfo *child = it.value();
849 const QString childName = path + slash + child->m_name;
850 if (child->m_flags & RCCFileInfo::Directory) {
852 } else {
853 m.insert(childName, child->m_fileInfo.filePath());
854 }
855 }
856}
857
859{
861 if (m_root)
862 resourceDataFileMapRecursion(m_root, QString(u':'), rc);
863 return rc;
864}
865
867{
868 if (value == "best"_L1)
870 if (value == "zlib"_L1) {
871#ifdef QT_NO_COMPRESS
872 *errorMsg = "zlib support not compiled in"_L1;
873#else
875#endif
876 } else if (value == "zstd"_L1) {
877#if QT_CONFIG(zstd)
879#else
880 *errorMsg = "Zstandard support not compiled in"_L1;
881#endif
882 } else if (value != "none"_L1) {
883 *errorMsg = QString::fromLatin1("Unknown compression algorithm '%1'").arg(value);
884 }
885
887}
888
890{
891 bool ok;
892 int c = level.toInt(&ok);
893 if (ok) {
894 switch (algo) {
897 return 0;
899 if (c >= 1 && c <= 9)
900 return c;
901 break;
903#if QT_CONFIG(zstd)
904 if (c >= 0 && c <= ZSTD_maxCLevel())
905 return c;
906#endif
907 break;
908 }
909 }
910
911 *errorMsg = QString::fromLatin1("invalid compression level '%1'").arg(level);
912 return 0;
913}
914
915bool RCCResourceLibrary::output(QIODevice &outDevice, QIODevice &tempDevice, QIODevice &errorDevice)
916{
917 m_errorDevice = &errorDevice;
918
919 if (m_format == Pass2) {
920 const char pattern[] = { 'Q', 'R', 'C', '_', 'D', 'A', 'T', 'A' };
921 bool foundSignature = false;
922
923 while (true) {
924 char c;
925 for (int i = 0; i < 8; ) {
926 if (!tempDevice.getChar(&c)) {
927 if (foundSignature)
928 return true;
929 m_errorDevice->write("No data signature found\n");
930 return false;
931 }
932
933 if (c != pattern[i]) {
934 for (int k = 0; k < i; ++k)
935 outDevice.putChar(pattern[k]);
936 i = 0;
937 }
938
939 if (c == pattern[i]) {
940 ++i;
941 } else {
942 outDevice.putChar(c);
943 }
944 }
945
946 m_outDevice = &outDevice;
947 quint64 start = outDevice.pos();
948 writeDataBlobs();
949 quint64 len = outDevice.pos() - start;
950
951 tempDevice.seek(tempDevice.pos() + len - 8);
952 foundSignature = true;
953 }
954 }
955
956 //write out
957 if (m_verbose)
958 m_errorDevice->write("Outputting code\n");
959 if (!writeHeader()) {
960 m_errorDevice->write("Could not write header\n");
961 return false;
962 }
963 if (m_root) {
964 if (!writeDataBlobs()) {
965 m_errorDevice->write("Could not write data blobs.\n");
966 return false;
967 }
968 if (!writeDataNames()) {
969 m_errorDevice->write("Could not write file names\n");
970 return false;
971 }
972 if (!writeDataStructure()) {
973 m_errorDevice->write("Could not write data tree\n");
974 return false;
975 }
976 }
977 if (!writeInitializer()) {
978 m_errorDevice->write("Could not write footer\n");
979 return false;
980 }
981 outDevice.write(m_out.constData(), m_out.size());
982 return true;
983}
984
985void RCCResourceLibrary::writeDecimal(int value)
986{
988 char buf[std::numeric_limits<int>::digits10 + 2];
989 int n = snprintf(buf, sizeof(buf), "%d", value);
990 write(buf, n);
991}
992
993static const char hexDigits[] = "0123456789abcdef";
994
995inline void RCCResourceLibrary::write2HexDigits(quint8 number)
996{
997 writeChar(hexDigits[number >> 4]);
998 writeChar(hexDigits[number & 0xf]);
999}
1000
1001void RCCResourceLibrary::writeHex(quint8 tmp)
1002{
1003 switch (m_format) {
1005 if (tmp >= 32 && tmp < 127 && tmp != '"' && tmp != '\\') {
1006 writeChar(char(tmp));
1007 } else {
1008 writeChar('\\');
1009 writeChar('x');
1010 write2HexDigits(tmp);
1011 }
1012 break;
1013 default:
1014 writeChar('0');
1015 writeChar('x');
1016 if (tmp < 16)
1017 writeChar(hexDigits[tmp]);
1018 else
1019 write2HexDigits(tmp);
1020 writeChar(',');
1021 break;
1022 }
1023}
1024
1025void RCCResourceLibrary::writeNumber2(quint16 number)
1026{
1027 if (m_format == RCCResourceLibrary::Binary) {
1028 writeChar(number >> 8);
1029 writeChar(number);
1030 } else {
1031 writeHex(number >> 8);
1032 writeHex(number);
1033 }
1034}
1035
1036void RCCResourceLibrary::writeNumber4(quint32 number)
1037{
1038 if (m_format == RCCResourceLibrary::Pass2) {
1039 m_outDevice->putChar(char(number >> 24));
1040 m_outDevice->putChar(char(number >> 16));
1041 m_outDevice->putChar(char(number >> 8));
1042 m_outDevice->putChar(char(number));
1043 } else if (m_format == RCCResourceLibrary::Binary) {
1044 writeChar(number >> 24);
1045 writeChar(number >> 16);
1046 writeChar(number >> 8);
1047 writeChar(number);
1048 } else {
1049 writeHex(number >> 24);
1050 writeHex(number >> 16);
1051 writeHex(number >> 8);
1052 writeHex(number);
1053 }
1054}
1055
1056void RCCResourceLibrary::writeNumber8(quint64 number)
1057{
1058 if (m_format == RCCResourceLibrary::Pass2) {
1059 m_outDevice->putChar(char(number >> 56));
1060 m_outDevice->putChar(char(number >> 48));
1061 m_outDevice->putChar(char(number >> 40));
1062 m_outDevice->putChar(char(number >> 32));
1063 m_outDevice->putChar(char(number >> 24));
1064 m_outDevice->putChar(char(number >> 16));
1065 m_outDevice->putChar(char(number >> 8));
1066 m_outDevice->putChar(char(number));
1067 } else if (m_format == RCCResourceLibrary::Binary) {
1068 writeChar(number >> 56);
1069 writeChar(number >> 48);
1070 writeChar(number >> 40);
1071 writeChar(number >> 32);
1072 writeChar(number >> 24);
1073 writeChar(number >> 16);
1074 writeChar(number >> 8);
1075 writeChar(number);
1076 } else {
1077 writeHex(number >> 56);
1078 writeHex(number >> 48);
1079 writeHex(number >> 40);
1080 writeHex(number >> 32);
1081 writeHex(number >> 24);
1082 writeHex(number >> 16);
1083 writeHex(number >> 8);
1084 writeHex(number);
1085 }
1086}
1087
1088bool RCCResourceLibrary::writeHeader()
1089{
1090 switch (m_format) {
1091 case C_Code:
1092 case Pass1:
1093 writeString("/****************************************************************************\n");
1094 writeString("** Resource object code\n");
1095 writeString("**\n");
1096 writeString("** Created by: The Resource Compiler for Qt version ");
1097 writeByteArray(QT_VERSION_STR);
1098 writeString("\n**\n");
1099 writeString("** WARNING! All changes made in this file will be lost!\n");
1100 writeString( "*****************************************************************************/\n\n");
1101 break;
1102 case Python_Code:
1103 writeString("# Resource object code (Python 3)\n");
1104 writeString("# Created by: object code\n");
1105 writeString("# Created by: The Resource Compiler for Qt version ");
1106 writeByteArray(QT_VERSION_STR);
1107 writeString("\n");
1108 writeString("# WARNING! All changes made in this file will be lost!\n\n");
1109 writeString("from PySide");
1110 writeByteArray(QByteArray::number(QT_VERSION_MAJOR));
1111 writeString(" import QtCore\n\n");
1112 break;
1113 case Binary:
1114 writeString("qres");
1115 writeNumber4(0);
1116 writeNumber4(0);
1117 writeNumber4(0);
1118 writeNumber4(0);
1119 if (m_formatVersion >= 3)
1120 writeNumber4(m_overallFlags);
1121 break;
1122 default:
1123 break;
1124 }
1125 return true;
1126}
1127
1128bool RCCResourceLibrary::writeDataBlobs()
1129{
1130 Q_ASSERT(m_errorDevice);
1131 switch (m_format) {
1132 case C_Code:
1133 writeString("static const unsigned char qt_resource_data[] = {\n");
1134 break;
1135 case Python_Code:
1136 writeString("qt_resource_data = b\"\\\n");
1137 break;
1138 case Binary:
1139 m_dataOffset = m_out.size();
1140 break;
1141 default:
1142 break;
1143 }
1144
1145 if (!m_root)
1146 return false;
1147
1149 pending.push(m_root);
1150 qint64 offset = 0;
1152 while (!pending.isEmpty()) {
1153 RCCFileInfo *file = pending.pop();
1154 for (auto it = file->m_children.cbegin(); it != file->m_children.cend(); ++it) {
1155 RCCFileInfo *child = it.value();
1156 if (child->m_flags & RCCFileInfo::Directory)
1157 pending.push(child);
1158 else {
1159 offset = child->writeDataBlob(*this, offset, &errorMessage);
1160 if (offset == 0) {
1161 m_errorDevice->write(errorMessage.toUtf8());
1162 return false;
1163 }
1164 }
1165 }
1166 }
1167 switch (m_format) {
1168 case C_Code:
1169 writeString("\n};\n\n");
1170 break;
1171 case Python_Code:
1172 writeString("\"\n\n");
1173 break;
1174 case Pass1:
1175 if (offset < 8)
1176 offset = 8;
1177 writeString("\nstatic const unsigned char qt_resource_data[");
1178 writeByteArray(QByteArray::number(offset));
1179 writeString("] = { 'Q', 'R', 'C', '_', 'D', 'A', 'T', 'A' };\n\n");
1180 break;
1181 default:
1182 break;
1183 }
1184 return true;
1185}
1186
1187bool RCCResourceLibrary::writeDataNames()
1188{
1189 switch (m_format) {
1190 case C_Code:
1191 case Pass1:
1192 writeString("static const unsigned char qt_resource_name[] = {\n");
1193 break;
1194 case Python_Code:
1195 writeString("qt_resource_name = b\"\\\n");
1196 break;
1197 case Binary:
1198 m_namesOffset = m_out.size();
1199 break;
1200 default:
1201 break;
1202 }
1203
1206
1207 if (!m_root)
1208 return false;
1209
1210 pending.push(m_root);
1211 qint64 offset = 0;
1212 while (!pending.isEmpty()) {
1213 RCCFileInfo *file = pending.pop();
1214 for (auto it = file->m_children.cbegin(); it != file->m_children.cend(); ++it) {
1215 RCCFileInfo *child = it.value();
1216 if (child->m_flags & RCCFileInfo::Directory)
1217 pending.push(child);
1218 if (names.contains(child->m_name)) {
1219 child->m_nameOffset = names.value(child->m_name);
1220 } else {
1221 names.insert(child->m_name, offset);
1222 offset = child->writeDataName(*this, offset);
1223 }
1224 }
1225 }
1226 switch (m_format) {
1227 case C_Code:
1228 case Pass1:
1229 writeString("\n};\n\n");
1230 break;
1231 case Python_Code:
1232 writeString("\"\n\n");
1233 break;
1234 default:
1235 break;
1236 }
1237 return true;
1238}
1239
1241{
1242 typedef bool result_type;
1244 {
1245 return qt_hash(left->m_name) < qt_hash(right->m_name);
1246 }
1247};
1248
1249bool RCCResourceLibrary::writeDataStructure()
1250{
1251 switch (m_format) {
1252 case C_Code:
1253 case Pass1:
1254 writeString("static const unsigned char qt_resource_struct[] = {\n");
1255 break;
1256 case Python_Code:
1257 writeString("qt_resource_struct = b\"\\\n");
1258 break;
1259 case Binary:
1260 m_treeOffset = m_out.size();
1261 break;
1262 default:
1263 break;
1264 }
1265
1267
1268 if (!m_root)
1269 return false;
1270
1271 //calculate the child offsets (flat)
1272 pending.push(m_root);
1273 int offset = 1;
1274 while (!pending.isEmpty()) {
1275 RCCFileInfo *file = pending.pop();
1276 file->m_childOffset = offset;
1277
1278 //sort by hash value for binary lookup
1279 QList<RCCFileInfo*> m_children = file->m_children.values();
1280 std::sort(m_children.begin(), m_children.end(), qt_rcc_compare_hash());
1281
1282 //write out the actual data now
1283 for (int i = 0; i < m_children.size(); ++i) {
1284 RCCFileInfo *child = m_children.at(i);
1285 ++offset;
1286 if (child->m_flags & RCCFileInfo::Directory)
1287 pending.push(child);
1288 }
1289 }
1290
1291 //write out the structure (ie iterate again!)
1292 pending.push(m_root);
1293 m_root->writeDataInfo(*this);
1294 while (!pending.isEmpty()) {
1295 RCCFileInfo *file = pending.pop();
1296
1297 //sort by hash value for binary lookup
1298 QList<RCCFileInfo*> m_children = file->m_children.values();
1299 std::sort(m_children.begin(), m_children.end(), qt_rcc_compare_hash());
1300
1301 //write out the actual data now
1302 for (int i = 0; i < m_children.size(); ++i) {
1303 RCCFileInfo *child = m_children.at(i);
1304 child->writeDataInfo(*this);
1305 if (child->m_flags & RCCFileInfo::Directory)
1306 pending.push(child);
1307 }
1308 }
1309 switch (m_format) {
1310 case C_Code:
1311 case Pass1:
1312 writeString("\n};\n\n");
1313 break;
1314 case Python_Code:
1315 writeString("\"\n\n");
1316 break;
1317 default:
1318 break;
1319 }
1320
1321 return true;
1322}
1323
1324void RCCResourceLibrary::writeMangleNamespaceFunction(const QByteArray &name)
1325{
1326 if (m_useNameSpace) {
1327 writeString("QT_RCC_MANGLE_NAMESPACE(");
1328 writeByteArray(name);
1329 writeChar(')');
1330 } else {
1331 writeByteArray(name);
1332 }
1333}
1334
1335void RCCResourceLibrary::writeAddNamespaceFunction(const QByteArray &name)
1336{
1337 if (m_useNameSpace) {
1338 writeString("QT_RCC_PREPEND_NAMESPACE(");
1339 writeByteArray(name);
1340 writeChar(')');
1341 } else {
1342 writeByteArray(name);
1343 }
1344}
1345
1346bool RCCResourceLibrary::writeInitializer()
1347{
1348 if (m_format == C_Code || m_format == Pass1) {
1349 //write("\nQT_BEGIN_NAMESPACE\n");
1350 QString initNameStr = m_initName;
1351 if (!initNameStr.isEmpty()) {
1352 initNameStr.prepend(u'_');
1353 auto isAsciiLetterOrNumber = [] (QChar c) -> bool {
1354 ushort ch = c.unicode();
1355 return (ch >= '0' && ch <= '9') ||
1356 (ch >= 'A' && ch <= 'Z') ||
1357 (ch >= 'a' && ch <= 'z') ||
1358 ch == '_';
1359 };
1360 for (QChar &c : initNameStr) {
1362 c = u'_';
1363 }
1364 }
1365 QByteArray initName = initNameStr.toLatin1();
1366
1367 //init
1368 if (m_useNameSpace) {
1369 writeString("#ifdef QT_NAMESPACE\n"
1370 "# define QT_RCC_PREPEND_NAMESPACE(name) ::QT_NAMESPACE::name\n"
1371 "# define QT_RCC_MANGLE_NAMESPACE0(x) x\n"
1372 "# define QT_RCC_MANGLE_NAMESPACE1(a, b) a##_##b\n"
1373 "# define QT_RCC_MANGLE_NAMESPACE2(a, b) QT_RCC_MANGLE_NAMESPACE1(a,b)\n"
1374 "# define QT_RCC_MANGLE_NAMESPACE(name) QT_RCC_MANGLE_NAMESPACE2( \\\n"
1375 " QT_RCC_MANGLE_NAMESPACE0(name), QT_RCC_MANGLE_NAMESPACE0(QT_NAMESPACE))\n"
1376 "#else\n"
1377 "# define QT_RCC_PREPEND_NAMESPACE(name) name\n"
1378 "# define QT_RCC_MANGLE_NAMESPACE(name) name\n"
1379 "#endif\n\n");
1380
1381 writeString("#ifdef QT_NAMESPACE\n"
1382 "namespace QT_NAMESPACE {\n"
1383 "#endif\n\n");
1384 }
1385
1386 if (m_root) {
1387 writeString("bool qRegisterResourceData"
1388 "(int, const unsigned char *, "
1389 "const unsigned char *, const unsigned char *);\n");
1390 writeString("bool qUnregisterResourceData"
1391 "(int, const unsigned char *, "
1392 "const unsigned char *, const unsigned char *);\n\n");
1393
1394 if (m_overallFlags & (RCCFileInfo::Compressed | RCCFileInfo::CompressedZstd)) {
1395 // use variable relocations with ELF and Mach-O
1396 writeString("#if defined(__ELF__) || defined(__APPLE__)\n");
1397 if (m_overallFlags & RCCFileInfo::Compressed) {
1398 writeString("static inline unsigned char qResourceFeatureZlib()\n"
1399 "{\n"
1400 " extern const unsigned char qt_resourceFeatureZlib;\n"
1401 " return qt_resourceFeatureZlib;\n"
1402 "}\n");
1403 }
1404 if (m_overallFlags & RCCFileInfo::CompressedZstd) {
1405 writeString("static inline unsigned char qResourceFeatureZstd()\n"
1406 "{\n"
1407 " extern const unsigned char qt_resourceFeatureZstd;\n"
1408 " return qt_resourceFeatureZstd;\n"
1409 "}\n");
1410 }
1411 writeString("#else\n");
1412 if (m_overallFlags & RCCFileInfo::Compressed)
1413 writeString("unsigned char qResourceFeatureZlib();\n");
1414 if (m_overallFlags & RCCFileInfo::CompressedZstd)
1415 writeString("unsigned char qResourceFeatureZstd();\n");
1416 writeString("#endif\n\n");
1417 }
1418 }
1419
1420 if (m_useNameSpace)
1421 writeString("#ifdef QT_NAMESPACE\n}\n#endif\n\n");
1422
1423 QByteArray initResources = "qInitResources";
1425
1426 // Work around -Wmissing-declarations warnings.
1427 writeString("int ");
1428 writeMangleNamespaceFunction(initResources);
1429 writeString("();\n");
1430
1431 writeString("int ");
1432 writeMangleNamespaceFunction(initResources);
1433 writeString("()\n{\n");
1434
1435 if (m_root) {
1436 writeString(" int version = ");
1437 writeDecimal(m_formatVersion);
1438 writeString(";\n ");
1439 writeAddNamespaceFunction("qRegisterResourceData");
1440 writeString("\n (version, qt_resource_struct, "
1441 "qt_resource_name, qt_resource_data);\n");
1442 }
1443 writeString(" return 1;\n");
1444 writeString("}\n\n");
1445
1446 //cleanup
1447 QByteArray cleanResources = "qCleanupResources";
1448 cleanResources += initName;
1449
1450 // Work around -Wmissing-declarations warnings.
1451 writeString("int ");
1452 writeMangleNamespaceFunction(cleanResources);
1453 writeString("();\n");
1454
1455 writeString("int ");
1456 writeMangleNamespaceFunction(cleanResources);
1457 writeString("()\n{\n");
1458 if (m_root) {
1459 writeString(" int version = ");
1460 writeDecimal(m_formatVersion);
1461 writeString(";\n ");
1462
1463 // ODR-use certain symbols from QtCore if we require optional features
1464 if (m_overallFlags & RCCFileInfo::Compressed) {
1465 writeString("version += ");
1466 writeAddNamespaceFunction("qResourceFeatureZlib()");
1467 writeString(";\n ");
1468 }
1469 if (m_overallFlags & RCCFileInfo::CompressedZstd) {
1470 writeString("version += ");
1471 writeAddNamespaceFunction("qResourceFeatureZstd()");
1472 writeString(";\n ");
1473 }
1474
1475 writeAddNamespaceFunction("qUnregisterResourceData");
1476 writeString("\n (version, qt_resource_struct, "
1477 "qt_resource_name, qt_resource_data);\n");
1478 }
1479 writeString(" return 1;\n");
1480 writeString("}\n\n");
1481
1482 // -Wexit-time-destructors was added to clang 3.0.0 in 2011.
1483 writeString("#ifdef __clang__\n"
1484 "# pragma clang diagnostic push\n"
1485 "# pragma clang diagnostic ignored \"-Wexit-time-destructors\"\n"
1486 "#endif\n\n");
1487
1488 writeString("namespace {\n"
1489 " struct initializer {\n");
1490
1491 if (m_useNameSpace) {
1492 writeByteArray(" initializer() { QT_RCC_MANGLE_NAMESPACE(" + initResources + ")(); }\n"
1493 " ~initializer() { QT_RCC_MANGLE_NAMESPACE(" + cleanResources + ")(); }\n");
1494 } else {
1495 writeByteArray(" initializer() { " + initResources + "(); }\n"
1496 " ~initializer() { " + cleanResources + "(); }\n");
1497 }
1498 writeString(" } dummy;\n"
1499 "}\n\n");
1500
1501 writeString("#ifdef __clang__\n"
1502 "# pragma clang diagnostic pop\n"
1503 "#endif\n");
1504
1505
1506 } else if (m_format == Binary) {
1507 int i = 4;
1508 char *p = m_out.data();
1509 p[i++] = 0;
1510 p[i++] = 0;
1511 p[i++] = 0;
1512 p[i++] = m_formatVersion;
1513
1514 p[i++] = (m_treeOffset >> 24) & 0xff;
1515 p[i++] = (m_treeOffset >> 16) & 0xff;
1516 p[i++] = (m_treeOffset >> 8) & 0xff;
1517 p[i++] = (m_treeOffset >> 0) & 0xff;
1518
1519 p[i++] = (m_dataOffset >> 24) & 0xff;
1520 p[i++] = (m_dataOffset >> 16) & 0xff;
1521 p[i++] = (m_dataOffset >> 8) & 0xff;
1522 p[i++] = (m_dataOffset >> 0) & 0xff;
1523
1524 p[i++] = (m_namesOffset >> 24) & 0xff;
1525 p[i++] = (m_namesOffset >> 16) & 0xff;
1526 p[i++] = (m_namesOffset >> 8) & 0xff;
1527 p[i++] = (m_namesOffset >> 0) & 0xff;
1528
1529 if (m_formatVersion >= 3) {
1530 p[i++] = (m_overallFlags >> 24) & 0xff;
1531 p[i++] = (m_overallFlags >> 16) & 0xff;
1532 p[i++] = (m_overallFlags >> 8) & 0xff;
1533 p[i++] = (m_overallFlags >> 0) & 0xff;
1534 }
1535 } else if (m_format == Python_Code) {
1536 writeString("def qInitResources():\n");
1537 writeString(" QtCore.qRegisterResourceData(0x");
1538 write2HexDigits(m_formatVersion);
1539 writeString(", qt_resource_struct, qt_resource_name, qt_resource_data)\n\n");
1540 writeString("def qCleanupResources():\n");
1541 writeString(" QtCore.qUnregisterResourceData(0x");
1542 write2HexDigits(m_formatVersion);
1543 writeString(", qt_resource_struct, qt_resource_name, qt_resource_data)\n\n");
1544 writeString("qInitResources()\n");
1545 }
1546 return true;
1547}
1548
\inmodule QtCore
Definition qbytearray.h:57
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
Definition qbytearray.h:534
qulonglong toULongLong(bool *ok=nullptr, int base=10) const
Returns the byte array converted to an {unsigned long long} using base base, which is ten by default.
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:474
void reserve(qsizetype size)
Attempts to allocate memory for at least size bytes.
Definition qbytearray.h:557
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:122
static QByteArray number(int, int base=10)
Returns a byte-array representing the whole number n as text.
void resize(qsizetype size)
Sets the size of the byte array to size bytes.
QByteArray & append(char c)
This is an overloaded member function, provided for convenience. It differs from the above function o...
\inmodule QtCore
Definition qchar.h:48
\inmodule QtCore\reentrant
Definition qdatetime.h:257
qint64 toMSecsSinceEpoch() const
bool isValid() const
Returns true if this datetime represents a definite moment, otherwise false.
The QDirIterator class provides an iterator for directory entrylists.
\inmodule QtCore
Definition qdir.h:19
static bool isRelativePath(const QString &path)
Returns true if path is relative; returns false if it is absolute.
Definition qdir.cpp:2409
static QString cleanPath(const QString &path)
Returns path with directory separators normalized (that is, platform-native separators converted to "...
Definition qdir.cpp:2395
static QString currentPath()
Returns the absolute path of the application's current directory.
Definition qdir.cpp:2051
\inmodule QtCore \reentrant
Definition qfileinfo.h:22
QDateTime lastModified() const
Returns the date and time when the file was last modified.
Definition qfileinfo.h:156
QString absoluteFilePath() const
Returns an absolute path including the file name.
QString path() const
Returns the file's path.
\inmodule QtCore
Definition qfile.h:93
bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
Definition qfile.cpp:881
void setFileName(const QString &name)
Sets the name of the file.
Definition qfile.cpp:302
bool exists() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qfile.cpp:351
qint64 size() const override
\reimp
Definition qfile.cpp:1156
\inmodule QtCore \reentrant
Definition qiodevice.h:34
virtual qint64 pos() const
For random-access devices, this function returns the position that data is written to or read from.
bool putChar(char c)
Writes the character c to the device.
QByteArray readAll()
Reads all remaining data from the device, and returns it as a byte array.
qint64 write(const char *data, qint64 len)
Writes at most maxSize bytes of data from data to the device.
QString errorString() const
Returns a human-readable description of the last device error that occurred.
bool getChar(char *c)
Reads one character from the device and stores it in c.
virtual bool seek(qint64 pos)
For random-access devices, this function sets the current position to pos, returning true on success,...
QString errorString() const
Returns a human readable description of the last error that occurred.
QString text(const QString &key) const
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
bool isEmpty() const noexcept
Definition qlist.h:390
iterator end()
Definition qlist.h:609
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
iterator begin()
Definition qlist.h:608
Language language() const
Returns the language of this locale.
Definition qlocale.cpp:1279
@ AnyTerritory
Definition qlocale.h:558
static QLocale c()
Returns a QLocale object initialized to the "C" locale.
Definition qlocale.h:1103
Territory territory() const
Definition qlocale.cpp:1303
\inmodule QtCore
Definition qhash.h:1348
const_iterator constBegin() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
Definition qhash.h:1829
const_iterator constEnd() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the ...
Definition qhash.h:1833
qsizetype size() const noexcept
Definition qhash.h:1490
\inmodule QtCore
Definition qstack.h:13
T & top()
Returns a reference to the stack's top item.
Definition qstack.h:19
T pop()
Removes the top item from the stack and returns it.
Definition qstack.h:18
void push(const T &t)
Adds element t to the top of the stack.
Definition qstack.h:17
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:76
QString toString() const
Returns a deep copy of this string view's data as a QString.
Definition qstring.h:1014
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
QByteArray toLatin1() const &
Definition qstring.h:559
int toInt(bool *ok=nullptr, int base=10) const
Returns the string converted to an int using base base, which is 10 by default and must be between 2 ...
Definition qstring.h:660
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition qstring.cpp:5299
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5710
QStringList split(const QString &sep, Qt::SplitBehavior behavior=Qt::KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Splits the string into substrings wherever sep occurs, and returns the list of those strings.
Definition qstring.cpp:7956
void clear()
Clears the contents of the string and makes it null.
Definition qstring.h:1107
bool isNull() const
Returns true if this string is null; otherwise returns false.
Definition qstring.h:898
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5857
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
Definition qstring.cpp:8606
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
Definition qstring.cpp:5350
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
QByteArray toLocal8Bit() const &
Definition qstring.h:567
QString & remove(qsizetype i, qsizetype len)
Removes n characters from the string, starting at the given position index, and returns a reference t...
Definition qstring.cpp:3435
QByteArray toUtf8() const &
Definition qstring.h:563
QString & prepend(QChar c)
Definition qstring.h:411
const QChar * unicode() const
Returns a Unicode representation of the string.
Definition qstring.h:1085
bool hasAttribute(QAnyStringView qualifiedName) const
Definition qxmlstream.h:91
Q_CORE_EXPORT QStringView value(QAnyStringView namespaceUri, QAnyStringView name) const noexcept
int m_flags
Definition rcc.cpp:98
bool m_isEmpty
Definition rcc.cpp:110
int m_compressLevel
Definition rcc.cpp:107
QFileInfo m_fileInfo
Definition rcc.cpp:102
@ NoFlags
Definition rcc.cpp:72
@ CompressedZstd
Definition rcc.cpp:75
@ Directory
Definition rcc.cpp:74
@ Compressed
Definition rcc.cpp:73
int m_compressThreshold
Definition rcc.cpp:108
RCCFileInfo()=default
RCCFileInfo & operator=(RCCFileInfo &&other)=delete
bool m_noZstd
Definition rcc.cpp:109
RCCFileInfo & operator=(const RCCFileInfo &)=delete
qint64 m_childOffset
Definition rcc.cpp:114
RCCResourceLibrary::CompressionAlgorithm m_compressAlgo
Definition rcc.cpp:106
qint64 m_nameOffset
Definition rcc.cpp:112
qint64 writeDataName(RCCResourceLibrary &, qint64 offset)
Definition rcc.cpp:364
RCCFileInfo(RCCFileInfo &&)=default
QLocale::Language m_language
Definition rcc.cpp:99
qint64 writeDataBlob(RCCResourceLibrary &lib, qint64 offset, QString *errorMessage)
Definition rcc.cpp:220
QString m_name
Definition rcc.cpp:101
QString resourceName() const
Definition rcc.cpp:139
qint64 m_dataOffset
Definition rcc.cpp:113
QMultiHash< QString, RCCFileInfo * > m_children
Definition rcc.cpp:104
~RCCFileInfo()
Definition rcc.cpp:134
void writeDataInfo(RCCResourceLibrary &lib)
Definition rcc.cpp:148
RCCFileInfo(const RCCFileInfo &)=delete
RCCFileInfo * m_parent
Definition rcc.cpp:103
QLocale::Territory m_territory
Definition rcc.cpp:100
ResourceDataFileMap resourceDataFileMap() const
Definition rcc.cpp:858
bool readFiles(bool listMode, QIODevice &errorDevice)
Definition rcc.cpp:779
bool verbose() const
Definition rcc.h:50
QStringList dataFiles() const
Definition rcc.cpp:820
int formatVersion() const
Definition rcc.h:85
static int parseCompressionLevel(CompressionAlgorithm algo, const QString &level, QString *errorMsg)
Definition rcc.cpp:889
int compressLevel() const
Definition rcc.h:72
bool output(QIODevice &outDevice, QIODevice &tempDevice, QIODevice &errorDevice)
Definition rcc.cpp:915
int compressThreshold() const
Definition rcc.h:75
friend class RCCFileInfo
Definition rcc.h:104
QString initName() const
Definition rcc.h:53
static CompressionAlgorithm parseCompressionAlgorithm(QStringView algo, QString *errorMsg)
Definition rcc.cpp:866
QString str
[2]
QString text
qDeleteAll(list.begin(), list.end())
QSet< QString >::iterator it
const PluginKeyMapConstIterator cend
Combined button and popup list for selecting options.
Q_MULTIMEDIA_EXPORT QString errorString(HRESULT hr)
constexpr bool isAsciiLetterOrNumber(char32_t c) noexcept
Definition qtools_p.h:82
@ CaseInsensitive
constexpr Initialization Uninitialized
QImageReader reader("image.png")
[1]
QByteArray qCompress(const uchar *data, qsizetype nbytes, int compressionLevel)
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage return DBusPendingCall * pending
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
EGLOutputLayerEXT EGLint attribute
uint qt_hash(QStringView key, uint chained) noexcept
Definition qhash.cpp:1146
#define qWarning
Definition qlogging.h:162
return ret
GLsizei GLsizei GLenum void * binary
const GLfloat * m
GLenum GLuint GLint level
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLdouble GLdouble right
GLint left
GLenum GLenum dst
GLenum GLuint GLenum GLsizei const GLchar * buf
GLbitfield flags
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint start
GLenum GLuint GLintptr offset
GLuint name
GLfloat n
GLboolean reset
const GLubyte * c
GLuint GLuint * names
GLenum GLsizei len
GLdouble GLdouble t
Definition qopenglext.h:243
GLsizei const GLchar *const * path
GLdouble s
[6]
Definition qopenglext.h:235
GLfloat GLfloat p
[1]
GLubyte * pattern
static void initResources()
Definition qpdf.cpp:38
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define qPrintable(string)
Definition qstring.h:1391
static char * toLocal8Bit(char *out, QStringView in, QStringConverter::State *state)
#define QStringLiteral(str)
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
@ Q_PRIMITIVE_TYPE
Definition qtypeinfo.h:144
#define Q_DECLARE_TYPEINFO(TYPE, FLAGS)
Definition qtypeinfo.h:163
unsigned int quint32
Definition qtypes.h:45
unsigned char uchar
Definition qtypes.h:27
unsigned short quint16
Definition qtypes.h:43
unsigned long long quint64
Definition qtypes.h:56
ptrdiff_t qsizetype
Definition qtypes.h:70
unsigned int uint
Definition qtypes.h:29
long long qint64
Definition qtypes.h:55
unsigned short ushort
Definition qtypes.h:28
unsigned char quint8
Definition qtypes.h:41
static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &errorSource, qsizetype errorPosition)
Definition qurl.cpp:3503
static bool parseBoolean(QStringView value, QString *errorMsg)
Definition rcc.cpp:475
@ CONSTANT_COMPRESSLEVEL_DEFAULT
Definition rcc.cpp:32
@ CONSTANT_USENAMESPACE
Definition rcc.cpp:31
@ CONSTANT_ZSTDCOMPRESSLEVEL_STORE
Definition rcc.cpp:34
@ CONSTANT_COMPRESSTHRESHOLD_DEFAULT
Definition rcc.cpp:35
@ CONSTANT_ZSTDCOMPRESSLEVEL_CHECK
Definition rcc.cpp:33
RCCXmlTag
Definition rcc.cpp:468
@ FileTag
Definition rcc.cpp:471
@ ResourceTag
Definition rcc.cpp:470
@ RccTag
Definition rcc.cpp:469
static QString msgOpenReadFailed(const QString &fname, const QString &why)
Definition rcc.cpp:54
static const char hexDigits[]
Definition rcc.cpp:993
static void resourceDataFileMapRecursion(const RCCFileInfo *m_root, const QString &path, RCCResourceLibrary::ResourceDataFileMap &m)
Definition rcc.cpp:843
QFile file
[0]
QByteArray compressed
QObject::connect nullptr
QSharedPointer< T > other(t)
[5]
QString dir
[11]
QLayoutItem * child
[0]
result_type operator()(const RCCFileInfo *left, const RCCFileInfo *right) const
Definition rcc.cpp:1243
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent