diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/android/jar/build.gradle | 2 | ||||
| -rw-r--r-- | src/corelib/Qt6AndroidGradleHelpers.cmake | 2 | ||||
| -rw-r--r-- | src/corelib/doc/src/cmake/cmake-properties.qdoc | 4 | ||||
| -rw-r--r-- | src/network/android/jar/build.gradle | 2 | ||||
| -rw-r--r-- | src/plugins/networkinformation/android/jar/build.gradle | 2 | ||||
| -rw-r--r-- | src/tools/androiddeployqt/main.cpp | 2 | ||||
| -rw-r--r-- | src/tools/rcc/rcc.cpp | 93 |
7 files changed, 84 insertions, 23 deletions
diff --git a/src/android/jar/build.gradle b/src/android/jar/build.gradle index 74ecff6b75f..54512f6f4b3 100644 --- a/src/android/jar/build.gradle +++ b/src/android/jar/build.gradle @@ -23,7 +23,7 @@ repositories { } android { - compileSdk 35 + compileSdk 36 namespace = "org.qtproject.qt.android" defaultConfig { diff --git a/src/corelib/Qt6AndroidGradleHelpers.cmake b/src/corelib/Qt6AndroidGradleHelpers.cmake index f71bac4e08a..fc8e009b9da 100644 --- a/src/corelib/Qt6AndroidGradleHelpers.cmake +++ b/src/corelib/Qt6AndroidGradleHelpers.cmake @@ -193,7 +193,7 @@ function(_qt_internal_android_generate_target_build_gradle target) QT_ANDROID_MIN_SDK_VERSION "28") _qt_internal_android_get_gradle_property(target_sdk_version ${target} - QT_ANDROID_TARGET_SDK_VERSION "34") + QT_ANDROID_TARGET_SDK_VERSION "36") set(target_abis "$<TARGET_PROPERTY:${target},_qt_android_abis>") set(target_abi_list "$<JOIN:${target_abis};${CMAKE_ANDROID_ARCH_ABI},'$<COMMA> '>") diff --git a/src/corelib/doc/src/cmake/cmake-properties.qdoc b/src/corelib/doc/src/cmake/cmake-properties.qdoc index c7b1a27a4b4..310debf7edc 100644 --- a/src/corelib/doc/src/cmake/cmake-properties.qdoc +++ b/src/corelib/doc/src/cmake/cmake-properties.qdoc @@ -239,7 +239,7 @@ precedence over this CMake property. \badcode set_target_properties(${target} PROPERTIES - QT_ANDROID_COMPILE_SDK_VERSION 35 + QT_ANDROID_COMPILE_SDK_VERSION 36 ) \endcode @@ -247,7 +247,7 @@ The following format also works: \badcode set_target_properties(${target} PROPERTIES - QT_ANDROID_COMPILE_SDK_VERSION "android-35" + QT_ANDROID_COMPILE_SDK_VERSION "android-36" ) \endcode diff --git a/src/network/android/jar/build.gradle b/src/network/android/jar/build.gradle index f1f470b6635..580e15b92f6 100644 --- a/src/network/android/jar/build.gradle +++ b/src/network/android/jar/build.gradle @@ -23,7 +23,7 @@ repositories { } android { - compileSdk 35 + compileSdk 36 defaultConfig { minSdkVersion 28 diff --git a/src/plugins/networkinformation/android/jar/build.gradle b/src/plugins/networkinformation/android/jar/build.gradle index f1f470b6635..580e15b92f6 100644 --- a/src/plugins/networkinformation/android/jar/build.gradle +++ b/src/plugins/networkinformation/android/jar/build.gradle @@ -23,7 +23,7 @@ repositories { } android { - compileSdk 35 + compileSdk 36 defaultConfig { minSdkVersion 28 diff --git a/src/tools/androiddeployqt/main.cpp b/src/tools/androiddeployqt/main.cpp index 7f24df7eac2..c4e7101b372 100644 --- a/src/tools/androiddeployqt/main.cpp +++ b/src/tools/androiddeployqt/main.cpp @@ -173,7 +173,7 @@ struct Options QString versionName; QString versionCode; QByteArray minSdkVersion{"28"}; - QByteArray targetSdkVersion{"35"}; + QByteArray targetSdkVersion{"36"}; // lib c++ path QString stdCppPath; diff --git a/src/tools/rcc/rcc.cpp b/src/tools/rcc/rcc.cpp index 40bfa9c2863..6a6027d44f2 100644 --- a/src/tools/rcc/rcc.cpp +++ b/src/tools/rcc/rcc.cpp @@ -1,10 +1,12 @@ // Copyright (C) 2018 The Qt Company Ltd. // Copyright (C) 2018 Intel Corporation. +// Copyright (C) 2024 Christoph Cullmann <christoph@cullmann.io> // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "rcc.h" #include <qbytearray.h> +#include <qcryptographichash.h> #include <qdatetime.h> #include <qdebug.h> #include <qdir.h> @@ -90,8 +92,28 @@ public: QString resourceName() const; + struct DeduplicationKey { + RCCResourceLibrary::CompressionAlgorithm compressAlgo; + int compressLevel; + int compressThreshold; + QByteArray hash; + + bool operator==(const DeduplicationKey &other) const + { + return compressAlgo == other.compressAlgo && + compressLevel == other.compressLevel && + compressThreshold == other.compressThreshold && + hash == other.hash; + } + }; + + typedef QMultiHash<DeduplicationKey, RCCFileInfo*> DeduplicationMultiHash; + public: - qint64 writeDataBlob(RCCResourceLibrary &lib, qint64 offset, QString *errorMessage); + qint64 writeDataBlob(RCCResourceLibrary &lib, + qint64 offset, + DeduplicationMultiHash &dedupByContent, + QString *errorMessage); qint64 writeDataName(RCCResourceLibrary &, qint64 offset); void writeDataInfo(RCCResourceLibrary &lib); @@ -114,6 +136,11 @@ public: qint64 m_childOffset = 0; }; +static size_t qHash(const RCCFileInfo::DeduplicationKey &key, size_t seed) noexcept +{ + return qHashMulti(seed, key.compressAlgo, key.compressLevel, key.compressThreshold, key.hash); +} + RCCFileInfo::RCCFileInfo(const QString &name, const QFileInfo &fileInfo, QLocale::Language language, QLocale::Territory territory, uint flags, RCCResourceLibrary::CompressionAlgorithm compressAlgo, int compressLevel, @@ -217,8 +244,10 @@ void RCCFileInfo::writeDataInfo(RCCResourceLibrary &lib) } } -qint64 RCCFileInfo::writeDataBlob(RCCResourceLibrary &lib, qint64 offset, - QString *errorMessage) +qint64 RCCFileInfo::writeDataBlob(RCCResourceLibrary &lib, + qint64 offset, + DeduplicationMultiHash &dedupByContent, + QString *errorMessage) { const bool text = lib.m_format == RCCResourceLibrary::C_Code; const bool pass1 = lib.m_format == RCCResourceLibrary::Pass1; @@ -230,24 +259,58 @@ qint64 RCCFileInfo::writeDataBlob(RCCResourceLibrary &lib, qint64 offset, m_dataOffset = offset; QByteArray data; + // determine compession algorithm & level early as used in de-duplication keys + // this avoid corruption for the two pass variants (QTBUG-137546) +#if QT_CONFIG(zstd) + if (m_compressAlgo == RCCResourceLibrary::CompressionAlgorithm::Best && !m_noZstd) { + m_compressAlgo = RCCResourceLibrary::CompressionAlgorithm::Zstd; + m_compressLevel = 19; // not ZSTD_maxCLevel(), as 20+ are experimental + } +#endif +#ifndef QT_NO_COMPRESS + if (m_compressAlgo == RCCResourceLibrary::CompressionAlgorithm::Best) { + m_compressAlgo = RCCResourceLibrary::CompressionAlgorithm::Zlib; + m_compressLevel = 9; + } +#endif + if (!m_isEmpty) { - //find the data to be written - QFile file(m_fileInfo.absoluteFilePath()); + // find the data to be written + const QString absoluteFilePath = m_fileInfo.absoluteFilePath(); + QFile file(absoluteFilePath); if (!file.open(QFile::ReadOnly)) { - *errorMessage = msgOpenReadFailed(m_fileInfo.absoluteFilePath(), file.errorString()); + *errorMessage = msgOpenReadFailed(absoluteFilePath, file.errorString()); return 0; } - data = file.readAll(); + + // de-duplicate the same file content, we can re-use already written data + // we only do that if we have the same compression settings + const QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Sha256); + const DeduplicationKey key{m_compressAlgo, m_compressLevel, m_compressThreshold, hash}; + const QList<RCCFileInfo *> potentialCandidates = dedupByContent.values(key); + for (const RCCFileInfo *candidate : potentialCandidates) { + // check real content, we can have collisions + QFile candidateFile(candidate->m_fileInfo.absoluteFilePath()); + if (!candidateFile.open(QFile::ReadOnly)) { + *errorMessage = msgOpenReadFailed(candidate->m_fileInfo.absoluteFilePath(), + candidateFile.errorString()); + return 0; + } + if (data != candidateFile.readAll()) + continue; + // just remember the offset & flags with final compression state + // of the already written data and be done + m_dataOffset = candidate->m_dataOffset; + m_flags = candidate->m_flags; + return offset; + } + dedupByContent.insert(key, this); } // Check if compression is useful for this file if (data.size() != 0) { #if QT_CONFIG(zstd) - if (m_compressAlgo == RCCResourceLibrary::CompressionAlgorithm::Best && !m_noZstd) { - m_compressAlgo = RCCResourceLibrary::CompressionAlgorithm::Zstd; - m_compressLevel = 19; // not ZSTD_maxCLevel(), as 20+ are experimental - } if (m_compressAlgo == RCCResourceLibrary::CompressionAlgorithm::Zstd && !m_noZstd) { if (lib.m_zstdCCtx == nullptr) lib.m_zstdCCtx = ZSTD_createCCtx(); @@ -292,10 +355,6 @@ qint64 RCCFileInfo::writeDataBlob(RCCResourceLibrary &lib, qint64 offset, } #endif #ifndef QT_NO_COMPRESS - if (m_compressAlgo == RCCResourceLibrary::CompressionAlgorithm::Best) { - m_compressAlgo = RCCResourceLibrary::CompressionAlgorithm::Zlib; - m_compressLevel = 9; - } if (m_compressAlgo == RCCResourceLibrary::CompressionAlgorithm::Zlib) { QByteArray compressed = qCompress(reinterpret_cast<uchar *>(data.data()), data.size(), m_compressLevel); @@ -1168,6 +1227,7 @@ bool RCCResourceLibrary::writeDataBlobs() QStack<RCCFileInfo*> pending; pending.push(m_root); qint64 offset = 0; + RCCFileInfo::DeduplicationMultiHash dedupByContent; QString errorMessage; while (!pending.isEmpty()) { RCCFileInfo *file = pending.pop(); @@ -1176,7 +1236,8 @@ bool RCCResourceLibrary::writeDataBlobs() if (child->m_flags & RCCFileInfo::Directory) pending.push(child); else { - offset = child->writeDataBlob(*this, offset, &errorMessage); + offset = child->writeDataBlob(*this, offset, + dedupByContent, &errorMessage); if (offset == 0) { m_errorDevice->write(errorMessage.toUtf8()); return false; |
