Merge branch 'master' of ssh://git.eden-emu.dev/eden-emu/eden into dynlruregs

This commit is contained in:
lizzie 2025-07-19 00:53:48 +01:00
commit 53b93b8954
33 changed files with 893 additions and 871 deletions

View file

@ -36,15 +36,16 @@ case "$1" in
ARCH=armv9
ARCH_FLAGS="-march=armv9-a -mtune=generic -w"
;;
*)
echo "Invalid target $1 specified, must be one of amd64, steamdeck, allyx, rog-ally, legacy, aarch64, armv9"
exit 1
;;
esac
export ARCH_FLAGS="$ARCH_FLAGS -O3"
NPROC="$2"
if [ -z "$NPROC" ]; then
NPROC="$(nproc)"
else
shift
fi
if [ "$1" != "" ]; then shift; fi
@ -72,11 +73,15 @@ else
MULTIMEDIA=ON
fi
if [ -z "$BUILD_TYPE" ]; then
export BUILD_TYPE="Release"
fi
export EXTRA_CMAKE_FLAGS=("${EXTRA_CMAKE_FLAGS[@]}" $@)
mkdir -p build && cd build
cmake .. -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_BUILD_TYPE="$BUILD_TYPE" \
-DENABLE_QT_TRANSLATION=ON \
-DUSE_DISCORD_PRESENCE=ON \
-DCMAKE_CXX_FLAGS="$ARCH_FLAGS" \

View file

@ -17,6 +17,10 @@ else
export EXTRA_CMAKE_FLAGS=("${EXTRA_CMAKE_FLAGS[@]}" -DYUZU_USE_BUNDLED_QT=OFF)
fi
if [ -z "$BUILD_TYPE" ]; then
export BUILD_TYPE="Release"
fi
if [ "$WINDEPLOYQT" == "" ]; then
echo "You must supply the WINDEPLOYQT environment variable."
exit 1
@ -38,7 +42,7 @@ export EXTRA_CMAKE_FLAGS=("${EXTRA_CMAKE_FLAGS[@]}" $@)
mkdir -p build && cd build
cmake .. -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_BUILD_TYPE="$BUILD_TYPE" \
-DENABLE_QT_TRANSLATION=ON \
-DUSE_DISCORD_PRESENCE=ON \
-DYUZU_USE_BUNDLED_SDL2=OFF \

1
.gitignore vendored
View file

@ -52,4 +52,3 @@ Thumbs.db
eden-windows-msvc
artifacts
*.AppImage*
*.patch

View file

