forked from qt-creator/qt-creator
Change-Id: Ic03e20993f05fb5b49a12c891d86afb2c8e18e08 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: hjk <hjk@qt.io>
669 lines
21 KiB
C++
669 lines
21 KiB
C++
// Copyright (C) 2016 The Qt Company Ltd.
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
|
|
#include "qrcparser.h"
|
|
|
|
#include "filepath.h"
|
|
#include "qtcassert.h"
|
|
|
|
#include <qmljs/qmljstr.h> // Yes, the translations are still there
|
|
|
|
#include <QCoreApplication>
|
|
#include <QDir>
|
|
#include <QDomDocument>
|
|
#include <QFile>
|
|
#include <QFileInfo>
|
|
#include <QLocale>
|
|
#include <QLoggingCategory>
|
|
#include <QReadLocker>
|
|
#include <QReadWriteLock>
|
|
#include <QWriteLocker>
|
|
|
|
static Q_LOGGING_CATEGORY(qrcParserLog, "qtc.qrcParser", QtWarningMsg)
|
|
|
|
namespace Utils {
|
|
|
|
namespace Internal {
|
|
|
|
class QrcParserPrivate
|
|
{
|
|
public:
|
|
typedef QMap<QString,QStringList> SMap;
|
|
QrcParserPrivate(QrcParser *q);
|
|
bool parseFile(const QString &path, const QString &contents);
|
|
QString firstFileAtPath(const QString &path, const QLocale &locale) const;
|
|
void collectFilesAtPath(const QString &path, QStringList *res, const QLocale *locale = nullptr) const;
|
|
bool hasDirAtPath(const QString &path, const QLocale *locale = nullptr) const;
|
|
void collectFilesInPath(const QString &path, QMap<QString,QStringList> *res, bool addDirs = false,
|
|
const QLocale *locale = nullptr) const;
|
|
void collectResourceFilesForSourceFile(const QString &sourceFile, QStringList *res,
|
|
const QLocale *locale = nullptr) const;
|
|
QrcParser::MatchResult longestReverseMatches(const QString &) const;
|
|
|
|
QStringList errorMessages() const;
|
|
QStringList languages() const;
|
|
private:
|
|
static QString fixPrefix(const QString &prefix);
|
|
const QStringList allUiLanguages(const QLocale *locale) const;
|
|
|
|
SMap m_resources;
|
|
SMap m_reverseResources;
|
|
SMap m_files;
|
|
QStringList m_languages;
|
|
QStringList m_errorMessages;
|
|
};
|
|
|
|
class QrcCachePrivate
|
|
{
|
|
public:
|
|
QrcCachePrivate(QrcCache *q);
|
|
QrcParser::Ptr addPath(const QString &path, const QString &contents);
|
|
void removePath(const QString &path);
|
|
QrcParser::Ptr updatePath(const QString &path, const QString &contents);
|
|
QrcParser::Ptr parsedPath(const QString &path);
|
|
void clear();
|
|
private:
|
|
QHash<QString, QPair<QrcParser::Ptr,int> > m_cache;
|
|
QReadWriteLock m_mutex;
|
|
};
|
|
} // namespace Internal
|
|
|
|
/*!
|
|
\class Utils::QrcParser
|
|
\inmodule QtCreator
|
|
\brief The QrcParser class parses one or more QRC files and keeps their
|
|
content cached.
|
|
|
|
A \l{The Qt Resource System}{Qt resource collection (QRC)} contains files
|
|
read from the file system but organized in a possibly different way.
|
|
To easily describe that with a simple structure, we use a map from QRC paths
|
|
to the paths in the filesystem.
|
|
By using a map, we can easily find all QRC paths that start with a given
|
|
prefix, and thus loop on a QRC directory.
|
|
|
|
QRC files also support languages, which are mapped to a prefix of the QRC
|
|
path. For example, the French /image/bla.png (lang=fr) will have the path
|
|
\c {fr/image/bla.png}. The empty language represents the default resource.
|
|
Languages are looked up using the locale uiLanguages() property
|
|
|
|
For a single QRC, a given path maps to a single file, but when one has
|
|
multiple (platform-specific and mutually exclusive) QRC files, multiple
|
|
files match, so QStringList are used.
|
|
|
|
Especially, the \c collect* functions are thought of as low level interface.
|
|
*/
|
|
|
|
/*!
|
|
\typedef QrcParser::Ptr
|
|
Represents pointers.
|
|
*/
|
|
|
|
/*!
|
|
\typedef QrcParser::ConstPtr
|
|
Represents constant pointers.
|
|
*/
|
|
|
|
/*!
|
|
Normalizes the \a path to a file in a QRC resource by dropping the \c qrc:/
|
|
or \c : and any extra slashes in the beginning.
|
|
*/
|
|
QString QrcParser::normalizedQrcFilePath(const QString &path) {
|
|
QString normPath = path;
|
|
int endPrefix = 0;
|
|
if (path.startsWith(QLatin1String("qrc:/")))
|
|
endPrefix = 4;
|
|
else if (path.startsWith(QLatin1String(":/")))
|
|
endPrefix = 1;
|
|
if (endPrefix < path.size() && path.at(endPrefix) == QLatin1Char('/'))
|
|
while (endPrefix + 1 < path.size() && path.at(endPrefix+1) == QLatin1Char('/'))
|
|
++endPrefix;
|
|
normPath = path.right(path.size()-endPrefix);
|
|
if (!normPath.startsWith(QLatin1Char('/')))
|
|
normPath.insert(0, QLatin1Char('/'));
|
|
return normPath;
|
|
}
|
|
|
|
/*!
|
|
Returns the path to a directory normalized to \a path in a QRC resource by
|
|
dropping the \c qrc:/ or \c : and any extra slashes at the beginning, and
|
|
by ensuring that the path ends with a slash
|
|
*/
|
|
QString QrcParser::normalizedQrcDirectoryPath(const QString &path) {
|
|
QString normPath = normalizedQrcFilePath(path);
|
|
if (!normPath.endsWith(QLatin1Char('/')))
|
|
normPath.append(QLatin1Char('/'));
|
|
return normPath;
|
|
}
|
|
|
|
/*!
|
|
Returns the QRC directory path for \a file.
|
|
*/
|
|
QString QrcParser::qrcDirectoryPathForQrcFilePath(const QString &file)
|
|
{
|
|
return file.left(file.lastIndexOf(QLatin1Char('/')));
|
|
}
|
|
|
|
QrcParser::QrcParser()
|
|
{
|
|
d = new Internal::QrcParserPrivate(this);
|
|
}
|
|
|
|
/*!
|
|
\internal
|
|
*/
|
|
QrcParser::~QrcParser()
|
|
{
|
|
delete d;
|
|
}
|
|
|
|
/*!
|
|
Parses the QRC file at \a path. If \a contents is not empty, it is used as
|
|
the file contents instead of reading it from the file system.
|
|
|
|
Returns whether the parsing succeeded.
|
|
|
|
\sa errorMessages(), parseQrcFile()
|
|
*/
|
|
bool QrcParser::parseFile(const QString &path, const QString &contents)
|
|
{
|
|
return d->parseFile(path, contents);
|
|
}
|
|
|
|
/*!
|
|
Returns the file system path of the first (active) file at the given QRC
|
|
\a path and \a locale.
|
|
*/
|
|
QString QrcParser::firstFileAtPath(const QString &path, const QLocale &locale) const
|
|
{
|
|
return d->firstFileAtPath(path, locale);
|
|
}
|
|
|
|
/*!
|
|
Adds the file system paths for the given QRC \a path to \a res.
|
|
|
|
If \a locale is null, all possible files are added. Otherwise, just
|
|
the first one that matches the locale is added.
|
|
*/
|
|
void QrcParser::collectFilesAtPath(const QString &path, QStringList *res, const QLocale *locale) const
|
|
{
|
|
d->collectFilesAtPath(path, res, locale);
|
|
}
|
|
|
|
QrcParser::MatchResult QrcParser::longestReverseMatches(const QString &p) const
|
|
{
|
|
return d->longestReverseMatches(p);
|
|
}
|
|
|
|
/*!
|
|
Returns \c true if \a path is a non-empty directory and matches \a locale.
|
|
|
|
*/
|
|
bool QrcParser::hasDirAtPath(const QString &path, const QLocale *locale) const
|
|
{
|
|
return d->hasDirAtPath(path, locale);
|
|
}
|
|
|
|
/*!
|
|
Adds the directory contents of the given QRC \a path to \a res if \a addDirs
|
|
is set to \c true.
|
|
|
|
Adds the QRC filename to file system path associations contained in the
|
|
given \a path to \a res. If addDirs() is \c true, directories are also
|
|
added.
|
|
|
|
If \a locale is null, all possible files are added. Otherwise, just the
|
|
first file with a matching the locale is added.
|
|
*/
|
|
void QrcParser::collectFilesInPath(const QString &path, QMap<QString,QStringList> *res, bool addDirs,
|
|
const QLocale *locale) const
|
|
{
|
|
d->collectFilesInPath(path, res, addDirs, locale);
|
|
}
|
|
|
|
/*!
|
|
Adds the resource files from the QRC file \a sourceFile to \a res.
|
|
|
|
If \a locale is null, all possible files are added. Otherwise, just
|
|
the first file with a matching the locale is added.
|
|
*/
|
|
void QrcParser::collectResourceFilesForSourceFile(const QString &sourceFile, QStringList *res,
|
|
const QLocale *locale) const
|
|
{
|
|
d->collectResourceFilesForSourceFile(sourceFile, res, locale);
|
|
}
|
|
|
|
/*!
|
|
Returns the errors found while parsing.
|
|
*/
|
|
QStringList QrcParser::errorMessages() const
|
|
{
|
|
return d->errorMessages();
|
|
}
|
|
|
|
/*!
|
|
Returns all languages used in this QRC.
|
|
*/
|
|
QStringList QrcParser::languages() const
|
|
{
|
|
return d->languages();
|
|
}
|
|
|
|
/*!
|
|
Indicates whether the QRC contents are valid.
|
|
|
|
Returns an error if the QRC is empty.
|
|
*/
|
|
bool QrcParser::isValid() const
|
|
{
|
|
return errorMessages().isEmpty();
|
|
}
|
|
|
|
/*!
|
|
Returns the \a contents of the QRC file at \a path.
|
|
*/
|
|
QrcParser::Ptr QrcParser::parseQrcFile(const QString &path, const QString &contents)
|
|
{
|
|
Ptr res(new QrcParser);
|
|
if (!path.isEmpty())
|
|
res->parseFile(path, contents);
|
|
return res;
|
|
}
|
|
|
|
// ----------------
|
|
|
|
/*!
|
|
\class Utils::QrcCache
|
|
\inmodule QtCreator
|
|
\brief The QrcCache class caches the contents of parsed QRC files.
|
|
|
|
\sa Utils::QrcParser
|
|
*/
|
|
|
|
QrcCache::QrcCache()
|
|
{
|
|
d = new Internal::QrcCachePrivate(this);
|
|
}
|
|
|
|
/*!
|
|
\internal
|
|
*/
|
|
QrcCache::~QrcCache()
|
|
{
|
|
delete d;
|
|
}
|
|
|
|
/*!
|
|
Parses the QRC file at \a path and caches the parser. If \a contents is not
|
|
empty, it is used as the file contents instead of reading it from the file
|
|
system.
|
|
|
|
Returns whether the parsing succeeded.
|
|
|
|
\sa QrcParser::errorMessages(), QrcParser::parseQrcFile()
|
|
*/
|
|
QrcParser::ConstPtr QrcCache::addPath(const QString &path, const QString &contents)
|
|
{
|
|
return d->addPath(path, contents);
|
|
}
|
|
|
|
/*!
|
|
Removes \a path from the cache.
|
|
*/
|
|
void QrcCache::removePath(const QString &path)
|
|
{
|
|
d->removePath(path);
|
|
}
|
|
|
|
/*!
|
|
Reparses the QRC file at \a path and returns the \a contents of the file.
|
|
*/
|
|
QrcParser::ConstPtr QrcCache::updatePath(const QString &path, const QString &contents)
|
|
{
|
|
return d->updatePath(path, contents);
|
|
}
|
|
|
|
/*!
|
|
Returns the cached QRC parser for the QRC file at \a path.
|
|
*/
|
|
QrcParser::ConstPtr QrcCache::parsedPath(const QString &path)
|
|
{
|
|
return d->parsedPath(path);
|
|
}
|
|
|
|
/*!
|
|
Clears the contents of the cache.
|
|
*/
|
|
void QrcCache::clear()
|
|
{
|
|
d->clear();
|
|
}
|
|
|
|
// --------------------
|
|
|
|
namespace Internal {
|
|
|
|
QrcParserPrivate::QrcParserPrivate(QrcParser *)
|
|
{ }
|
|
|
|
bool QrcParserPrivate::parseFile(const QString &path, const QString &contents)
|
|
{
|
|
QDomDocument doc;
|
|
QDir baseDir(QFileInfo(path).path());
|
|
|
|
if (contents.isEmpty()) {
|
|
// Regular file
|
|
QFile file(path);
|
|
if (!file.open(QIODevice::ReadOnly)) {
|
|
m_errorMessages.append(file.errorString());
|
|
return false;
|
|
}
|
|
|
|
QString error_msg;
|
|
int error_line, error_col;
|
|
if (!doc.setContent(&file, &error_msg, &error_line, &error_col)) {
|
|
m_errorMessages.append(QmlJS::Tr::tr("XML error on line %1, col %2: %3")
|
|
.arg(error_line).arg(error_col).arg(error_msg));
|
|
return false;
|
|
}
|
|
} else {
|
|
// Virtual file from qmake evaluator
|
|
QString error_msg;
|
|
int error_line, error_col;
|
|
if (!doc.setContent(contents, &error_msg, &error_line, &error_col)) {
|
|
m_errorMessages.append(QmlJS::Tr::tr("XML error on line %1, col %2: %3")
|
|
.arg(error_line).arg(error_col).arg(error_msg));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
QDomElement root = doc.firstChildElement(QLatin1String("RCC"));
|
|
if (root.isNull()) {
|
|
m_errorMessages.append(QmlJS::Tr::tr("The <RCC> root element is missing."));
|
|
return false;
|
|
}
|
|
|
|
QDomElement relt = root.firstChildElement(QLatin1String("qresource"));
|
|
for (; !relt.isNull(); relt = relt.nextSiblingElement(QLatin1String("qresource"))) {
|
|
|
|
QString prefix = fixPrefix(relt.attribute(QLatin1String("prefix")));
|
|
const QString language = relt.attribute(QLatin1String("lang"));
|
|
if (!m_languages.contains(language))
|
|
m_languages.append(language);
|
|
|
|
QDomElement felt = relt.firstChildElement(QLatin1String("file"));
|
|
for (; !felt.isNull(); felt = felt.nextSiblingElement(QLatin1String("file"))) {
|
|
const QString fileName = felt.text();
|
|
const QString alias = felt.attribute(QLatin1String("alias"));
|
|
QString filePath = baseDir.absoluteFilePath(fileName);
|
|
QString accessPath;
|
|
if (!alias.isEmpty())
|
|
accessPath = language + prefix + alias;
|
|
else
|
|
accessPath = language + prefix + fileName;
|
|
QStringList &resources = m_resources[accessPath];
|
|
if (!resources.contains(filePath)) {
|
|
resources.append(filePath);
|
|
QString reversePath(accessPath);
|
|
std::reverse(reversePath.begin(), reversePath.end());
|
|
if (!reversePath.endsWith('/'))
|
|
reversePath.append('/');
|
|
m_reverseResources[reversePath].append(filePath);
|
|
}
|
|
QStringList &files = m_files[filePath];
|
|
if (!files.contains(accessPath))
|
|
files.append(accessPath);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// path is assumed to be a normalized absolute path
|
|
QString QrcParserPrivate::firstFileAtPath(const QString &path, const QLocale &locale) const
|
|
{
|
|
QTC_CHECK(path.startsWith(QLatin1Char('/')));
|
|
for (const QString &language : allUiLanguages(&locale)) {
|
|
if (m_languages.contains(language)) {
|
|
SMap::const_iterator res = m_resources.find(language + path);
|
|
if (res != m_resources.end())
|
|
return res.value().at(0);
|
|
}
|
|
}
|
|
return QString();
|
|
}
|
|
|
|
void QrcParserPrivate::collectFilesAtPath(const QString &path, QStringList *files,
|
|
const QLocale *locale) const
|
|
{
|
|
QTC_CHECK(path.startsWith(QLatin1Char('/')));
|
|
for (const QString &language : allUiLanguages(locale)) {
|
|
if (m_languages.contains(language)) {
|
|
SMap::const_iterator res = m_resources.find(language + path);
|
|
if (res != m_resources.end())
|
|
(*files) << res.value();
|
|
}
|
|
}
|
|
}
|
|
|
|
// path is expected to be normalized and start and end with a slash
|
|
bool QrcParserPrivate::hasDirAtPath(const QString &path, const QLocale *locale) const
|
|
{
|
|
QTC_CHECK(path.startsWith(QLatin1Char('/')));
|
|
QTC_CHECK(path.endsWith(QLatin1Char('/')));
|
|
for (const QString &language : allUiLanguages(locale)) {
|
|
if (m_languages.contains(language)) {
|
|
QString key = language + path;
|
|
SMap::const_iterator res = m_resources.lowerBound(key);
|
|
if (res != m_resources.end() && res.key().startsWith(key))
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void QrcParserPrivate::collectFilesInPath(const QString &path, QMap<QString,QStringList> *contents,
|
|
bool addDirs, const QLocale *locale) const
|
|
{
|
|
QTC_CHECK(path.startsWith(QLatin1Char('/')));
|
|
QTC_CHECK(path.endsWith(QLatin1Char('/')));
|
|
SMap::const_iterator end = m_resources.end();
|
|
for (const QString &language : allUiLanguages(locale)) {
|
|
QString key = language + path;
|
|
SMap::const_iterator res = m_resources.lowerBound(key);
|
|
while (res != end && res.key().startsWith(key)) {
|
|
const QString &actualKey = res.key();
|
|
int endDir = actualKey.indexOf(QLatin1Char('/'), key.size());
|
|
if (endDir == -1) {
|
|
QString fileName = res.key().right(res.key().size()-key.size());
|
|
QStringList &els = (*contents)[fileName];
|
|
for (const QString &val : res.value())
|
|
if (!els.contains(val))
|
|
els << val;
|
|
++res;
|
|
} else {
|
|
QString dirName = res.key().mid(key.size(), endDir - key.size() + 1);
|
|
if (addDirs)
|
|
contents->insert(dirName, QStringList());
|
|
QString key2 = key + dirName;
|
|
do {
|
|
++res;
|
|
} while (res != end && res.key().startsWith(key2));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void QrcParserPrivate::collectResourceFilesForSourceFile(const QString &sourceFile,
|
|
QStringList *results,
|
|
const QLocale *locale) const
|
|
{
|
|
// TODO: use FileName from fileutils for file paths
|
|
|
|
const QStringList langs = allUiLanguages(locale);
|
|
SMap::const_iterator file = m_files.find(sourceFile);
|
|
if (file == m_files.end())
|
|
return;
|
|
for (const QString &resource : file.value()) {
|
|
for (const QString &language : langs) {
|
|
if (resource.startsWith(language) && !results->contains(resource))
|
|
results->append(resource);
|
|
}
|
|
}
|
|
}
|
|
|
|
QrcParser::MatchResult QrcParserPrivate::longestReverseMatches(const QString &reversePath) const
|
|
{
|
|
QrcParser::MatchResult res;
|
|
if (reversePath.length() == 1)
|
|
return res;
|
|
auto lastMatch = m_reverseResources.end();
|
|
qsizetype matchedUntil = 0;
|
|
for (qsizetype i = 1, j = 0; i < reversePath.size(); i = j + 1) {
|
|
j = reversePath.indexOf(u'/', i);
|
|
if (j == -1)
|
|
j = reversePath.size() - 1;
|
|
auto match = m_reverseResources.lowerBound(reversePath.mid(0, j + 1));
|
|
QString pNow = reversePath.left(j + 1);
|
|
if (match == m_reverseResources.end() || match.key().left(j + 1) != pNow)
|
|
break;
|
|
++res.matchDepth;
|
|
matchedUntil = j + 1;
|
|
lastMatch = match;
|
|
}
|
|
res.reversedPaths.clear();
|
|
res.sourceFiles.clear();
|
|
for (auto it = lastMatch; it != m_reverseResources.end()
|
|
&& it.key().left(matchedUntil) == reversePath.left(matchedUntil);
|
|
++it) {
|
|
res.reversedPaths.append(it.key());
|
|
for (const QString &filePath : it.value())
|
|
res.sourceFiles.append(Utils::FilePath::fromString(filePath));
|
|
}
|
|
return res;
|
|
}
|
|
|
|
QStringList QrcParserPrivate::errorMessages() const
|
|
{
|
|
return m_errorMessages;
|
|
}
|
|
|
|
QStringList QrcParserPrivate::languages() const
|
|
{
|
|
return m_languages;
|
|
}
|
|
|
|
QString QrcParserPrivate::fixPrefix(const QString &prefix)
|
|
{
|
|
const QChar slash = QLatin1Char('/');
|
|
QString result = QString(slash);
|
|
for (int i = 0; i < prefix.size(); ++i) {
|
|
const QChar c = prefix.at(i);
|
|
if (c == slash && result.at(result.size() - 1) == slash)
|
|
continue;
|
|
result.append(c);
|
|
}
|
|
|
|
if (!result.endsWith(slash))
|
|
result.append(slash);
|
|
|
|
return result;
|
|
}
|
|
|
|
const QStringList QrcParserPrivate::allUiLanguages(const QLocale *locale) const
|
|
{
|
|
if (!locale)
|
|
return languages();
|
|
bool hasEmptyString = false;
|
|
const QStringList langs = locale->uiLanguages();
|
|
QStringList allLangs = langs;
|
|
for (const QString &language : langs) {
|
|
if (language.isEmpty())
|
|
hasEmptyString = true;
|
|
else if (language.contains('_') || language.contains('-')) {
|
|
const QStringList splits = QString(language).replace('_', '-').split('-');
|
|
if (splits.size() > 1 && !allLangs.contains(splits.at(0)))
|
|
allLangs.append(splits.at(0));
|
|
}
|
|
}
|
|
if (!hasEmptyString)
|
|
allLangs.append(QString());
|
|
return allLangs;
|
|
}
|
|
|
|
// ----------------
|
|
|
|
QrcCachePrivate::QrcCachePrivate(QrcCache *)
|
|
{ }
|
|
|
|
QrcParser::Ptr QrcCachePrivate::addPath(const QString &path, const QString &contents)
|
|
{
|
|
QPair<QrcParser::Ptr,int> currentValue;
|
|
{
|
|
QWriteLocker l(&m_mutex);
|
|
currentValue = m_cache.value(path, {QrcParser::Ptr(nullptr), 0});
|
|
currentValue.second += 1;
|
|
if (currentValue.second > 1) {
|
|
m_cache.insert(path, currentValue);
|
|
return currentValue.first;
|
|
}
|
|
}
|
|
QrcParser::Ptr newParser = QrcParser::parseQrcFile(path, contents);
|
|
if (!newParser->isValid())
|
|
qCWarning(qrcParserLog) << "adding invalid qrc " << path << " to the cache:" << newParser->errorMessages();
|
|
{
|
|
QWriteLocker l(&m_mutex);
|
|
QPair<QrcParser::Ptr,int> currentValue = m_cache.value(path, {QrcParser::Ptr(nullptr), 0});
|
|
if (currentValue.first.isNull())
|
|
currentValue.first = newParser;
|
|
currentValue.second += 1;
|
|
m_cache.insert(path, currentValue);
|
|
return currentValue.first;
|
|
}
|
|
}
|
|
|
|
void QrcCachePrivate::removePath(const QString &path)
|
|
{
|
|
QPair<QrcParser::Ptr,int> currentValue;
|
|
{
|
|
QWriteLocker l(&m_mutex);
|
|
currentValue = m_cache.value(path, {QrcParser::Ptr(nullptr), 0});
|
|
if (currentValue.second == 1) {
|
|
m_cache.remove(path);
|
|
} else if (currentValue.second > 1) {
|
|
currentValue.second -= 1;
|
|
m_cache.insert(path, currentValue);
|
|
} else {
|
|
QTC_CHECK(!m_cache.contains(path));
|
|
}
|
|
}
|
|
}
|
|
|
|
QrcParser::Ptr QrcCachePrivate::updatePath(const QString &path, const QString &contents)
|
|
{
|
|
QrcParser::Ptr newParser = QrcParser::parseQrcFile(path, contents);
|
|
{
|
|
QWriteLocker l(&m_mutex);
|
|
QPair<QrcParser::Ptr,int> currentValue = m_cache.value(path, {QrcParser::Ptr(nullptr), 0});
|
|
currentValue.first = newParser;
|
|
if (currentValue.second == 0)
|
|
currentValue.second = 1; // add qrc files that are not in the resources of a project
|
|
m_cache.insert(path, currentValue);
|
|
return currentValue.first;
|
|
}
|
|
}
|
|
|
|
QrcParser::Ptr QrcCachePrivate::parsedPath(const QString &path)
|
|
{
|
|
QReadLocker l(&m_mutex);
|
|
QPair<QrcParser::Ptr,int> currentValue = m_cache.value(path, {QrcParser::Ptr(nullptr), 0});
|
|
return currentValue.first;
|
|
}
|
|
|
|
void QrcCachePrivate::clear()
|
|
{
|
|
QWriteLocker l(&m_mutex);
|
|
m_cache.clear();
|
|
}
|
|
|
|
} // namespace Internal
|
|
} // namespace QmlJS
|