QTfrontend/util/FileEngine.cpp
branchhedgeroid
changeset 15515 7030706266df
parent 14323 d688455cad8f
equal deleted inserted replaced
7861:bc7b6aa5d67a 15515:7030706266df
       
     1 /* borrowed from https://github.com/skhaz/qt-physfs-wrapper
       
     2  * TODO: add copyright header, determine license
       
     3  */
       
     4 
       
     5 #include "FileEngine.h"
       
     6 #include "hwpacksmounter.h"
       
     7 
       
     8 
       
     9 const QString FileEngineHandler::scheme = "physfs:/";
       
    10 
       
    11 FileEngine::FileEngine(const QString& filename)
       
    12     : m_handle(NULL)
       
    13     , m_size(0)
       
    14     , m_flags(0)
       
    15     , m_bufferSet(false)
       
    16     , m_readWrite(false)
       
    17 {
       
    18     setFileName(filename);
       
    19 }
       
    20 
       
    21 FileEngine::~FileEngine()
       
    22 {
       
    23     close();
       
    24 }
       
    25 
       
    26 bool FileEngine::open(QIODevice::OpenMode openMode)
       
    27 {
       
    28     close();
       
    29 
       
    30     if ((openMode & QIODevice::ReadWrite) == QIODevice::ReadWrite) {
       
    31         m_handle = PHYSFS_openAppend(m_fileName.toUtf8().constData());
       
    32         if(m_handle)
       
    33         {
       
    34             m_readWrite = true;
       
    35             seek(0);
       
    36         }
       
    37     }
       
    38 
       
    39     else if (openMode & QIODevice::WriteOnly) {
       
    40         m_handle = PHYSFS_openWrite(m_fileName.toUtf8().constData());
       
    41         m_flags = QAbstractFileEngine::WriteOwnerPerm | QAbstractFileEngine::WriteUserPerm | QAbstractFileEngine::FileType;
       
    42     }
       
    43 
       
    44     else if (openMode & QIODevice::ReadOnly) {
       
    45         m_handle = PHYSFS_openRead(m_fileName.toUtf8().constData());
       
    46     }
       
    47 
       
    48     else if (openMode & QIODevice::Append) {
       
    49         m_handle = PHYSFS_openAppend(m_fileName.toUtf8().constData());
       
    50     }
       
    51 
       
    52     else {
       
    53         qWarning("[PHYSFS] Bad file open mode: %d", (int)openMode);
       
    54     }
       
    55 
       
    56     if (!m_handle) {
       
    57         qWarning("%s", QString("[PHYSFS] Failed to open %1, reason: %2").arg(m_fileName).arg(FileEngineHandler::errorStr()).toLocal8Bit().constData());
       
    58         return false;
       
    59     }
       
    60 
       
    61     return true;
       
    62 }
       
    63 
       
    64 bool FileEngine::close()
       
    65 {
       
    66     if (isOpened()) {
       
    67         int result = PHYSFS_close(m_handle);
       
    68         m_handle = NULL;
       
    69         return result != 0;
       
    70     }
       
    71 
       
    72     return true;
       
    73 }
       
    74 
       
    75 bool FileEngine::flush()
       
    76 {
       
    77     return PHYSFS_flush(m_handle) != 0;
       
    78 }
       
    79 
       
    80 qint64 FileEngine::size() const
       
    81 {
       
    82     return m_size;
       
    83 }
       
    84 
       
    85 qint64 FileEngine::pos() const
       
    86 {
       
    87     return PHYSFS_tell(m_handle);
       
    88 }
       
    89 
       
    90 bool FileEngine::setSize(qint64 size)
       
    91 {
       
    92     if(size == 0)
       
    93     {
       
    94         m_size = 0;
       
    95         return open(QIODevice::WriteOnly);
       
    96     }
       
    97     else
       
    98         return false;
       
    99 }
       
   100 
       
   101 bool FileEngine::seek(qint64 pos)
       
   102 {
       
   103     bool ok = PHYSFS_seek(m_handle, pos) != 0;
       
   104 
       
   105     return ok;
       
   106 }
       
   107 
       
   108 bool FileEngine::isSequential() const
       
   109 {
       
   110     return false;
       
   111 }
       
   112 
       
   113 bool FileEngine::remove()
       
   114 {
       
   115     return PHYSFS_delete(m_fileName.toUtf8().constData()) != 0;
       
   116 }
       
   117 
       
   118 bool FileEngine::mkdir(const QString &dirName, bool createParentDirectories) const
       
   119 {
       
   120     Q_UNUSED(createParentDirectories);
       
   121 
       
   122     return PHYSFS_mkdir(dirName.toUtf8().constData()) != 0;
       
   123 }
       
   124 
       
   125 bool FileEngine::rmdir(const QString &dirName, bool recurseParentDirectories) const
       
   126 {
       
   127     Q_UNUSED(recurseParentDirectories);
       
   128 
       
   129     return PHYSFS_delete(dirName.toUtf8().constData()) != 0;
       
   130 }
       
   131 
       
   132 bool FileEngine::caseSensitive() const
       
   133 {
       
   134     return true;
       
   135 }
       
   136 
       
   137 bool FileEngine::isRelativePath() const
       
   138 {
       
   139     return false;
       
   140 }
       
   141 
       
   142 QAbstractFileEngineIterator * FileEngine::beginEntryList(QDir::Filters filters, const QStringList &filterNames)
       
   143 {
       
   144     return new FileEngineIterator(filters, filterNames, entryList(filters, filterNames));
       
   145 }
       
   146 
       
   147 QStringList FileEngine::entryList(QDir::Filters filters, const QStringList &filterNames) const
       
   148 {
       
   149     Q_UNUSED(filters);
       
   150 
       
   151     QString file;
       
   152     QStringList result;
       
   153     char **files = PHYSFS_enumerateFiles(m_fileName.toUtf8().constData());
       
   154 
       
   155     for (char **i = files; *i != NULL; i++) {
       
   156         file = QString::fromUtf8(*i);
       
   157 
       
   158         if (filterNames.isEmpty() || QDir::match(filterNames, file)) {
       
   159             result << file;
       
   160         }
       
   161     }
       
   162 
       
   163     PHYSFS_freeList(files);
       
   164 
       
   165     return result;
       
   166 }
       
   167 
       
   168 QAbstractFileEngine::FileFlags FileEngine::fileFlags(FileFlags type) const
       
   169 {
       
   170     return type & m_flags;
       
   171 }
       
   172 
       
   173 QString FileEngine::fileName(FileName file) const
       
   174 {
       
   175     switch(file)
       
   176     {
       
   177         case QAbstractFileEngine::AbsolutePathName:
       
   178         {
       
   179             QString s(PHYSFS_getWriteDir());
       
   180             return s;
       
   181         }
       
   182         case QAbstractFileEngine::BaseName:
       
   183         {
       
   184             int l = m_fileName.lastIndexOf('/');
       
   185             QString s = m_fileName.mid(l + 1);
       
   186             return s;
       
   187         }
       
   188         case QAbstractFileEngine::DefaultName:
       
   189         case QAbstractFileEngine::AbsoluteName:
       
   190         default:
       
   191         {
       
   192             QString s = "physfs:/" + m_fileName;
       
   193             return s;
       
   194         }
       
   195     }
       
   196 }
       
   197 
       
   198 QDateTime FileEngine::fileTime(FileTime time) const
       
   199 {
       
   200     switch (time)
       
   201     {
       
   202         case QAbstractFileEngine::ModificationTime:
       
   203         default:
       
   204             return m_date;
       
   205             break;
       
   206     };
       
   207 }
       
   208 
       
   209 void FileEngine::setFileName(const QString &file)
       
   210 {
       
   211     if(file.startsWith(FileEngineHandler::scheme))
       
   212         m_fileName = file.mid(FileEngineHandler::scheme.size());
       
   213     else
       
   214         m_fileName = file;
       
   215     PHYSFS_Stat stat;
       
   216     if (PHYSFS_stat(m_fileName.toUtf8().constData(), &stat) != 0) {
       
   217         m_size = stat.filesize;
       
   218         m_date = QDateTime::fromTime_t(stat.modtime);
       
   219 //        m_flags |= QAbstractFileEngine::WriteOwnerPerm;
       
   220         m_flags |= QAbstractFileEngine::ReadOwnerPerm;
       
   221         m_flags |= QAbstractFileEngine::ReadUserPerm;
       
   222         m_flags |= QAbstractFileEngine::ExistsFlag;
       
   223         m_flags |= QAbstractFileEngine::LocalDiskFlag;
       
   224 
       
   225         switch (stat.filetype)
       
   226         {
       
   227             case PHYSFS_FILETYPE_REGULAR:
       
   228                 m_flags |= QAbstractFileEngine::FileType;
       
   229                 break;
       
   230             case PHYSFS_FILETYPE_DIRECTORY:
       
   231                 m_flags |= QAbstractFileEngine::DirectoryType;
       
   232                 break;
       
   233             case PHYSFS_FILETYPE_SYMLINK:
       
   234                 m_flags |= QAbstractFileEngine::LinkType;
       
   235                 break;
       
   236             default: ;
       
   237         }
       
   238     }
       
   239 }
       
   240 
       
   241 bool FileEngine::atEnd() const
       
   242 {
       
   243     return PHYSFS_eof(m_handle) != 0;
       
   244 }
       
   245 
       
   246 qint64 FileEngine::read(char *data, qint64 maxlen)
       
   247 {
       
   248     if(m_readWrite)
       
   249     {
       
   250         if(pos() == 0)
       
   251             open(QIODevice::ReadOnly);
       
   252         else
       
   253             return -1;
       
   254     }
       
   255 
       
   256     qint64 len = PHYSFS_readBytes(m_handle, data, maxlen);
       
   257     return len;
       
   258 }
       
   259 
       
   260 qint64 FileEngine::readLine(char *data, qint64 maxlen)
       
   261 {
       
   262     if(!m_bufferSet)
       
   263     {
       
   264         PHYSFS_setBuffer(m_handle, 4096);
       
   265         m_bufferSet = true;
       
   266     }
       
   267 
       
   268     qint64 bytesRead = 0;
       
   269     while(PHYSFS_readBytes(m_handle, data, 1)
       
   270           && maxlen
       
   271           && (*data == '\n'))
       
   272     {
       
   273         ++data;
       
   274         --maxlen;
       
   275         ++bytesRead;
       
   276     }
       
   277 
       
   278     return bytesRead;
       
   279 }
       
   280 
       
   281 qint64 FileEngine::write(const char *data, qint64 len)
       
   282 {
       
   283     return PHYSFS_writeBytes(m_handle, data, len);
       
   284 }
       
   285 
       
   286 bool FileEngine::isOpened() const
       
   287 {
       
   288     return m_handle != NULL;
       
   289 }
       
   290 
       
   291 QFile::FileError FileEngine::error() const
       
   292 {
       
   293     return QFile::UnspecifiedError;
       
   294 }
       
   295 
       
   296 QString FileEngine::errorString() const
       
   297 {
       
   298 #if PHYSFS_VER_MAJOR >= 3
       
   299     return PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode());
       
   300 #else
       
   301     return PHYSFS_getLastError();
       
   302 #endif
       
   303 }
       
   304 
       
   305 bool FileEngine::supportsExtension(Extension extension) const
       
   306 {
       
   307     return
       
   308             (extension == QAbstractFileEngine::AtEndExtension)
       
   309             || (extension == QAbstractFileEngine::FastReadLineExtension)
       
   310             ;
       
   311 }
       
   312 
       
   313 
       
   314 FileEngineHandler::FileEngineHandler(char *argv0)
       
   315 {
       
   316     if (!PHYSFS_init(argv0))
       
   317     {
       
   318         qCritical("PHYSFS initialization failed");
       
   319     }
       
   320     qDebug("%s", QString("[PHYSFS] Init: %1").arg(errorStr()).toLocal8Bit().constData());
       
   321 }
       
   322 
       
   323 FileEngineHandler::~FileEngineHandler()
       
   324 {
       
   325     PHYSFS_deinit();
       
   326 }
       
   327 
       
   328 QAbstractFileEngine* FileEngineHandler::create(const QString &filename) const
       
   329 {
       
   330     if (filename.startsWith(scheme))
       
   331         return new FileEngine(filename);
       
   332     else
       
   333         return NULL;
       
   334 }
       
   335 
       
   336 void FileEngineHandler::mount(const QString &path)
       
   337 {
       
   338     PHYSFS_mount(path.toUtf8().constData(), NULL, 0);
       
   339     qDebug("%s", QString("[PHYSFS] Mounting '%1' to '/': %2").arg(path).arg(errorStr()).toLocal8Bit().constData());
       
   340 }
       
   341 
       
   342 void FileEngineHandler::mount(const QString & path, const QString & mountPoint)
       
   343 {
       
   344     PHYSFS_mount(path.toUtf8().constData(), mountPoint.toUtf8().constData(), 0);
       
   345     qDebug("%s", QString("[PHYSFS] Mounting '%1' to '%2': %3").arg(path).arg(mountPoint).arg(errorStr()).toLocal8Bit().data());
       
   346 }
       
   347 
       
   348 void FileEngineHandler::setWriteDir(const QString &path)
       
   349 {
       
   350     PHYSFS_setWriteDir(path.toUtf8().constData());
       
   351     qDebug("%s", QString("[PHYSFS] Setting write dir to '%1': %2").arg(path).arg(errorStr()).toLocal8Bit().data());
       
   352 }
       
   353 
       
   354 void FileEngineHandler::mountPacks()
       
   355 {
       
   356     hedgewarsMountPackages();
       
   357 }
       
   358 
       
   359 QString FileEngineHandler::errorStr()
       
   360 {
       
   361     QString s;
       
   362 #if PHYSFS_VER_MAJOR >= 3
       
   363     s = QString::fromUtf8(PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
       
   364 #else
       
   365     s = QString::fromUtf8(PHYSFS_getLastError());
       
   366 #endif
       
   367     return s.isEmpty() ? "ok" : s;
       
   368 }
       
   369 
       
   370 
       
   371 FileEngineIterator::FileEngineIterator(QDir::Filters filters, const QStringList &nameFilters, const QStringList &entries)
       
   372     : QAbstractFileEngineIterator(filters, nameFilters)
       
   373 {
       
   374     m_entries = entries;
       
   375 
       
   376     /* heck.. docs are unclear on this
       
   377      * QDirIterator puts iterator before first entry
       
   378      * but QAbstractFileEngineIterator example puts iterator on first entry
       
   379      * though QDirIterator approach seems to be the right one
       
   380      */
       
   381 
       
   382     m_index = -1;
       
   383 }
       
   384 
       
   385 bool FileEngineIterator::hasNext() const
       
   386 {
       
   387     return m_index < m_entries.size() - 1;
       
   388 }
       
   389 
       
   390 QString FileEngineIterator::next()
       
   391 {
       
   392    if (!hasNext())
       
   393        return QString();
       
   394 
       
   395    ++m_index;
       
   396    return currentFilePath();
       
   397 }
       
   398 
       
   399 QString FileEngineIterator::currentFileName() const
       
   400 {
       
   401     return m_entries.at(m_index);
       
   402 }