@ -0,0 +1,80 @@
diff --git a/quazip/quazipdir.cpp b/quazip/quazipdir.cpp
index d43f1c1..eb24bf1 100644
--- a/quazip/quazipdir.cpp
+++ b/quazip/quazipdir.cpp
@@ -293,8 +293,8 @@ bool QuaZipDirComparator::operator()(const QuaZipFileInfo64 &info1,
}
template<typename TFileInfoList>
-bool QuaZipDirPrivate::entryInfoList(QStringList nameFilters,
- QDir::Filters filter, QDir::SortFlags sort, TFileInfoList &result) const
+bool QuaZipDirPrivate::entryInfoList(QStringList _nameFilters,
+ QDir::Filters _filter, QDir::SortFlags sort, TFileInfoList &result) const
{
QString basePath = simplePath();
if (!basePath.isEmpty())
@@ -305,12 +305,12 @@ bool QuaZipDirPrivate::entryInfoList(QStringList nameFilters,
if (!zip->goToFirstFile()) {
return zip->getZipError() == UNZ_OK;
}
- QDir::Filters fltr = filter;
+ QDir::Filters fltr = _filter;
if (fltr == QDir::NoFilter)
fltr = this->filter;
if (fltr == QDir::NoFilter)
fltr = QDir::AllEntries;
- QStringList nmfltr = nameFilters;
+ QStringList nmfltr = _nameFilters;
if (nmfltr.isEmpty())
nmfltr = this->nameFilters;
QSet<QString> dirsFound;
diff --git a/quazip/quazipfile.cpp b/quazip/quazipfile.cpp
index 4a5f2f9..f7865f5 100644
--- a/quazip/quazipfile.cpp
+++ b/quazip/quazipfile.cpp
@@ -241,14 +241,14 @@ void QuaZipFile::setFileName(const QString& fileName, QuaZip::CaseSensitivity cs
p->caseSensitivity=cs;
}
-void QuaZipFilePrivate::setZipError(int zipError) const
+void QuaZipFilePrivate::setZipError(int _zipError) const
{
QuaZipFilePrivate *fakeThis = const_cast<QuaZipFilePrivate*>(this); // non-const
- fakeThis->zipError=zipError;
- if(zipError==UNZ_OK)
+ fakeThis->zipError = _zipError;
+ if(_zipError == UNZ_OK)
q->setErrorString(QString());
else
- q->setErrorString(QuaZipFile::tr("ZIP/UNZIP API error %1").arg(zipError));
+ q->setErrorString(QuaZipFile::tr("ZIP/UNZIP API error %1").arg(_zipError));
}
bool QuaZipFile::open(OpenMode mode)
diff --git a/quazip/unzip.c b/quazip/unzip.c
index a39365d..ee7b487 100644
--- a/quazip/unzip.c
+++ b/quazip/unzip.c
@@ -1054,7 +1054,7 @@ local int unz64local_GetCurrentFileInfoInternal (unzFile file,
/* ZIP64 extra fields */
if (headerId == 0x0001)
{
- uLong uL;
+ uLong _uL;
if(file_info.uncompressed_size == (ZPOS64_T)0xFFFFFFFFu)
{
@@ -1078,7 +1078,7 @@ local int unz64local_GetCurrentFileInfoInternal (unzFile file,
if(file_info.disk_num_start == 0xFFFFFFFFu)
{
/* Disk Start Number */
- if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
+ if (unz64local_getLong(&s->z_filefunc, s->filestream, &_uL) != UNZ_OK)
err=UNZ_ERRNO;
}
@@ -2151,3 +2151,4 @@ int ZEXPORT unzClearFlags(unzFile file, unsigned flags)
s->flags &= ~flags;
return UNZ_OK;
}
+

View file

@ -0,0 +1,26 @@
diff --git a/quazip/minizip_crypt.h b/quazip/minizip_crypt.h
index 2e833f7..ea9d277 100644
--- a/quazip/minizip_crypt.h
+++ b/quazip/minizip_crypt.h
@@ -90,13 +90,14 @@ static void init_keys(const char* passwd,unsigned long* pkeys,const z_crc_t FAR
# define ZCR_SEED2 3141592654UL /* use PI as default pattern */
# endif
-static int crypthead(passwd, buf, bufSize, pkeys, pcrc_32_tab, crcForCrypting)
- const char *passwd; /* password string */
- unsigned char *buf; /* where to write header */
- int bufSize;
- unsigned long* pkeys;
- const z_crc_t FAR * pcrc_32_tab;
- unsigned long crcForCrypting;
+static int crypthead(
+ const char *passwd, /* password string */
+ unsigned char *buf, /* where to write header */
+ int bufSize,
+ unsigned long* pkeys,
+ const z_crc_t FAR * pcrc_32_tab,
+ unsigned long crcForCrypting
+)
{
int n; /* index in random header */
int t; /* temporary */

View file

@ -0,0 +1,19 @@
diff --git a/quazip/zip.c b/quazip/zip.c
index 7788b88..f4e21aa 100644
--- a/quazip/zip.c
+++ b/quazip/zip.c
@@ -645,6 +645,14 @@ local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib
return relativeOffset;
}
+// compilers hate this ONE SIMPLE TRICK!
+static int LoadCentralDirectoryRecord(zip64_internal* pziinit);
+static int Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt size_extrafield_local, const void* extrafield_local, uLong version_to_extract);
+static int Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip);
+static int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip);
+static int Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip);
+static int Write_GlobalComment(zip64_internal* zi, const char* global_comment);
+
int LoadCentralDirectoryRecord(zip64_internal* pziinit)
{
int err=ZIP_OK;

View file

@ -0,0 +1,400 @@
"Debloats" QuaZip by removing some unneeded stuff (Qt <6, bzip2, emscripten...)
This is completely optional.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b376fb2..4aac4ec 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,64 +3,16 @@ cmake_minimum_required(VERSION 3.15...3.18)
project(QuaZip VERSION 1.5)
-include(cmake/clone-repo.cmake)
-
set(QUAZIP_LIB_VERSION ${QuaZip_VERSION})
set(QUAZIP_LIB_SOVERSION 1.5.0)
-if(EMSCRIPTEN)
- #option(ZLIB_INCLUDE "Path to include dir" "")
- #option(ZLIB_LIBRARY "Path to library dir" "")
- option(BUILD_SHARED_LIBS "" OFF)
- option(QUAZIP_INSTALL "" OFF)
- option(QUAZIP_USE_QT_ZLIB "" OFF)
- option(QUAZIP_ENABLE_TESTS "Build QuaZip tests" OFF)
-else()
- option(BUILD_SHARED_LIBS "" ON)
- option(QUAZIP_INSTALL "" ON)
- option(QUAZIP_USE_QT_ZLIB "" OFF)
- option(QUAZIP_ENABLE_TESTS "Build QuaZip tests" OFF)
-endif()
+option(BUILD_SHARED_LIBS "" ON)
+option(QUAZIP_INSTALL "" ON)
+option(QUAZIP_ENABLE_TESTS "Build QuaZip tests" OFF)
OPTION(ZLIB_CONST "Sets ZLIB_CONST preprocessor definition" OFF)
-# Make BZIP2 optional
-option(QUAZIP_BZIP2 "Enables BZIP2 compression" ON)
-option(QUAZIP_BZIP2_STDIO "Output BZIP2 errors to stdio" ON)
-
-option(QUAZIP_FETCH_LIBS "Enables fetching third-party libraries if not found" ${WIN32})
-option(QUAZIP_FORCE_FETCH_LIBS "Enables fetching third-party libraries always" OFF)
-
-if (QUAZIP_USE_QT_ZLIB AND BUILD_SHARED_LIBS)
- message(FATAL_ERROR "Using BUILD_SHARED_LIBS=ON together with QUAZIP_USE_QT_ZLIB=ON is not supported." )
-endif()
-
-# Set the default value of `${QUAZIP_QT_MAJOR_VERSION}`.
-# We search quietly for Qt6, Qt5 and Qt4 in that order.
-# Qt6 and Qt5 provide config files for CMake.
-# Qt4 relies on `FindQt4.cmake`.
-find_package(
- QT NAMES Qt6 Qt5
- QUIET COMPONENTS Core
-)
-if (NOT QT_FOUND)
- find_package(Qt4 QUIET COMPONENTS QtCore)
- if (Qt4_FOUND)
- set(QT_VERSION_MAJOR 4)
- else()
- # If neither 6, 5 nor 4 are found, we default to 5.
- # The setup will fail further down.
- set(QT_VERSION_MAJOR 5)
- endif()
-endif()
-
-set(QUAZIP_QT_MAJOR_VERSION ${QT_VERSION_MAJOR} CACHE STRING "Qt version to use (4, 5 or 6), defaults to ${QT_VERSION_MAJOR}")
-
-if (QUAZIP_QT_MAJOR_VERSION EQUAL 6)
- set(CMAKE_CXX_STANDARD 17)
-else()
- set(CMAKE_CXX_STANDARD 14)
-endif()
+set(CMAKE_CXX_STANDARD 17)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE RELEASE)
@@ -77,92 +29,17 @@ set(QUAZIP_LIB_TARGET_NAME QuaZip)
set(QUAZIP_DIR_NAME QuaZip-Qt${QUAZIP_QT_MAJOR_VERSION}-${QUAZIP_LIB_VERSION})
set(QUAZIP_PACKAGE_NAME QuaZip-Qt${QUAZIP_QT_MAJOR_VERSION})
-message(STATUS "QUAZIP_QT_MAJOR_VERSION set to ${QUAZIP_QT_MAJOR_VERSION}")
-message(STATUS "CMAKE_CXX_STANDARD set to ${CMAKE_CXX_STANDARD}")
-
-if(QUAZIP_QT_MAJOR_VERSION EQUAL 6)
- find_package(Qt6 REQUIRED COMPONENTS Core Core5Compat
- OPTIONAL_COMPONENTS Network Test)
- message(STATUS "Found Qt version ${Qt6_VERSION} at ${Qt6_DIR}")
- set(QUAZIP_QT_ZLIB_COMPONENT BundledZLIB)
- set(QUAZIP_QT_ZLIB_HEADER_COMPONENT ZlibPrivate)
- set(QUAZIP_LIB_LIBRARIES Qt6::Core Qt6::Core5Compat)
- set(QUAZIP_TEST_QT_LIBRARIES Qt6::Core Qt6::Core5Compat Qt6::Network Qt6::Test)
- set(QUAZIP_PKGCONFIG_REQUIRES "zlib, Qt6Core")
-elseif(QUAZIP_QT_MAJOR_VERSION EQUAL 5)
- find_package(Qt5 REQUIRED COMPONENTS Core
- OPTIONAL_COMPONENTS Network Test)
- message(STATUS "Found Qt version ${Qt5_VERSION} at ${Qt5_DIR}")
- set(QUAZIP_QT_ZLIB_COMPONENT Zlib)
- set(QUAZIP_LIB_LIBRARIES Qt5::Core)
- set(QUAZIP_TEST_QT_LIBRARIES Qt5::Core Qt5::Network Qt5::Test)
- set(QUAZIP_PKGCONFIG_REQUIRES "zlib, Qt5Core")
-elseif(QUAZIP_QT_MAJOR_VERSION EQUAL 4)
- find_package(Qt4 4.5.0 REQUIRED COMPONENTS QtCore
- OPTIONAL_COMPONENTS QtNetwork QtTest)
- set(QUAZIP_QT_ZLIB_COMPONENT Zlib)
- set(QUAZIP_LIB_LIBRARIES Qt4::QtCore)
- set(QUAZIP_TEST_QT_LIBRARIES Qt4::QtCore Qt4::QtNetwork Qt4::QtTest)
- set(QUAZIP_PKGCONFIG_REQUIRES "zlib, QtCore")
-else()
- message(FATAL_ERROR "Qt version ${QUAZIP_QT_MAJOR_VERSION} is not supported")
-endif()
-
-message(STATUS "Using Qt version ${QUAZIP_QT_MAJOR_VERSION}")
-
-set(QUAZIP_QT_ZLIB_USED OFF)
-if(QUAZIP_USE_QT_ZLIB)
- find_package(Qt${QUAZIP_QT_MAJOR_VERSION} OPTIONAL_COMPONENTS ${QUAZIP_QT_ZLIB_COMPONENT})
- set(QUAZIP_QT_ZLIB_COMPONENT_FOUND Qt${QUAZIP_QT_MAJOR_VERSION}${QUAZIP_QT_ZLIB_COMPONENT}_FOUND)
- if (DEFINED QUAZIP_QT_ZLIB_HEADER_COMPONENT)
- find_package(Qt${QUAZIP_QT_MAJOR_VERSION} OPTIONAL_COMPONENTS ${QUAZIP_QT_ZLIB_HEADER_COMPONENT})
- set(QUAZIP_QT_ZLIB_HEADER_COMPONENT_FOUND Qt${QUAZIP_QT_MAJOR_VERSION}${QUAZIP_QT_ZLIB_HEADER_COMPONENT}_FOUND)
- else()
- set(QUAZIP_QT_ZLIB_HEADER_COMPONENT_FOUND ON)
- endif()
- if(QUAZIP_QT_ZLIB_COMPONENT_FOUND AND QUAZIP_QT_ZLIB_HEADER_COMPONENT_FOUND)
- message(STATUS "Qt component ${QUAZIP_QT_ZLIB_COMPONENT} found")
- set(QUAZIP_LIB_LIBRARIES ${QUAZIP_LIB_LIBRARIES} Qt${QUAZIP_QT_MAJOR_VERSION}::${QUAZIP_QT_ZLIB_COMPONENT})
- if(DEFINED QUAZIP_QT_ZLIB_HEADER_COMPONENT)
- message(STATUS "Qt component ${QUAZIP_QT_ZLIB_HEADER_COMPONENT} found")
- set(QUAZIP_LIB_LIBRARIES ${QUAZIP_LIB_LIBRARIES} Qt${QUAZIP_QT_MAJOR_VERSION}::${QUAZIP_QT_ZLIB_HEADER_COMPONENT})
- endif()
- set(QUAZIP_QT_ZLIB_USED ON)
- else()
- message(FATAL_ERROR "QUAZIP_USE_QT_ZLIB was set but bundled zlib was not found. Terminating to prevent accidental linking to system libraries.")
- endif()
-endif()
-
-if(QUAZIP_QT_ZLIB_USED AND QUAZIP_QT_ZLIB_COMPONENT STREQUAL BundledZLIB)
- # Qt's new BundledZLIB uses z-prefix in zlib
- add_compile_definitions(Z_PREFIX)
-endif()
-
-if(NOT QUAZIP_QT_ZLIB_USED)
-
- if(EMSCRIPTEN)
- if(NOT DEFINED ZLIB_LIBRARY)
- message(WARNING "ZLIB_LIBRARY is not set")
- endif()
+find_package(Qt6 REQUIRED COMPONENTS Core Core5Compat
+ OPTIONAL_COMPONENTS Network Test)
+message(STATUS "Found Qt version ${Qt6_VERSION} at ${Qt6_DIR}")
+set(QUAZIP_QT_ZLIB_COMPONENT BundledZLIB)
+set(QUAZIP_QT_ZLIB_HEADER_COMPONENT ZlibPrivate)
+set(QUAZIP_LIB_LIBRARIES Qt6::Core Qt6::Core5Compat)
+set(QUAZIP_TEST_QT_LIBRARIES Qt6::Core Qt6::Core5Compat Qt6::Network Qt6::Test)
+set(QUAZIP_PKGCONFIG_REQUIRES "zlib, Qt6Core")
- if(NOT DEFINED ZLIB_INCLUDE)
- message(WARNING "ZLIB_INCLUDE is not set")
- else()
- include_directories(${ZLIB_INCLUDE})
- endif()
-
- if(NOT DEFINED ZCONF_INCLUDE)
- message(WARNING "ZCONF_INCLUDE is not set")
- else()
- include_directories(${ZCONF_INCLUDE})
- endif()
-
- set(QUAZIP_LIB_LIBRARIES ${QUAZIP_LIB_LIBRARIES} ${ZLIB_LIBRARY})
- else()
- find_package(ZLIB REQUIRED)
- set(QUAZIP_LIB_LIBRARIES ${QUAZIP_LIB_LIBRARIES} ZLIB::ZLIB)
- endif()
-endif()
+find_package(ZLIB REQUIRED)
+set(QUAZIP_LIB_LIBRARIES ${QUAZIP_LIB_LIBRARIES} ZLIB::ZLIB)
if (ZLIB_CONST)
add_compile_definitions(ZLIB_CONST)
@@ -173,65 +50,4 @@ set(QUAZIP_INC)
set(QUAZIP_LIB)
set(QUAZIP_LBD)
-if(QUAZIP_BZIP2)
- # Check if bzip2 is present
- set(QUAZIP_BZIP2 ON)
-
- if(NOT QUAZIP_FORCE_FETCH_LIBS)
- find_package(BZip2 QUIET)
- endif()
-
- if(BZIP2_FOUND AND NOT QUAZIP_FORCE_FETCH_LIBS)
- message(STATUS "Using BZIP2 ${BZIP2_VERSION_STRING}")
-
- list(APPEND QUAZIP_INC ${BZIP2_INCLUDE_DIRS})
- list(APPEND QUAZIP_LIB ${BZIP2_LIBRARIES})
- list(APPEND QUAZIP_LBD ${BZIP2_LIBRARY_DIRS})
-
- set(PC_PRIVATE_LIBS "${PC_PRIVATE_LIBS} -lbzip2")
- elseif(QUAZIP_FETCH_LIBS)
- clone_repo(bzip2 https://sourceware.org/git/bzip2.git)
-
- # BZip2 repository does not support cmake so we have to create
- # the bzip2 library ourselves
- set(BZIP2_SRC
- ${BZIP2_SOURCE_DIR}/blocksort.c
- ${BZIP2_SOURCE_DIR}/bzlib.c
- ${BZIP2_SOURCE_DIR}/compress.c
- ${BZIP2_SOURCE_DIR}/crctable.c
- ${BZIP2_SOURCE_DIR}/decompress.c
- ${BZIP2_SOURCE_DIR}/huffman.c
- ${BZIP2_SOURCE_DIR}/randtable.c)
-
- set(BZIP2_HDR
- ${BZIP2_SOURCE_DIR}/bzlib.h
- ${BZIP2_SOURCE_DIR}/bzlib_private.h)
-
- add_library(bzip2 STATIC ${BZIP2_SRC} ${BZIP2_HDR})
-
- if(NOT QUAZIP_BZIP2_STDIO)
- target_compile_definitions(bzip2 PRIVATE -DBZ_NO_STDIO)
- endif()
-
- list(APPEND QUAZIP_DEP bzip2)
- list(APPEND QUAZIP_LIB bzip2)
- list(APPEND QUAZIP_INC ${BZIP2_SOURCE_DIR})
- else()
- message(STATUS "BZip2 library not found")
-
- set(QUAZIP_BZIP2 OFF)
- endif()
-
- if(QUAZIP_BZIP2)
- find_package(BZip2)
- add_compile_definitions(HAVE_BZIP2)
- endif()
-endif()
-
add_subdirectory(quazip)
-
-if(QUAZIP_ENABLE_TESTS)
- message(STATUS "Building QuaZip tests")
- enable_testing()
- add_subdirectory(qztest)
-endif()
diff --git a/quazip/CMakeLists.txt b/quazip/CMakeLists.txt
index 6cfdf4e..66bc4cb 100644
--- a/quazip/CMakeLists.txt
+++ b/quazip/CMakeLists.txt
@@ -46,10 +46,6 @@ set(QUAZIP_INCLUDE_PATH ${QUAZIP_DIR_NAME}/quazip)
set(QUAZIP_INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake)
set(QUAZIP_PKGCONFIG_NAME quazip${QuaZip_VERSION_MAJOR}-qt${QUAZIP_QT_MAJOR_VERSION})
-if(EMSCRIPTEN)
- set(BUILD_SHARED_LIBS OFF)
-endif()
-
add_library(${QUAZIP_LIB_TARGET_NAME} ${QUAZIP_SOURCES})
add_library(QuaZip::QuaZip ALIAS ${QUAZIP_LIB_TARGET_NAME})
diff --git a/quazip/quazip_qt_compat.h b/quazip/quazip_qt_compat.h
index 0dde011..41f9dd1 100644
--- a/quazip/quazip_qt_compat.h
+++ b/quazip/quazip_qt_compat.h
@@ -14,16 +14,11 @@
// Legacy encodings are still everywhere, but the Qt team decided we
// don't need them anymore and moved them out of Core in Qt 6.
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
-# include <QtCore5Compat/QTextCodec>
-#else
-# include <QtCore/QTextCodec>
-#endif
+#include <QtCore5Compat/QTextCodec>
// QSaveFile terribly breaks the is-a idiom (Liskov substitution principle):
// QSaveFile is-a QIODevice, but it makes close() private and aborts
// if you call it through the base class. Hence this ugly hack:
-#if (QT_VERSION >= 0x050100)
#include <QtCore/QSaveFile>
inline bool quazip_close(QIODevice *device) {
QSaveFile *file = qobject_cast<QSaveFile*>(device);
@@ -34,74 +29,35 @@ inline bool quazip_close(QIODevice *device) {
device->close();
return true;
}
-#else
-inline bool quazip_close(QIODevice *device) {
- device->close();
- return true;
-}
-#endif
-// this is yet another stupid move and deprecation
-#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
using Qt::SkipEmptyParts;
-#else
-#include <QtCore/QString>
-const auto SkipEmptyParts = QString::SplitBehavior::SkipEmptyParts;
-#endif
// and yet another... (why didn't they just make qSort delegate to std::sort?)
#include <QtCore/QList>
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
#include <algorithm>
template<typename T, typename C>
inline void quazip_sort(T begin, T end, C comparator) {
std::sort(begin, end, comparator);
}
-#else
-#include <QtCore/QtAlgorithms>
-template<typename T, typename C>
-inline void quazip_sort(T begin, T end, C comparator) {
- qSort(begin, end, comparator);
-}
-#endif
// this is a stupid rename...
#include <QtCore/QDateTime>
#include <QtCore/QFileInfo>
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
inline QDateTime quazip_ctime(const QFileInfo &fi) {
return fi.birthTime();
}
-#else
-inline QDateTime quazip_ctime(const QFileInfo &fi) {
- return fi.created();
-}
-#endif
// this is just a slightly better alternative
#include <QtCore/QFileInfo>
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
inline bool quazip_is_symlink(const QFileInfo &fi) {
return fi.isSymbolicLink();
}
-#else
-inline bool quazip_is_symlink(const QFileInfo &fi) {
- // also detects *.lnk on Windows, but better than nothing
- return fi.isSymLink();
-}
-#endif
// I'm not even sure what this one is, but nevertheless
#include <QtCore/QFileInfo>
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0))
inline QString quazip_symlink_target(const QFileInfo &fi) {
return fi.symLinkTarget();
}
-#else
-inline QString quazip_symlink_target(const QFileInfo &fi) {
- return fi.readLink(); // What's the difference? I've no idea.
-}
-#endif
// deprecation
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
@@ -125,40 +81,19 @@ inline QDateTime quazip_since_epoch_ntfs() {
// this is not a deprecation but an improvement, for a change
#include <QtCore/QDateTime>
-#if (QT_VERSION >= 0x040700)
inline quint64 quazip_ntfs_ticks(const QDateTime &time, int fineTicks) {
QDateTime base = quazip_since_epoch_ntfs();
return base.msecsTo(time) * 10000 + fineTicks;
}
-#else
-inline quint64 quazip_ntfs_ticks(const QDateTime &time, int fineTicks) {
- QDateTime base = quazip_since_epoch_ntfs();
- QDateTime utc = time.toUTC();
- return (static_cast<qint64>(base.date().daysTo(utc.date()))
- * Q_INT64_C(86400000)
- + static_cast<qint64>(base.time().msecsTo(utc.time())))
- * Q_INT64_C(10000) + fineTicks;
-}
-#endif
// yet another improvement...
#include <QtCore/QDateTime>
-#if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0) // Yay! Finally a way to get time as qint64!
inline qint64 quazip_to_time64_t(const QDateTime &time) {
return time.toSecsSinceEpoch();
}
-#else
-inline qint64 quazip_to_time64_t(const QDateTime &time) {
- return static_cast<qint64>(time.toTime_t()); // 32 bits only, but better than nothing
-}
-#endif
#include <QtCore/QTextStream>
-// and another stupid move
-#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
const auto quazip_endl = Qt::endl;
-#else
-const auto quazip_endl = endl;
-#endif
#endif // QUAZIP_QT_COMPAT_H
+

View file

@ -60,7 +60,7 @@ endif()
if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
option(YUZU_USE_EXTERNAL_VULKAN_HEADERS "Use Vulkan-Headers from externals" OFF)
else()
option(YUZU_USE_EXTERNAL_VULKAN_HEADERS "Use Vulkan-Headers from externals" ON)
option(YUZU_USE_EXTERNAL_VULKAN_HEADERS "Use Vulkan-Headers from externals" ON)
endif()
if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
@ -79,6 +79,8 @@ option(YUZU_USE_QT_MULTIMEDIA "Use QtMultimedia for Camera" OFF)
option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF)
set(YUZU_QT_MIRROR "" CACHE STRING "What mirror to use for downloading the bundled Qt libraries")
option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF)
@ -465,12 +467,10 @@ if (ENABLE_QT)
list(APPEND CMAKE_PREFIX_PATH "${Qt6_DIR}")
endif()
# QT6 Multimedia pulls in unneeded audio systems (ALSA, Pulseaudio) for FreeBSD
# ALSA is the default sound system on Linux, but FreeBSD uses OSS which works well enough
if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
find_package(Qt6 REQUIRED COMPONENTS Widgets Concurrent)
else()
find_package(Qt6 REQUIRED COMPONENTS Widgets Multimedia Concurrent)
find_package(Qt6 REQUIRED COMPONENTS Widgets Concurrent)
if (YUZU_USE_QT_MULTIMEDIA)
find_package(Qt6 REQUIRED COMPONENTS Multimedia)
endif()
if (UNIX AND NOT APPLE)

24
CMakeModules/CPM.cmake Normal file
View file

@ -0,0 +1,24 @@
# SPDX-License-Identifier: MIT
#
# SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors
set(CPM_DOWNLOAD_VERSION 0.42.0)
set(CPM_HASH_SUM "2020b4fc42dba44817983e06342e682ecfc3d2f484a581f11cc5731fbe4dce8a")
if(CPM_SOURCE_CACHE)
set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
elseif(DEFINED ENV{CPM_SOURCE_CACHE})
set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
else()
set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
endif()
# Expand relative path. This is important if the provided path contains a tilde (~)
get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE)
file(DOWNLOAD
https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM}
)
include(${CPM_DOWNLOAD_LOCATION})

