QResource: re-factor the memory-mapping code into two helper functions

So I can more easily extend to Windows support and to reuse them later.

Change-Id: I6979d02a7395405cbf23fffd17c90b32dbbddd94
Reviewed-by: Ahmad Samir <a.samirh78@gmail.com>
bb10
Thiago Macieira 2024-04-23 16:04:06 -07:00
parent fe6dda9bb9
commit 315d6b6c2e
1 changed files with 48 additions and 42 deletions

View File

@ -1109,6 +1109,11 @@ public:
class QDynamicFileResourceRoot : public QDynamicBufferResourceRoot
{
public:
static uchar *map_sys(QFile &file, qint64 base, qsizetype size);
static void unmap_sys(void *base, qsizetype size);
private:
QString fileName;
// for mmap'ed files, this is what needs to be unmapped.
uchar *unmapPointer;
@ -1119,16 +1124,10 @@ public:
: QDynamicBufferResourceRoot(_root), unmapPointer(nullptr), unmapLength(0)
{ }
~QDynamicFileResourceRoot() {
#if defined(QT_USE_MMAP)
if (unmapPointer) {
munmap(reinterpret_cast<char *>(unmapPointer), unmapLength);
unmapPointer = nullptr;
unmapLength = 0;
} else
#endif
{
if (unmapPointer)
unmap_sys(unmapPointer, unmapLength);
else
delete[] mappingBuffer();
}
}
QString mappingFile() const { return fileName; }
ResourceRootType type() const override { return Resource_File; }
@ -1144,49 +1143,56 @@ public:
# define MAP_FAILED reinterpret_cast<void *>(-1)
#endif
void QDynamicFileResourceRoot::unmap_sys(void *base, qsizetype size)
{
#if defined(QT_USE_MMAP)
munmap(base, size);
#endif
}
// Note: caller must ensure \a offset and \a size are acceptable to the OS.
uchar *QDynamicFileResourceRoot::map_sys(QFile &file, qint64 offset, qsizetype size)
{
Q_ASSERT(file.isOpen());
void *ptr = nullptr;
if (size < 0)
size = qMin(file.size() - offset, (std::numeric_limits<qsizetype>::max)());
// We don't use QFile::map() here because we want to dispose of the QFile object
#if defined(QT_USE_MMAP)
int fd = file.handle();
int protection = PROT_READ; // read-only memory
int flags = MAP_FILE | MAP_PRIVATE; // swap-backed map from file
ptr = QT_MMAP(nullptr, size, protection, flags, fd, offset);
if (ptr == MAP_FAILED)
ptr = nullptr;
#endif // QT_USE_MMAP
return static_cast<uchar *>(ptr);
}
bool QDynamicFileResourceRoot::registerSelf(const QString &f)
{
bool fromMM = false;
uchar *data = nullptr;
qsizetype data_len = 0;
QFile file(f);
if (!file.open(QIODevice::ReadOnly))
return false;
#if defined(QT_USE_MMAP)
int fd = QT_OPEN(QFile::encodeName(f), O_RDONLY);
if (fd >= 0) {
QT_STATBUF st;
if (!QT_FSTAT(fd, &st) && st.st_size <= std::numeric_limits<qsizetype>::max()) {
int protection = PROT_READ; // read-only memory
int flags = MAP_FILE | MAP_PRIVATE; // swap-backed map from file
void *ptr = QT_MMAP(nullptr, st.st_size, // any address, whole file
protection, flags,
fd, 0); // from offset 0 of fd
if (ptr != MAP_FAILED) {
data = static_cast<uchar *>(ptr);
data_len = st.st_size;
fromMM = true;
}
}
QT_CLOSE(fd);
}
#endif // QT_USE_MMAP
if (!data) {
QFile file(f);
qint64 data_len = file.size();
if (data_len > std::numeric_limits<qsizetype>::max())
return false;
uchar *data = map_sys(file, 0, data_len);
bool fromMM = !!data;
if (!fromMM) {
bool ok = false;
if (file.open(QIODevice::ReadOnly)) {
qint64 fsize = file.size();
if (fsize <= std::numeric_limits<qsizetype>::max()) {
data_len = file.size();
data = new uchar[data_len];
ok = (data_len == file.read(reinterpret_cast<char *>(data), data_len));
}
}
data = new uchar[data_len];
ok = (data_len == file.read(reinterpret_cast<char *>(data), data_len));
if (!ok) {
delete[] data;
data = nullptr;
data_len = 0;
return false;
}
fromMM = false;
}
if (data && QDynamicBufferResourceRoot::registerSelf(data, data_len)) {
if (fromMM) {