View file

@ -94,7 +94,7 @@ function(determine_qt_parameters target host_out type_out arch_out arch_path_out
else()
set(host "linux")
set(type "desktop")
set(arch "gcc_64")
set(arch "linux_gcc_64")
set(arch_path "linux")
endif()
@ -133,12 +133,26 @@ function(download_qt_configuration prefix_out target host type arch arch_path ba
set(install_args ${install_args} install-tool --outputdir ${base_path} ${host} desktop ${target})
else()
set(prefix "${base_path}/${target}/${arch_path}")
set(install_args ${install_args} install-qt --outputdir ${base_path} ${host} ${type} ${target} ${arch} -m qt3d qt5compat qtactiveqt qtcharts qtconnectivity qtdatavis3d qtgraphs qtgrpc qthttpserver qtimageformats qtlanguageserver qtlocation qtlottie qtmultimedia qtnetworkauth qtpdf qtpositioning qtquick3d qtquick3dphysics qtquickeffectmaker qtquicktimeline qtremoteobjects qtscxml qtsensors qtserialbus qtserialport qtshadertools qtspeech qtvirtualkeyboard qtwebchannel qtwebengine qtwebsockets qtwebview)
set(install_args ${install_args} install-qt --outputdir ${base_path} ${host} ${type} ${target} ${arch} -m qt_base)
if (YUZU_USE_QT_MULTIMEDIA)
set(install_args ${install_args} qtmultimedia)
endif()
if (YUZU_USE_QT_WEB_ENGINE)
set(install_args ${install_args} qtpositioning qtwebchannel qtwebengine)
endif()
if (NOT ${YUZU_QT_MIRROR} STREQUAL "")
message(STATUS "Using Qt mirror ${YUZU_QT_MIRROR}")
set(install_args ${install_args} -b ${YUZU_QT_MIRROR})
endif()
endif()
message(STATUS "Install Args ${install_args}")
if (NOT EXISTS "${prefix}")
message(STATUS "Downloading Qt binaries for ${target}:${host}:${type}:${arch}:${arch_path}")
set(AQT_PREBUILD_BASE_URL "https://github.com/miurahr/aqtinstall/releases/download/v3.2.1")
set(AQT_PREBUILD_BASE_URL "https://github.com/miurahr/aqtinstall/releases/download/v3.3.0")
if (WIN32)
set(aqt_path "${base_path}/aqt.exe")
if (NOT EXISTS "${aqt_path}")

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD

View file

@ -1,6 +1,6 @@
# This file has been adapted from dynarmic
cmake_minimum_required(VERSION 3.8)
cmake_minimum_required(VERSION 3.12)
project(sirit CXX)
# Determine if we're built as a subproject (using add_subdirectory)

View file

@ -34,6 +34,7 @@ import org.yuzu.yuzu_emu.databinding.ItemBanListBinding
import org.yuzu.yuzu_emu.databinding.ItemButtonNetplayBinding
import org.yuzu.yuzu_emu.databinding.ItemTextNetplayBinding
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
import org.yuzu.yuzu_emu.network.NetDataValidators
import org.yuzu.yuzu_emu.network.NetPlayManager
import org.yuzu.yuzu_emu.utils.CompatUtils
import org.yuzu.yuzu_emu.utils.GameHelper
@ -102,8 +103,16 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
dismiss()
}
btnLobbyBrowser.setOnClickListener {
LobbyBrowser(context).show()
dismiss()
if (!NetDataValidators.username()) {
Toast.makeText(
context,
R.string.multiplayer_nickname_invalid,
Toast.LENGTH_LONG
).show()
} else {
LobbyBrowser(context).show()
dismiss()
}
}
}
}
@ -368,7 +377,7 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
)
) {
override fun validate(s: String): Boolean {
return s.length in 3..20
return NetDataValidators.roomName(s)
}
}
@ -378,7 +387,7 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
context.getString(R.string.multiplayer_required)
) {
override fun validate(s: String): Boolean {
return s.isNotEmpty()
return NetDataValidators.notEmpty(s)
}
}
@ -388,12 +397,7 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
context.getString(R.string.multiplayer_token_required)
) {
override fun validate(s: String): Boolean {
if (s != context.getString(R.string.multiplayer_public_visibility)) {
return true;
}
val token = StringSetting.WEB_TOKEN.getString()
return token.matches(Regex("[a-z]{48}"))
return NetDataValidators.roomVisibility(s, context)
}
}
@ -403,12 +407,7 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
context.getString(R.string.multiplayer_ip_error)
) {
override fun validate(s: String): Boolean {
return try {
InetAddress.getByName(s)
s.length >= 7
} catch (_: Exception) {
false
}
return NetDataValidators.ipAddress(s)
}
}
@ -418,7 +417,7 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
context.getString(R.string.multiplayer_username_error)
) {
override fun validate(s: String): Boolean {
return s.length in 4..20
return NetDataValidators.username(s)
}
}
@ -428,7 +427,7 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
context.getString(R.string.multiplayer_port_error)
) {
override fun validate(s: String): Boolean {
return s.toIntOrNull() in 1..65535
return NetDataValidators.port(s)
}
}

View file

@ -20,6 +20,7 @@ import org.yuzu.yuzu_emu.features.settings.model.IntSetting
import org.yuzu.yuzu_emu.features.settings.model.LongSetting
import org.yuzu.yuzu_emu.features.settings.model.ShortSetting
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
import org.yuzu.yuzu_emu.network.NetDataValidators
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.NativeConfig
@ -300,9 +301,7 @@ abstract class SettingsItem(
val chars = "abcdefghijklmnopqrstuvwxyz"
(1..48).map { chars.random() }.joinToString("")
},
validator = { s ->
s?.matches(Regex("[a-z]{48}")) == true
},
validator = NetDataValidators::token,
errorId = R.string.multiplayer_token_error
)
)
@ -312,9 +311,7 @@ abstract class SettingsItem(
StringSetting.WEB_USERNAME,
titleId = R.string.web_username,
descriptionId = R.string.web_username_description,
validator = { s ->
s?.length in 4..20
},
validator = NetDataValidators::username,
errorId = R.string.multiplayer_username_error
)
)

View file

@ -154,8 +154,6 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
stringInputBinding.generate.setOnClickListener {
stringInputBinding.editText.setText(onGenerate())
}
} else {
stringInputBinding.generate.isVisible = false
}
val validator = item.validator
@ -179,8 +177,9 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
}
override fun afterTextChanged(s: Editable?) {
stringInputBinding.editText.error =
if (validator(s.toString())) null else requireContext().getString(item.errorId)
val isValid = validator(s.toString())
stringInputBinding.editTextLayout.isErrorEnabled = !isValid
stringInputBinding.editTextLayout.error = if (isValid) null else requireContext().getString(item.errorId)
}
}

View file

@ -0,0 +1,56 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.network
import android.content.Context
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
import java.net.InetAddress
object NetDataValidators {
fun roomName(s: String): Boolean {
return s.length in 3..20
}
fun notEmpty(s: String): Boolean {
return s.isNotEmpty()
}
fun token(s: String?): Boolean {
return s?.matches(Regex("[a-z]{48}")) == true
}
fun token(): Boolean {
return token(StringSetting.WEB_TOKEN.getString())
}
fun roomVisibility(s: String, context: Context): Boolean {
if (s != context.getString(R.string.multiplayer_public_visibility)) {
return true;
}
return token()
}
fun ipAddress(s: String): Boolean {
return try {
InetAddress.getByName(s)
s.length >= 7
} catch (_: Exception) {
false
}
}
fun username(s: String?): Boolean {
return s?.matches(Regex("^[ a-zA-Z0-9._-]{4,20}$")) == true
}
fun username(): Boolean {
return username(StringSetting.WEB_USERNAME.getString())
}
fun port(s: String): Boolean {
return s.toIntOrNull() in 1..65535
}
}

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -177,6 +180,10 @@ object GpuDriverHelper {
* @return A non-null [GpuDriverMetadata] instance that may have null members
*/
fun getMetadataFromZip(driver: File): GpuDriverMetadata {
if (!driver.exists()) {
return GpuDriverMetadata()
}
try {
ZipFile(driver).use { zf ->
val entries = zf.entries()

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View file

@ -1,751 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="512dp"
android:height="512dp"
android:viewportWidth="512"
android:viewportHeight="512">
<group>
<clip-path
android:pathData="M0,0h512v512h-512z"/>
<path
android:pathData="M0,0h512v512h-512z"
android:fillColor="#ffffff"/>
<path
android:pathData="M0,0h512v512h-512z"
android:fillColor="#1C1C1C"/>
<path
android:pathData="M208.16,7H159.88C155.54,7 152,10.54 152,14.88V92.16C152,96.54 155.54,100.04 159.88,100.04H208.12C212.5,100.04 216,96.5 216,92.16V14.88C216.04,10.54 212.5,7 208.16,7Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M208.8,89.73H158.44C156.65,89.73 155.18,88.26 155.18,86.47V17.02C155.18,15.23 156.65,13.76 158.44,13.76H208.84C210.63,13.76 212.1,15.23 212.1,17.02V86.51C212.06,88.26 210.59,89.73 208.8,89.73Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M194.16,14.16H173.08V12.93C173.08,12.29 173.6,11.77 174.24,11.77H193.01C193.65,11.77 194.16,12.29 194.16,12.93V14.16Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M183.86,97.29L177.93,92.92H189.79L183.86,97.29Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M424.16,7H375.88C371.54,7 368,10.54 368,14.88V92.16C368,96.54 371.54,100.04 375.88,100.04H424.12C428.5,100.04 432,96.5 432,92.16V14.88C432.04,10.54 428.5,7 424.16,7Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M424.8,89.73H374.44C372.65,89.73 371.18,88.26 371.18,86.47V17.02C371.18,15.23 372.65,13.76 374.44,13.76H424.84C426.63,13.76 428.1,15.23 428.1,17.02V86.51C428.06,88.26 426.59,89.73 424.8,89.73Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M410.16,14.16H389.08V12.93C389.08,12.29 389.6,11.77 390.23,11.77H409.01C409.65,11.77 410.16,12.29 410.16,12.93V14.16Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M399.86,97.29L393.93,92.92H405.79L399.86,97.29Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M352.16,109H303.88C299.54,109 296,112.54 296,116.88V194.16C296,198.54 299.54,202.04 303.88,202.04H352.12C356.5,202.04 360,198.5 360,194.16V116.88C360.04,112.54 356.5,109 352.16,109Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M352.8,191.73H302.44C300.65,191.73 299.18,190.26 299.18,188.47V119.02C299.18,117.23 300.65,115.76 302.44,115.76H352.84C354.63,115.76 356.1,117.23 356.1,119.02V188.51C356.06,190.26 354.59,191.73 352.8,191.73Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M338.16,116.16H317.08V114.93C317.08,114.29 317.6,113.77 318.23,113.77H337.01C337.65,113.77 338.16,114.29 338.16,114.93V116.16Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M327.86,199.29L321.93,194.92H333.79L327.86,199.29Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M496.16,7H447.88C443.54,7 440,10.54 440,14.88V92.16C440,96.54 443.54,100.04 447.88,100.04H496.12C500.5,100.04 504,96.5 504,92.16V14.88C504.04,10.54 500.5,7 496.16,7Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M496.8,89.73H446.44C444.65,89.73 443.18,88.26 443.18,86.47V17.02C443.18,15.23 444.65,13.76 446.44,13.76H496.84C498.63,13.76 500.1,15.23 500.1,17.02V86.51C500.06,88.26 498.59,89.73 496.8,89.73Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M482.16,14.16H461.08V12.93C461.08,12.29 461.6,11.77 462.23,11.77H481.01C481.65,11.77 482.16,12.29 482.16,12.93V14.16Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M471.86,97.29L465.93,92.92H477.79L471.86,97.29Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M352.16,7H303.88C299.54,7 296,10.54 296,14.88V92.16C296,96.54 299.54,100.04 303.88,100.04H352.12C356.5,100.04 360,96.5 360,92.16V14.88C360.04,10.54 356.5,7 352.16,7Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M352.8,89.73H302.44C300.65,89.73 299.18,88.26 299.18,86.47V17.02C299.18,15.23 300.65,13.76 302.44,13.76H352.84C354.63,13.76 356.1,15.23 356.1,17.02V86.51C356.06,88.26 354.59,89.73 352.8,89.73Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M338.16,14.16H317.08V12.93C317.08,12.29 317.6,11.77 318.23,11.77H337.01C337.65,11.77 338.16,12.29 338.16,12.93V14.16Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M327.86,97.29L321.93,92.92H333.79L327.86,97.29Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M280.16,7H231.88C227.54,7 224,10.54 224,14.88V92.16C224,96.54 227.54,100.04 231.88,100.04H280.12C284.5,100.04 288,96.5 288,92.16V14.88C288.04,10.54 284.5,7 280.16,7Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M280.8,89.73H230.44C228.65,89.73 227.18,88.26 227.18,86.47V17.02C227.18,15.23 228.65,13.76 230.44,13.76H280.84C282.63,13.76 284.1,15.23 284.1,17.02V86.51C284.06,88.26 282.59,89.73 280.8,89.73Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M266.16,14.16H245.08V12.93C245.08,12.29 245.6,11.77 246.24,11.77H265.01C265.65,11.77 266.16,12.29 266.16,12.93V14.16Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M255.86,97.29L249.93,92.92H261.79L255.86,97.29Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M424.16,109H375.88C371.54,109 368,112.54 368,116.88V194.16C368,198.54 371.54,202.04 375.88,202.04H424.12C428.5,202.04 432,198.5 432,194.16V116.88C432.04,112.54 428.5,109 424.16,109Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M135.16,411H86.88C82.54,411 79,414.54 79,418.88V496.16C79,500.54 82.54,504.04 86.88,504.04H135.12C139.5,504.04 143,500.5 143,496.16V418.88C143.04,414.54 139.5,411 135.16,411Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M64.16,7H15.88C11.54,7 8,10.54 8,14.88V92.16C8,96.54 11.54,100.04 15.88,100.04H64.12C68.5,100.04 72,96.5 72,92.16V14.88C72.04,10.54 68.5,7 64.16,7Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M64.8,89.73H14.44C12.65,89.73 11.18,88.26 11.18,86.47V17.02C11.18,15.23 12.65,13.76 14.44,13.76H64.84C66.63,13.76 68.1,15.23 68.1,17.02V86.51C68.06,88.26 66.59,89.73 64.8,89.73Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M50.16,14.16H29.08V12.93C29.08,12.29 29.6,11.77 30.23,11.77H49.01C49.65,11.77 50.16,12.29 50.16,12.93V14.16Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M39.86,97.29L33.93,92.92H45.79L39.86,97.29Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M63.16,310H14.88C10.54,310 7,313.54 7,317.88V395.16C7,399.54 10.54,403.04 14.88,403.04H63.12C67.5,403.04 71,399.5 71,395.16V317.88C71.04,313.54 67.5,310 63.16,310Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M63.8,392.73H13.44C11.65,392.73 10.18,391.26 10.18,389.47V320.02C10.18,318.23 11.65,316.76 13.44,316.76H63.84C65.63,316.76 67.1,318.23 67.1,320.02V389.51C67.06,391.26 65.59,392.73 63.8,392.73Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M49.16,317.16H28.08V315.93C28.08,315.29 28.6,314.77 29.23,314.77H48.01C48.65,314.77 49.16,315.29 49.16,315.93V317.16Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M38.86,400.29L32.93,395.92H44.79L38.86,400.29Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M424.16,209H375.88C371.54,209 368,212.54 368,216.88V294.16C368,298.54 371.54,302.04 375.88,302.04H424.12C428.5,302.04 432,298.5 432,294.16V216.88C432.04,212.54 428.5,209 424.16,209Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M424.8,291.73H374.44C372.65,291.73 371.18,290.26 371.18,288.47V219.02C371.18,217.23 372.65,215.76 374.44,215.76H424.84C426.63,215.76 428.1,217.23 428.1,219.02V288.51C428.06,290.26 426.59,291.73 424.8,291.73Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M410.16,216.16H389.08V214.93C389.08,214.29 389.6,213.77 390.23,213.77H409.01C409.65,213.77 410.16,214.29 410.16,214.93V216.16Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M399.86,299.29L393.93,294.92H405.79L399.86,299.29Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M496.16,209H447.88C443.54,209 440,212.54 440,216.88V294.16C440,298.54 443.54,302.04 447.88,302.04H496.12C500.5,302.04 504,298.5 504,294.16V216.88C504.04,212.54 500.5,209 496.16,209Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M496.8,291.73H446.44C444.65,291.73 443.18,290.26 443.18,288.47V219.02C443.18,217.23 444.65,215.76 446.44,215.76H496.84C498.63,215.76 500.1,217.23 500.1,219.02V288.51C500.06,290.26 498.59,291.73 496.8,291.73Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M482.16,216.16H461.08V214.93C461.08,214.29 461.6,213.77 462.23,213.77H481.01C481.65,213.77 482.16,214.29 482.16,214.93V216.16Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M471.86,299.29L465.93,294.92H477.79L471.86,299.29Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M136.16,209H87.88C83.54,209 80,212.54 80,216.88V294.16C80,298.54 83.54,302.04 87.88,302.04H136.12C140.5,302.04 144,298.5 144,294.16V216.88C144.04,212.54 140.5,209 136.16,209Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M136.8,291.73H86.44C84.65,291.73 83.18,290.26 83.18,288.47V219.02C83.18,217.23 84.65,215.76 86.44,215.76H136.84C138.63,215.76 140.1,217.23 140.1,219.02V288.51C140.06,290.26 138.59,291.73 136.8,291.73Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M122.16,216.16H101.08V214.93C101.08,214.29 101.6,213.77 102.24,213.77H121.01C121.65,213.77 122.16,214.29 122.16,214.93V216.16Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M111.86,299.29L105.93,294.92H117.79L111.86,299.29Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M352.16,209H303.88C299.54,209 296,212.54 296,216.88V294.16C296,298.54 299.54,302.04 303.88,302.04H352.12C356.5,302.04 360,298.5 360,294.16V216.88C360.04,212.54 356.5,209 352.16,209Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M352.8,291.73H302.44C300.65,291.73 299.18,290.26 299.18,288.47V219.02C299.18,217.23 300.65,215.76 302.44,215.76H352.84C354.63,215.76 356.1,217.23 356.1,219.02V288.51C356.06,290.26 354.59,291.73 352.8,291.73Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M338.16,216.16H317.08V214.93C317.08,214.29 317.6,213.77 318.23,213.77H337.01C337.65,213.77 338.16,214.29 338.16,214.93V216.16Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M327.86,299.29L321.93,294.92H333.79L327.86,299.29Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M64.16,209H15.88C11.54,209 8,212.54 8,216.88V294.16C8,298.54 11.54,302.04 15.88,302.04H64.12C68.5,302.04 72,298.5 72,294.16V216.88C72.04,212.54 68.5,209 64.16,209Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M64.8,291.73H14.44C12.65,291.73 11.18,290.26 11.18,288.47V219.02C11.18,217.23 12.65,215.76 14.44,215.76H64.84C66.63,215.76 68.1,217.23 68.1,219.02V288.51C68.06,290.26 66.59,291.73 64.8,291.73Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M50.16,216.16H29.08V214.93C29.08,214.29 29.6,213.77 30.23,213.77H49.01C49.65,213.77 50.16,214.29 50.16,214.93V216.16Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M39.86,299.29L33.93,294.92H45.79L39.86,299.29Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M135.16,310H86.88C82.54,310 79,313.54 79,317.88V395.16C79,399.54 82.54,403.04 86.88,403.04H135.12C139.5,403.04 143,399.5 143,395.16V317.88C143.04,313.54 139.5,310 135.16,310Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M135.8,392.73H85.44C83.65,392.73 82.18,391.26 82.18,389.47V320.02C82.18,318.23 83.65,316.76 85.44,316.76H135.84C137.63,316.76 139.1,318.23 139.1,320.02V389.51C139.06,391.26 137.59,392.73 135.8,392.73Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M121.16,317.16H100.08V315.93C100.08,315.29 100.6,314.77 101.24,314.77H120.01C120.65,314.77 121.16,315.29 121.16,315.93V317.16Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M110.86,400.29L104.93,395.92H116.79L110.86,400.29Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M208.16,108H159.88C155.54,108 152,111.54 152,115.88V193.16C152,197.54 155.54,201.04 159.88,201.04H208.12C212.5,201.04 216,197.5 216,193.16V115.88C216.04,111.54 212.5,108 208.16,108Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M208.8,190.73H158.44C156.65,190.73 155.18,189.26 155.18,187.47V118.02C155.18,116.23 156.65,114.76 158.44,114.76H208.84C210.63,114.76 212.1,116.23 212.1,118.02V187.51C212.06,189.26 210.59,190.73 208.8,190.73Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M194.16,115.16H173.08V113.93C173.08,113.29 173.6,112.77 174.24,112.77H193.01C193.65,112.77 194.16,113.29 194.16,113.93V115.16Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M183.86,198.29L177.93,193.92H189.79L183.86,198.29Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M496.16,108H447.88C443.54,108 440,111.54 440,115.88V193.16C440,197.54 443.54,201.04 447.88,201.04H496.12C500.5,201.04 504,197.5 504,193.16V115.88C504.04,111.54 500.5,108 496.16,108Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M496.8,190.73H446.44C444.65,190.73 443.18,189.26 443.18,187.47V118.02C443.18,116.23 444.65,114.76 446.44,114.76H496.84C498.63,114.76 500.1,116.23 500.1,118.02V187.51C500.06,189.26 498.59,190.73 496.8,190.73Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M482.16,115.16H461.08V113.93C461.08,113.29 461.6,112.77 462.23,112.77H481.01C481.65,112.77 482.16,113.29 482.16,113.93V115.16Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M471.86,198.29L465.93,193.92H477.79L471.86,198.29Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M64.16,108H15.88C11.54,108 8,111.54 8,115.88V193.16C8,197.54 11.54,201.04 15.88,201.04H64.12C68.5,201.04 72,197.5 72,193.16V115.88C72.04,111.54 68.5,108 64.16,108Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M64.8,190.73H14.44C12.65,190.73 11.18,189.26 11.18,187.47V118.02C11.18,116.23 12.65,114.76 14.44,114.76H64.84C66.63,114.76 68.1,116.23 68.1,118.02V187.51C68.06,189.26 66.59,190.73 64.8,190.73Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M50.16,115.16H29.08V113.93C29.08,113.29 29.6,112.77 30.23,112.77H49.01C49.65,112.77 50.16,113.29 50.16,113.93V115.16Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M39.86,198.29L33.93,193.92H45.79L39.86,198.29Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M280.16,108H231.88C227.54,108 224,111.54 224,115.88V193.16C224,197.54 227.54,201.04 231.88,201.04H280.12C284.5,201.04 288,197.5 288,193.16V115.88C288.04,111.54 284.5,108 280.16,108Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M280.8,190.73H230.44C228.65,190.73 227.18,189.26 227.18,187.47V118.02C227.18,116.23 228.65,114.76 230.44,114.76H280.84C282.63,114.76 284.1,116.23 284.1,118.02V187.51C284.06,189.26 282.59,190.73 280.8,190.73Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M266.16,115.16H245.08V113.93C245.08,113.29 245.6,112.77 246.24,112.77H265.01C265.65,112.77 266.16,113.29 266.16,113.93V115.16Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M255.86,198.29L249.93,193.92H261.79L255.86,198.29Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M496.16,310H447.88C443.54,310 440,313.54 440,317.88V395.16C440,399.54 443.54,403.04 447.88,403.04H496.12C500.5,403.04 504,399.5 504,395.16V317.88C504.04,313.54 500.5,310 496.16,310Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M496.8,392.73H446.44C444.65,392.73 443.18,391.26 443.18,389.47V320.02C443.18,318.23 444.65,316.76 446.44,316.76H496.84C498.63,316.76 500.1,318.23 500.1,320.02V389.51C500.06,391.26 498.59,392.73 496.8,392.73Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M482.16,317.16H461.08V315.93C461.08,315.29 461.6,314.77 462.23,314.77H481.01C481.65,314.77 482.16,315.29 482.16,315.93V317.16Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M471.86,400.29L465.93,395.92H477.79L471.86,400.29Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M352.16,310H303.88C299.54,310 296,313.54 296,317.88V395.16C296,399.54 299.54,403.04 303.88,403.04H352.12C356.5,403.04 360,399.5 360,395.16V317.88C360.04,313.54 356.5,310 352.16,310Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M352.8,392.73H302.44C300.65,392.73 299.18,391.26 299.18,389.47V320.02C299.18,318.23 300.65,316.76 302.44,316.76H352.84C354.63,316.76 356.1,318.23 356.1,320.02V389.51C356.06,391.26 354.59,392.73 352.8,392.73Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M338.16,317.16H317.08V315.93C317.08,315.29 317.6,314.77 318.23,314.77H337.01C337.65,314.77 338.16,315.29 338.16,315.93V317.16Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M327.86,400.29L321.93,395.92H333.79L327.86,400.29Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M63.16,411H14.88C10.54,411 7,414.54 7,418.88V496.16C7,500.54 10.54,504.04 14.88,504.04H63.12C67.5,504.04 71,500.5 71,496.16V418.88C71.04,414.54 67.5,411 63.16,411Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M63.8,493.73H13.44C11.65,493.73 10.18,492.26 10.18,490.47V421.02C10.18,419.23 11.65,417.76 13.44,417.76H63.84C65.63,417.76 67.1,419.23 67.1,421.02V490.51C67.06,492.26 65.59,493.73 63.8,493.73Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M49.16,418.16H28.08V416.93C28.08,416.29 28.6,415.77 29.23,415.77H48.01C48.65,415.77 49.16,416.29 49.16,416.93V418.16Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M38.86,501.29L32.93,496.92H44.79L38.86,501.29Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M496.16,411H447.88C443.54,411 440,414.54 440,418.88V496.16C440,500.54 443.54,504.04 447.88,504.04H496.12C500.5,504.04 504,500.5 504,496.16V418.88C504.04,414.54 500.5,411 496.16,411Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M496.8,493.73H446.44C444.65,493.73 443.18,492.26 443.18,490.47V421.02C443.18,419.23 444.65,417.76 446.44,417.76H496.84C498.63,417.76 500.1,419.23 500.1,421.02V490.51C500.06,492.26 498.59,493.73 496.8,493.73Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M482.16,418.16H461.08V416.93C461.08,416.29 461.6,415.77 462.23,415.77H481.01C481.65,415.77 482.16,416.29 482.16,416.93V418.16Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M471.86,501.29L465.93,496.92H477.79L471.86,501.29Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M352.16,411H303.88C299.54,411 296,414.54 296,418.88V496.16C296,500.54 299.54,504.04 303.88,504.04H352.12C356.5,504.04 360,500.5 360,496.16V418.88C360.04,414.54 356.5,411 352.16,411Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M352.8,493.73H302.44C300.65,493.73 299.18,492.26 299.18,490.47V421.02C299.18,419.23 300.65,417.76 302.44,417.76H352.84C354.63,417.76 356.1,419.23 356.1,421.02V490.51C356.06,492.26 354.59,493.73 352.8,493.73Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M338.16,418.16H317.08V416.93C317.08,416.29 317.6,415.77 318.23,415.77H337.01C337.65,415.77 338.16,416.29 338.16,416.93V418.16Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M327.86,501.29L321.93,496.92H333.79L327.86,501.29Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M208.16,411H159.88C155.54,411 152,414.54 152,418.88V496.16C152,500.54 155.54,504.04 159.88,504.04H208.12C212.5,504.04 216,500.5 216,496.16V418.88C216.04,414.54 212.5,411 208.16,411Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M208.8,493.73H158.44C156.65,493.73 155.18,492.26 155.18,490.47V421.02C155.18,419.23 156.65,417.76 158.44,417.76H208.84C210.63,417.76 212.1,419.23 212.1,421.02V490.51C212.06,492.26 210.59,493.73 208.8,493.73Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M194.16,418.16H173.08V416.93C173.08,416.29 173.6,415.77 174.24,415.77H193.01C193.65,415.77 194.16,416.29 194.16,416.93V418.16Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M183.86,501.29L177.93,496.92H189.79L183.86,501.29Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M280.16,411H231.88C227.54,411 224,414.54 224,418.88V496.16C224,500.54 227.54,504.04 231.88,504.04H280.12C284.5,504.04 288,500.5 288,496.16V418.88C288.04,414.54 284.5,411 280.16,411Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M280.8,493.73H230.44C228.65,493.73 227.18,492.26 227.18,490.47V421.02C227.18,419.23 228.65,417.76 230.44,417.76H280.84C282.63,417.76 284.1,419.23 284.1,421.02V490.51C284.06,492.26 282.59,493.73 280.8,493.73Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M266.16,418.16H245.08V416.93C245.08,416.29 245.6,415.77 246.24,415.77H265.01C265.65,415.77 266.16,416.29 266.16,416.93V418.16Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M255.86,501.29L249.93,496.92H261.79L255.86,501.29Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<group>
<clip-path
android:pathData="M80,8h64v192h-64z"/>
<path
android:pathData="M112.06,8H144.11V200H112.06C94.32,200 80,185.68 80,167.96V40.04C80,22.31 94.32,8 112.06,8Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M138.2,26.4H128.43C128.31,26.4 128.31,26.29 128.31,26.18V23.79C128.31,23.68 128.43,23.56 128.43,23.56H138.2C138.32,23.56 138.32,23.68 138.32,23.79V26.18C138.32,26.29 138.2,26.4 138.2,26.4Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M129.9,142.85V147.63C129.9,149.67 128.31,151.26 126.27,151.26H121.49C119.45,151.26 117.85,149.67 117.85,147.63V142.85C117.85,140.81 119.45,139.22 121.49,139.22H126.27C128.31,139.33 129.9,140.92 129.9,142.85Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M113.76,65.26C120.1,65.26 125.24,60.12 125.24,53.78C125.24,47.45 120.1,42.31 113.76,42.31C107.42,42.31 102.28,47.45 102.28,53.78C102.28,60.12 107.42,65.26 113.76,65.26Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M112.85,39.02V40.95C112.85,40.95 112.85,41.06 112.74,41.06C106.49,41.51 101.49,46.51 100.92,52.88C100.92,52.88 100.92,52.99 100.8,52.99H98.98C98.98,52.99 98.87,52.99 98.87,52.88C98.87,52.53 98.87,52.31 98.98,51.97C100.01,44.7 105.92,39.47 112.85,39.02Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M128.54,54.69C128.65,55.03 128.54,55.38 128.54,55.72C127.63,62.87 121.72,68.1 114.9,68.55C114.9,68.55 114.79,68.55 114.79,68.44V66.62C114.79,66.62 114.79,66.51 114.9,66.51C121.15,66.05 126.15,61.06 126.72,54.69C126.72,54.69 126.72,54.58 126.83,54.58H128.54V54.69Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M128.54,52.88H126.61C126.61,52.88 126.49,52.88 126.49,52.76C126.04,46.51 121.04,41.51 114.67,40.95C114.67,40.95 114.56,40.95 114.56,40.83V39.02C114.56,39.02 114.56,38.9 114.67,38.9C115.01,38.9 115.24,38.9 115.58,39.02C122.86,40.04 128.09,45.83 128.54,52.88Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M112.85,66.62V68.44C112.85,68.44 112.85,68.55 112.74,68.55C112.4,68.55 112.17,68.55 111.83,68.44C104.67,67.53 99.44,61.62 98.98,54.81C98.98,54.81 98.98,54.69 99.1,54.69H100.92C100.92,54.69 101.03,54.69 101.03,54.81C101.49,61.06 106.49,66.05 112.85,66.62C112.85,66.51 112.85,66.51 112.85,66.62Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M108.08,109.68C108.08,113.66 104.89,116.84 100.92,116.84C96.94,116.84 93.64,113.66 93.64,109.68C93.64,105.7 96.82,102.52 100.92,102.52C104.89,102.52 108.08,105.7 108.08,109.68Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M120.7,97.18C120.7,101.16 117.51,104.34 113.42,104.34C109.44,104.34 106.26,101.16 106.26,97.18C106.26,93.21 109.44,90.03 113.42,90.03C117.4,89.91 120.7,93.21 120.7,97.18Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M133.2,109.68C133.2,113.66 130.02,116.84 126.04,116.84C122.06,116.84 118.88,113.66 118.88,109.68C118.88,105.7 122.06,102.52 126.04,102.52C129.9,102.52 133.2,105.7 133.2,109.68Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M120.7,122.29C120.7,126.27 117.51,129.45 113.42,129.45C109.44,129.45 106.26,126.27 106.26,122.29C106.26,118.32 109.44,115.13 113.42,115.13C117.4,115.02 120.7,118.32 120.7,122.29Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
</group>
<path
android:pathData="M157.99,209.4C157.87,209.5 157.75,209.7 157.75,210C157.75,210.5 157.63,210.8 157.51,211.01C157.03,211.81 155.83,212.21 154.51,212.21L152.95,212.21C152.95,212.21 152.71,212.21 152.59,212.31C152.47,212.41 152.47,212.51 152.47,212.61L152.47,399.35C152.47,399.45 152.47,399.45 152.47,399.55C152.59,399.75 152.83,399.85 153.07,399.85L154.87,399.85C154.87,399.85 156.31,399.75 157.15,400.65C157.75,401.36 157.75,402.26 157.75,402.26C157.75,402.36 157.75,402.56 157.87,402.66C158.1,402.96 158.46,403.16 159.06,403.16L287.28,403.16C287.4,403.16 287.52,403.16 287.64,403.06C288,402.86 288,402.56 288,402.56L288,209.7C288,209.7 288,209.3 287.76,209.1C287.64,209 287.52,209 287.4,209L159.18,209C159.18,209 158.35,209 157.99,209.4ZM279.85,214.52C279.97,214.52 281.41,214.52 282.49,215.42C283.57,216.32 283.57,217.63 283.57,217.73L283.57,394.54C283.57,394.64 283.57,395.94 282.49,396.84C281.41,397.74 279.97,397.74 279.85,397.74L160.74,397.74C160.62,397.74 159.18,397.74 158.1,396.84C157.03,395.94 157.03,394.64 157.03,394.54L157.03,217.73C157.03,217.63 156.91,216.42 158.1,215.42C159.18,214.52 160.62,214.52 160.74,214.52L279.85,214.52Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M151.36,353.72L152.44,353.72L152.44,377.49L151.36,377.49C151.36,377.49 151,377.39 151,377.09L151,369.87C151,369.87 151,369.47 151.36,369.47L151.36,361.44C151.36,361.44 151,361.44 151,361.14L151,353.92C151.12,353.82 151.12,353.72 151.36,353.72Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M160.78,214.51L279.89,214.51C280.01,214.51 281.45,214.51 282.52,215.41C283.6,216.31 283.6,217.62 283.6,217.72L283.6,394.53C283.6,394.63 283.6,395.93 282.52,396.83C281.45,397.74 280.01,397.74 279.89,397.74L160.78,397.74C160.66,397.74 159.22,397.74 158.14,396.83C157.06,395.93 157.06,394.63 157.06,394.53L157.06,217.72C157.06,217.62 156.95,216.41 158.14,215.41C159.22,214.51 160.66,214.51 160.78,214.51Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<group>
<clip-path
android:pathData="M368,311h64v192h-64z"/>
<path
android:pathData="M400.06,311H368V503H400.06C417.79,503 432.11,488.68 432.11,470.96V343.04C432,325.32 417.68,311 400.06,311Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:strokeWidth="1"
android:pathData="M374.14,327.81H378.23C378.35,327.81 378.35,327.7 378.35,327.7V323.84C378.35,323.72 378.46,323.72 378.46,323.72H379.6C379.71,323.72 379.71,323.84 379.71,323.84V327.7C379.71,327.81 379.82,327.81 379.82,327.81H383.8C383.92,327.81 383.92,327.93 383.92,327.93V329.06C383.92,329.18 383.8,329.18 383.8,329.18H379.82C379.71,329.18 379.71,329.29 379.71,329.29V333.15C379.71,333.27 379.6,333.27 379.6,333.27H378.46C378.35,333.27 378.35,333.15 378.35,333.15V329.29C378.35,329.18 378.23,329.18 378.23,329.18H374.14C374.02,329.18 374.02,329.06 374.02,329.06V327.93C374.02,327.93 374.02,327.81 374.14,327.81Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:strokeColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M399.49,423.81C405.83,423.81 410.97,418.68 410.97,412.34C410.97,406 405.83,400.86 399.49,400.86C393.15,400.86 388.01,406 388.01,412.34C388.01,418.68 393.15,423.81 399.49,423.81Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M398.58,397.68V399.5C398.58,399.5 398.58,399.61 398.46,399.61C392.21,400.07 387.21,405.07 386.64,411.43C386.64,411.43 386.64,411.54 386.53,411.54H384.71C384.71,411.54 384.6,411.54 384.6,411.43C384.6,411.09 384.6,410.86 384.71,410.52C385.73,403.25 391.64,398.02 398.58,397.68C398.58,397.57 398.58,397.57 398.58,397.68Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M414.27,413.25C414.38,413.59 414.27,413.93 414.27,414.27C413.36,421.43 407.45,426.65 400.63,427.11C400.63,427.11 400.51,427.11 400.51,426.99V425.18C400.51,425.18 400.51,425.06 400.63,425.06C406.88,424.61 411.88,419.61 412.45,413.25C412.45,413.25 412.45,413.14 412.56,413.14H414.27V413.25Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M414.27,411.43H412.33C412.33,411.43 412.22,411.43 412.22,411.32C411.77,405.07 406.76,400.07 400.4,399.5C400.4,399.5 400.28,399.5 400.28,399.39V397.57C400.28,397.57 400.28,397.46 400.4,397.46C400.74,397.46 400.97,397.46 401.31,397.57C408.58,398.59 413.81,404.39 414.27,411.43Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M398.58,425.18V426.99C398.58,426.99 398.58,427.11 398.46,427.11C398.12,427.11 397.9,427.11 397.56,426.99C390.39,426.09 385.17,420.18 384.71,413.36C384.71,413.36 384.71,413.25 384.82,413.25H386.64C386.64,413.25 386.76,413.25 386.76,413.36C387.21,419.61 392.21,424.61 398.58,425.18Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M392.67,358.15C392.67,362.12 389.48,365.3 385.51,365.3C381.53,365.42 378.23,362.12 378.23,358.15C378.23,354.17 381.41,350.99 385.51,350.99C389.48,350.99 392.67,354.17 392.67,358.15Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M405.29,345.65C405.29,349.63 402.1,352.81 398.01,352.81C394.03,352.81 390.85,349.63 390.85,345.65C390.85,341.67 394.03,338.49 398.01,338.49C401.99,338.38 405.29,341.67 405.29,345.65Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M417.79,358.15C417.79,362.12 414.61,365.3 410.63,365.3C406.65,365.3 403.47,362.12 403.47,358.15C403.47,354.17 406.65,350.99 410.63,350.99C414.49,350.99 417.79,354.17 417.79,358.15Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M405.29,370.76C405.29,374.73 402.1,377.92 398.01,377.92C394.03,377.92 390.85,374.73 390.85,370.76C390.85,366.78 394.03,363.6 398.01,363.6C401.99,363.49 405.29,366.78 405.29,370.76Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M394.15,448.81C394.15,452.33 391.3,455.17 387.78,455.17C384.26,455.17 381.41,452.33 381.41,448.81C381.41,445.29 384.26,442.45 387.78,442.45C391.3,442.56 394.15,445.4 394.15,448.81Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
</group>
<path
android:pathData="M91.95,468.95C97.99,468.95 102.9,464.05 102.9,458C102.9,451.95 97.99,447.05 91.95,447.05C85.9,447.05 81,451.95 81,458C81,464.05 85.9,468.95 91.95,468.95Z"
android:strokeAlpha="0.7"
android:fillColor="#1A1A1A"
android:fillAlpha="0.7"/>
<path
android:pathData="M88.14,457.83L93.88,454.5C94,454.42 94.17,454.53 94.17,454.67V461.3C94.17,461.44 94.02,461.53 93.88,461.47L88.14,458.14C88.02,458.08 88.02,457.92 88.14,457.83Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M111,449.9C117.05,449.9 121.95,444.99 121.95,438.95C121.95,432.9 117.05,428 111,428C104.95,428 100.05,432.9 100.05,438.95C100.05,444.99 104.95,449.9 111,449.9Z"
android:strokeAlpha="0.7"
android:fillColor="#1A1A1A"
android:fillAlpha="0.7"/>
<path
android:pathData="M111.17,435.14L114.5,440.88C114.58,440.99 114.47,441.17 114.33,441.17H107.7C107.56,441.17 107.47,441.02 107.53,440.88L110.86,435.14C110.92,435.02 111.08,435.02 111.17,435.14Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M130.05,468.95C136.1,468.95 141,464.05 141,458C141,451.95 136.1,447.05 130.05,447.05C124.01,447.05 119.1,451.95 119.1,458C119.1,464.05 124.01,468.95 130.05,468.95Z"
android:strokeAlpha="0.7"
android:fillColor="#1A1A1A"
android:fillAlpha="0.7"/>
<path
android:pathData="M133.86,458.17L128.12,461.5C128.01,461.58 127.83,461.47 127.83,461.33V454.7C127.83,454.56 127.98,454.47 128.12,454.53L133.86,457.86C134.01,457.92 134.01,458.08 133.86,458.17Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M111,488C117.05,488 121.95,483.1 121.95,477.05C121.95,471.01 117.05,466.1 111,466.1C104.95,466.1 100.05,471.01 100.05,477.05C100.05,483.1 104.95,488 111,488Z"
android:strokeAlpha="0.7"
android:fillColor="#1A1A1A"
android:fillAlpha="0.7"/>
<path
android:pathData="M110.83,480.86L107.5,475.12C107.42,475.01 107.53,474.83 107.67,474.83H114.3C114.44,474.83 114.53,474.98 114.47,475.12L111.14,480.86C111.08,481.01 110.92,481.01 110.83,480.86Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M380.95,165.95C386.99,165.95 391.9,161.05 391.9,155C391.9,148.95 386.99,144.05 380.95,144.05C374.9,144.05 370,148.95 370,155C370,161.05 374.9,165.95 380.95,165.95Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M380.46,155.54L377.68,151.3H378.96L380.98,154.54L383.05,151.3H384.27L381.49,155.54V158.7H380.49V155.54H380.46Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M399.72,185C405.76,185 410.66,180.1 410.66,174.05C410.66,168.01 405.76,163.1 399.72,163.1C393.67,163.1 388.77,168.01 388.77,174.05C388.77,180.1 393.67,185 399.72,185Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M397.44,170.64H400C400.31,170.64 400.63,170.67 400.88,170.75C401.17,170.84 401.39,170.95 401.59,171.1C401.79,171.24 401.93,171.44 402.08,171.66C402.19,171.89 402.25,172.18 402.25,172.49C402.25,172.91 402.13,173.26 401.9,173.54C401.68,173.8 401.36,173.99 400.99,174.14V174.17C401.22,174.17 401.42,174.25 401.62,174.34C401.82,174.42 401.99,174.56 402.13,174.74C402.27,174.9 402.39,175.08 402.47,175.3C402.56,175.53 402.59,175.76 402.59,176.01C402.59,176.35 402.53,176.64 402.39,176.9C402.25,177.15 402.08,177.35 401.82,177.55C401.59,177.72 401.31,177.86 400.99,177.95C400.68,178.03 400.34,178.09 399.97,178.09H397.44V170.64ZM398.44,173.71H399.8C400,173.71 400.17,173.68 400.34,173.65C400.51,173.63 400.65,173.54 400.77,173.46C400.88,173.37 400.99,173.26 401.05,173.11C401.14,172.97 401.17,172.8 401.17,172.6C401.17,172.32 401.08,172.06 400.88,171.83C400.68,171.61 400.4,171.52 400,171.52H398.44V173.71ZM398.44,177.15H399.92C400.06,177.15 400.23,177.12 400.43,177.1C400.6,177.07 400.8,177.01 400.94,176.9C401.11,176.81 401.22,176.67 401.34,176.53C401.45,176.35 401.51,176.16 401.51,175.9C401.51,175.47 401.36,175.13 401.08,174.9C400.8,174.68 400.4,174.56 399.92,174.56H398.44V177.15Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M419.05,165.95C425.1,165.95 430,161.05 430,155C430,148.95 425.1,144.05 419.05,144.05C413.01,144.05 408.1,148.95 408.1,155C408.1,161.05 413.01,165.95 419.05,165.95Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M418.63,151.3H419.54L422.69,158.67H421.53L420.79,156.85H417.29L416.55,158.67H415.38L418.63,151.3ZM420.42,155.99L419.05,152.61H419.02L417.63,155.99H420.42Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
<path
android:pathData="M400,146.9C406.05,146.9 410.95,141.99 410.95,135.95C410.95,129.9 406.05,125 400,125C393.95,125 389.05,129.9 389.05,135.95C389.05,141.99 393.95,146.9 400,146.9Z"
android:strokeAlpha="0.7"
android:fillColor="#1C1C1C"
android:fillAlpha="0.7"/>
<path
android:pathData="M399.26,135.78L396.79,132.28H398.07L400,135.12L401.9,132.28H403.16L400.68,135.78L403.41,139.67H402.1L399.97,136.46L397.84,139.67H396.59L399.26,135.78Z"
android:strokeAlpha="0.7"
android:fillColor="#282828"
android:fillAlpha="0.7"/>
</group>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

View file

@ -27,6 +27,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="@string/generate"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="@+id/edit_text_layout"
app:layout_constraintTop_toBottomOf="@+id/edit_text_layout" />

View file

@ -148,18 +148,18 @@
<string name="multiplayer_join_room_failed">Failed to join room</string>
<string name="multiplayer_name_invalid">Name is too short</string>
<string name="multiplayer_address_invalid">Invalid address</string>
<string name="multiplayer_port_invalid">Invalid port!</string>
<string name="multiplayer_port_invalid">Invalid port</string>
<string name="multiplayer_exit_room">Exit Room</string>
<string name="multiplayer_network_error">Network error</string>
<string name="multiplayer_lost_connection">Lost connection</string>
<string name="multiplayer_name_collision">Name collision</string>
<string name="multiplayer_name_collision">Username already taken</string>
<string name="multiplayer_mac_collision">MAC Address collision</string>
<string name="multiplayer_console_id_collision">Console ID collision</string>
<string name="multiplayer_wrong_version">Wrong version</string>
<string name="multiplayer_wrong_password">Wrong password</string>
<string name="multiplayer_could_not_connect">Could not connect</string>
<string name="multiplayer_room_is_full">Room is full</string>
<string name="multiplayer_host_banned">Host banned</string>
<string name="multiplayer_host_banned">You are banned from this room</string>
<string name="multiplayer_permission_denied">Permission denied</string>
<string name="multiplayer_no_such_user">No such user</string>
<string name="multiplayer_already_in_room">Already in room</string>
@ -221,7 +221,8 @@
<string name="multiplayer_required">Required</string>
<string name="multiplayer_token_required">Web Token required, go to Advanced Settings -> System -> Network</string>
<string name="multiplayer_ip_error">Invalid IP format</string>
<string name="multiplayer_username_error">Must be between 420 characters</string>
<string name="multiplayer_username_error">Must be between 420 characters, and contain alphanumeric characters, periods, dashes, underscores, and spaces only</string>
<string name="multiplayer_nickname_invalid">Username invalid, ensure it is set properly in System -> Network</string>
<string name="multiplayer_token_error">Must be 48 characters, and lowercase a-z only</string>
<string name="multiplayer_port_error">Must be between 1 and 65535</string>
<string name="cancel">Cancel</string>
@ -467,7 +468,7 @@
<string name="web_token">Web Token</string>
<string name="web_token_description">Web token used for creating public lobbies. It is a 48-character string containing only lowercase a-z.</string>
<string name="web_username">Web Username</string>
<string name="web_username_description">Username to be shown in multiplayer lobbies. It must be 420 characters.</string>
<string name="web_username_description">Username to be shown in multiplayer lobbies. It must be 420 characters, containing only alphanumeric characters, dashes, periods, underscores, and spaces.</string>
<string name="network">Network</string>
<!-- Graphics settings strings -->

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

View file

@ -23,31 +23,48 @@ namespace FFmpeg {
namespace {
constexpr AVPixelFormat PreferredGpuFormat = AV_PIX_FMT_NV12;
constexpr AVPixelFormat PreferredCpuFormat = AV_PIX_FMT_YUV420P;
constexpr std::array PreferredGpuDecoders = {
#if defined (_WIN32)
AV_HWDEVICE_TYPE_CUDA,
#ifdef _WIN32
AV_HWDEVICE_TYPE_D3D11VA,
AV_HWDEVICE_TYPE_DXVA2,
#elif defined(__unix__)
AV_HWDEVICE_TYPE_VAAPI,
#elif defined(__FreeBSD__)
AV_HWDEVICE_TYPE_VDPAU,
#elif defined(__unix__)
AV_HWDEVICE_TYPE_CUDA,
AV_HWDEVICE_TYPE_VAAPI,
AV_HWDEVICE_TYPE_VDPAU,
#endif
AV_HWDEVICE_TYPE_VULKAN,
};
AVPixelFormat GetGpuFormat(AVCodecContext* codec_context, const AVPixelFormat* pix_fmts) {
for (const AVPixelFormat* p = pix_fmts; *p != AV_PIX_FMT_NONE; ++p) {
if (*p == codec_context->pix_fmt) {
return codec_context->pix_fmt;
}
}
// Check if there is a pixel format supported by the GPU decoder.
const auto desc = av_pix_fmt_desc_get(codec_context->pix_fmt);
if (desc && desc->flags & AV_PIX_FMT_FLAG_HWACCEL) {
for (const AVPixelFormat* p = pix_fmts; *p != AV_PIX_FMT_NONE; ++p) {
if (*p == codec_context->pix_fmt) {
return codec_context->pix_fmt;
}
}
}
LOG_INFO(HW_GPU, "Could not find compatible GPU AV format, falling back to CPU");
// Another check to confirm if there is a pixel format supported by specific GPU decoders.
for (int i = 0;; i++) {
const AVCodecHWConfig* config = avcodec_get_hw_config(codec_context->codec, i);
if (!config) {
break;
}
if ((config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX) && (config->device_type == AV_HWDEVICE_TYPE_CUDA || config->device_type == AV_HWDEVICE_TYPE_VAAPI)) {
return config->pix_fmt;
}
}
// Fallback to CPU decoder.
LOG_INFO(HW_GPU, "Could not find compatible GPU pixel format, falling back to CPU");
av_buffer_unref(&codec_context->hw_device_ctx);
codec_context->pix_fmt = PreferredCpuFormat;
return codec_context->pix_fmt;
}
@ -57,7 +74,7 @@ std::string AVError(int errnum) {
return errbuf;
}
} // namespace
}
Packet::Packet(std::span<const u8> data) {
m_packet = av_packet_alloc();
@ -80,16 +97,16 @@ Frame::~Frame() {
Decoder::Decoder(Tegra::Host1x::NvdecCommon::VideoCodec codec) {
const AVCodecID av_codec = [&] {
switch (codec) {
case Tegra::Host1x::NvdecCommon::VideoCodec::H264:
return AV_CODEC_ID_H264;
case Tegra::Host1x::NvdecCommon::VideoCodec::VP8:
return AV_CODEC_ID_VP8;
case Tegra::Host1x::NvdecCommon::VideoCodec::VP9:
return AV_CODEC_ID_VP9;
default:
UNIMPLEMENTED_MSG("Unknown codec {}", codec);
return AV_CODEC_ID_NONE;
}
case Tegra::Host1x::NvdecCommon::VideoCodec::H264:
return AV_CODEC_ID_H264;
case Tegra::Host1x::NvdecCommon::VideoCodec::VP8:
return AV_CODEC_ID_VP8;
case Tegra::Host1x::NvdecCommon::VideoCodec::VP9:
return AV_CODEC_ID_VP9;
default:
UNIMPLEMENTED_MSG("Unknown codec {}", codec);
return AV_CODEC_ID_NONE;
}
}();
m_codec = avcodec_find_decoder(av_codec);
@ -102,6 +119,7 @@ bool Decoder::SupportsDecodingOnDevice(AVPixelFormat* out_pix_fmt, AVHWDeviceTyp
LOG_DEBUG(HW_GPU, "{} decoder does not support device type {}", m_codec->name, av_hwdevice_get_type_name(type));
break;
}
if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX && config->device_type == type) {
LOG_INFO(HW_GPU, "Using {} GPU decoder", av_hwdevice_get_type_name(type));
*out_pix_fmt = config->pix_fmt;
@ -214,19 +232,17 @@ bool DecoderContext::OpenContext(const Decoder& decoder) {
}
bool DecoderContext::SendPacket(const Packet& packet) {
m_temp_frame = std::make_shared<Frame>();
if (const int ret = avcodec_send_packet(m_codec_context, packet.GetPacket()); ret < 0) {
if (const int ret = avcodec_send_packet(m_codec_context, packet.GetPacket()); ret < 0 && ret != AVERROR_EOF) {
LOG_ERROR(HW_GPU, "avcodec_send_packet error: {}", AVError(ret));
return false;
}
return true;
}
std::shared_ptr<Frame> DecoderContext::ReceiveFrame() {
auto ReceiveImpl = [&](AVFrame* frame) -> bool {
if (const int ret = avcodec_receive_frame(m_codec_context, frame); ret < 0) {
if (const int ret = avcodec_receive_frame(m_codec_context, frame); ret < 0 && ret != AVERROR_EOF) {
LOG_ERROR(HW_GPU, "avcodec_receive_frame error: {}", AVError(ret));
return false;
}
@ -238,14 +254,15 @@ std::shared_ptr<Frame> DecoderContext::ReceiveFrame() {
return {};
}
const auto desc = av_pix_fmt_desc_get(intermediate_frame->GetPixelFormat());
if (m_codec_context->hw_device_ctx && (desc && desc->flags & AV_PIX_FMT_FLAG_HWACCEL)) {
m_temp_frame->SetFormat(PreferredGpuFormat);
m_temp_frame = std::make_shared<Frame>();
if (m_codec_context->hw_device_ctx) {
m_temp_frame->SetFormat(AV_PIX_FMT_NV12);
if (int ret = av_hwframe_transfer_data(m_temp_frame->GetFrame(), intermediate_frame->GetFrame(), 0); ret < 0) {
LOG_ERROR(HW_GPU, "av_hwframe_transfer_data error: {}", AVError(ret));
return {};
}
} else {
m_temp_frame->SetFormat(AV_PIX_FMT_YUV420P);
m_temp_frame = std::move(intermediate_frame);
}
@ -288,4 +305,4 @@ std::shared_ptr<Frame> DecodeApi::ReceiveFrame() {
return m_decoder_context->ReceiveFrame();
}
} // namespace FFmpeg
}

View file

@ -26,7 +26,6 @@ extern "C" {
#include <libavutil/opt.h>
#include <libavutil/pixdesc.h>
// Works quite fine, and omits the hacky ffmpeg building for now...
#if defined(__FreeBSD__)
#include <libavcodec/codec.h>
#else

View file

@ -462,8 +462,8 @@ if (WIN32 AND NOT YUZU_USE_BUNDLED_QT AND QT_VERSION VERSION_GREATER_EQUAL 6)
endif()
if (YUZU_USE_BUNDLED_QT)
include(CopyYuzuQt6Deps)
copy_yuzu_Qt6_deps(yuzu)
include(CopyYuzuQt6Deps)
copy_yuzu_Qt6_deps(yuzu)
endif()
if (ENABLE_SDL2)
@ -494,4 +494,8 @@ if (YUZU_ROOM)
target_link_libraries(yuzu PRIVATE yuzu-room)
endif()
# Extra deps
add_subdirectory(externals)
target_link_libraries(yuzu PRIVATE QuaZip::QuaZip)
create_target_directory_groups(yuzu)

View file

@ -16,9 +16,9 @@ AboutDialog::AboutDialog(QWidget* parent)
std::string yuzu_build;
if (Common::g_is_dev_build) {
yuzu_build = fmt::format("eden Nightly | {}-{}", description, build_id);
yuzu_build = fmt::format("Eden Nightly | {}-{}", description, build_id);
} else {
yuzu_build = fmt::format("eden | {}", description);
yuzu_build = fmt::format("Eden | {}", description);
}
const auto override_build = fmt::format(fmt::runtime(

17
src/yuzu/externals/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,17 @@
# Disable tests in all externals supporting the standard option name
set(BUILD_TESTING OFF)
# Build only static externals
set(BUILD_SHARED_LIBS OFF)
# QuaZip
include(CPM)
set(CPM_SOURCE_CACHE ${CMAKE_SOURCE_DIR}/.cache/cpm)
set(CPM_USE_LOCAL_PACKAGES ON)
CPMAddPackage(
NAME QuaZip-Qt6
VERSION 1.3
GIT_REPOSITORY "https://github.com/crueter/quazip-qt6.git"
GIT_TAG v1.5-qt6
)

View file

@ -12,6 +12,8 @@
#include "core/tools/renderdoc.h"
#include "frontend_common/firmware_manager.h"
#include <JlCompress.h>
#ifdef __APPLE__
#include <unistd.h> // for chdir
#endif
@ -1683,7 +1685,8 @@ void GMainWindow::ConnectMenuEvents() {
connect_menu(ui->action_Discord, &GMainWindow::OnOpenDiscord);
connect_menu(ui->action_Verify_installed_contents, &GMainWindow::OnVerifyInstalledContents);
connect_menu(ui->action_Install_Firmware, &GMainWindow::OnInstallFirmware);
connect_menu(ui->action_Firmware_From_Folder, &GMainWindow::OnInstallFirmware);
connect_menu(ui->action_Firmware_From_ZIP, &GMainWindow::OnInstallFirmwareFromZIP);
connect_menu(ui->action_Install_Keys, &GMainWindow::OnInstallDecryptionKeys);
connect_menu(ui->action_About, &GMainWindow::OnAbout);
}
@ -1714,7 +1717,8 @@ void GMainWindow::UpdateMenuState() {
action->setEnabled(emulation_running);
}
ui->action_Install_Firmware->setEnabled(!emulation_running);
ui->action_Firmware_From_Folder->setEnabled(!emulation_running);
ui->action_Firmware_From_ZIP->setEnabled(!emulation_running);
ui->action_Install_Keys->setEnabled(!emulation_running);
for (QAction* action : applet_actions) {
@ -4239,26 +4243,8 @@ void GMainWindow::OnVerifyInstalledContents() {
}
}
void GMainWindow::OnInstallFirmware() {
// Don't do this while emulation is running, that'd probably be a bad idea.
if (emu_thread != nullptr && emu_thread->IsRunning()) {
return;
}
// Check for installed keys, error out, suggest restart?
if (!ContentManager::AreKeysPresent()) {
QMessageBox::information(
this, tr("Keys not installed"),
tr("Install decryption keys and restart eden before attempting to install firmware."));
return;
}
const QString firmware_source_location = QFileDialog::getExistingDirectory(
this, tr("Select Dumped Firmware Source Location"), {}, QFileDialog::ShowDirsOnly);
if (firmware_source_location.isEmpty()) {
return;
}
void GMainWindow::InstallFirmware(const QString &location, bool recursive)
{
QProgressDialog progress(tr("Installing Firmware..."), tr("Cancel"), 0, 100, this);
progress.setWindowModality(Qt::WindowModal);
progress.setMinimumDuration(100);
@ -4272,11 +4258,11 @@ void GMainWindow::OnInstallFirmware() {
return progress.wasCanceled();
};
LOG_INFO(Frontend, "Installing firmware from {}", firmware_source_location.toStdString());
LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString());
// Check for a reasonable number of .nca files (don't hardcode them, just see if there's some in
// there.)
std::filesystem::path firmware_source_path = firmware_source_location.toStdString();
std::filesystem::path firmware_source_path = location.toStdString();
if (!Common::FS::IsDir(firmware_source_path)) {
progress.close();
return;
@ -4294,7 +4280,12 @@ void GMainWindow::OnInstallFirmware() {
QtProgressCallback(100, 10);
Common::FS::IterateDirEntries(firmware_source_path, callback, Common::FS::DirEntryFilter::File);
if (recursive) {
Common::FS::IterateDirEntriesRecursively(firmware_source_path, callback, Common::FS::DirEntryFilter::File);
} else {
Common::FS::IterateDirEntries(firmware_source_path, callback, Common::FS::DirEntryFilter::File);
}
if (out.size() <= 0) {
progress.close();
QMessageBox::warning(this, tr("Firmware install failed"),
@ -4377,6 +4368,93 @@ void GMainWindow::OnInstallFirmware() {
OnCheckFirmware();
}
void GMainWindow::OnInstallFirmware() {
// Don't do this while emulation is running, that'd probably be a bad idea.
if (emu_thread != nullptr && emu_thread->IsRunning()) {
return;
}
// Check for installed keys, error out, suggest restart?
if (!ContentManager::AreKeysPresent()) {
QMessageBox::information(
this, tr("Keys not installed"),
tr("Install decryption keys and restart Eden before attempting to install firmware."));
return;
}
const QString firmware_source_location = QFileDialog::getExistingDirectory(
this, tr("Select Dumped Firmware Source Location"), {}, QFileDialog::ShowDirsOnly);
if (firmware_source_location.isEmpty()) {
return;
}
InstallFirmware(firmware_source_location);
}
void GMainWindow::OnInstallFirmwareFromZIP()
{
// Don't do this while emulation is running, that'd probably be a bad idea.
if (emu_thread != nullptr && emu_thread->IsRunning()) {
return;
}
// Check for installed keys, error out, suggest restart?
if (!ContentManager::AreKeysPresent()) {
QMessageBox::information(
this, tr("Keys not installed"),
tr("Install decryption keys and restart Eden before attempting to install firmware."));
return;
}
const QString firmware_zip_location = QFileDialog::getOpenFileName(
this, tr("Select Dumped Firmware ZIP"), {}, tr("Zipped Archives (*.zip)"));
if (firmware_zip_location.isEmpty()) {
return;
}
namespace fs = std::filesystem;
fs::path tmp{std::filesystem::temp_directory_path()};
if (!std::filesystem::create_directories(tmp / "eden" / "firmware")) {
goto unzipFailed;
}
{
tmp /= "eden";
tmp /= "firmware";
QString qCacheDir = QString::fromStdString(tmp.string());
QFile zip(firmware_zip_location);
QStringList result = JlCompress::extractDir(&zip, qCacheDir);
if (result.isEmpty()) {
goto unzipFailed;
}
// In this case, it has to be done recursively, since sometimes people
// will pack it into a subdirectory after dumping
InstallFirmware(qCacheDir, true);
std::error_code ec;
std::filesystem::remove_all(tmp, ec);
if (ec) {
QMessageBox::warning(this, tr("Firmware cleanup failed"),
tr("Failed to clean up extracted firmware cache.\n"
"Check write permissions in the system temp directory and try again.\nOS reported error: %1")
.arg(QString::fromStdString(ec.message())));
}
return;
}
unzipFailed:
QMessageBox::critical(this, tr("Firmware unzip failed"),
tr("Check write permissions in the system temp directory and try again."));
return;
}
void GMainWindow::OnInstallDecryptionKeys() {
// Don't do this while emulation is running.
if (emu_thread != nullptr && emu_thread->IsRunning()) {
@ -4824,9 +4902,9 @@ void GMainWindow::UpdateWindowTitle(std::string_view title_name, std::string_vie
std::string yuzu_title;
if (Common::g_is_dev_build) {
yuzu_title = fmt::format("eden Nightly | {}-{}", description, build_id);
yuzu_title = fmt::format("Eden Nightly | {}-{}", description, build_id);
} else {
yuzu_title = fmt::format("eden | {}", description);
yuzu_title = fmt::format("Eden | {}", description);
}
const auto override_title =

View file

@ -394,6 +394,7 @@ private slots:
void OnOpenLogFolder();
void OnVerifyInstalledContents();
void OnInstallFirmware();
void OnInstallFirmwareFromZIP();
void OnInstallDecryptionKeys();
void OnAbout();
void OnToggleFilterBar();
@ -614,6 +615,8 @@ private:
std::string arguments,
const bool needs_title);
void InstallFirmware(const QString& location, bool recursive = false);
protected:
void dropEvent(QDropEvent* event) override;
void dragEnterEvent(QDragEnterEvent* event) override;

View file

@ -182,8 +182,15 @@
<addaction name="action_Desktop"/>
<addaction name="action_Application_Menu"/>
</widget>
<widget class="QMenu" name="menuInstall_Firmware">
<property name="title">
<string>Install Firmware</string>
</property>
<addaction name="action_Firmware_From_Folder"/>
<addaction name="action_Firmware_From_ZIP"/>
</widget>
<addaction name="action_Install_Keys"/>
<addaction name="action_Install_Firmware"/>
<addaction name="menuInstall_Firmware"/>
<addaction name="action_Verify_installed_contents"/>
<addaction name="separator"/>
<addaction name="menu_cabinet_applet"/>
@ -484,11 +491,6 @@
<string>Open &amp;Controller Menu</string>
</property>
</action>
<action name="action_Install_Firmware">
<property name="text">
<string>Install Firmware</string>
</property>
</action>
<action name="action_Install_Keys">
<property name="text">
<string>Install Decryption Keys</string>
@ -545,6 +547,16 @@
<action name="action_Log_Folder">
<property name="text">
<string>&amp;Log Folder</string>
</property>
</action>
<action name="action_Firmware_From_Folder">
<property name="text">
<string>From Folder</string>
</property>
</action>
<action name="action_Firmware_From_ZIP">
<property name="text">
<string>From ZIP</string>
</property>
</action>
</widget>

3
tools/update-cpm.sh Executable file
View file

@ -0,0 +1,3 @@
#!/bin/sh
wget -O CMakeModules/CPM.cmake https://github.com/cpm-cmake/CPM.cmake/releases/latest/download/get_cpm.cmake