18 #include "qgsconfig.h" 
   23 #include <QRegularExpression> 
   27 #include <QDirIterator> 
   31 #include <sys/resource.h> 
   38 #pragma comment(lib,"Shell32.lib")
 
   44   list << QObject::tr( 
"KB" ) << QObject::tr( 
"MB" ) << QObject::tr( 
"GB" ) << QObject::tr( 
"TB" );
 
   46   QStringListIterator i( list );
 
   47   QString unit = QObject::tr( 
"B" );
 
   49   double fileSize = bytes;
 
   50   while ( fileSize >= 1024.0 && i.hasNext() )
 
   55   return QStringLiteral( 
"%1 %2" ).arg( QString::number( fileSize, 
'f', bytes >= 1048576 ? 2 : 0 ), unit );
 
   60   const QRegularExpression rx( QStringLiteral( 
"\\*\\.([a-zA-Z0-9]+)" ) );
 
   61   QStringList extensions;
 
   62   QRegularExpressionMatchIterator matches = rx.globalMatch( filter );
 
   64   while ( matches.hasNext() )
 
   66     const QRegularExpressionMatch match = matches.next();
 
   67     if ( match.hasMatch() )
 
   69       QStringList newExtensions = match.capturedTexts();
 
   70       newExtensions.pop_front(); 
 
   71       extensions.append( newExtensions );
 
   79   const QRegularExpression globPatternsRx( QStringLiteral( 
".*\\((.*?)\\)$" ) );
 
   80   const QRegularExpressionMatch matches = globPatternsRx.match( filter );
 
   81   if ( matches.hasMatch() )
 
   82     return matches.captured( 1 );
 
   89   QFileInfo fi( fileName );
 
   90   const QString name = fi.fileName();
 
   91   const QStringList parts = filter.split( QStringLiteral( 
";;" ) );
 
   92   for ( 
const QString &part : parts )
 
   94 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) 
   95     const QStringList globPatterns = 
wildcardsFromFilter( part ).split( 
' ', QString::SkipEmptyParts );
 
   97     const QStringList globPatterns = 
wildcardsFromFilter( part ).split( 
' ', Qt::SkipEmptyParts );
 
   99     for ( 
const QString &glob : globPatterns )
 
  101       const QString re = QRegularExpression::wildcardToRegularExpression( glob );
 
  103       const QRegularExpression globRx( re );
 
  104       if ( globRx.match( name ).hasMatch() )
 
  113   if ( extensions.empty() || f.isEmpty() )
 
  116   QString fileName = f;
 
  118   for ( 
const QString &extension : std::as_const( extensions ) )
 
  120     const QString extWithDot = extension.startsWith( 
'.' ) ? extension : 
'.' + extension;
 
  121     if ( fileName.endsWith( extWithDot, Qt::CaseInsensitive ) )
 
  130     const QString extension = extensions.at( 0 );
 
  131     const QString extWithDot = extension.startsWith( 
'.' ) ? extension : 
'.' + extension;
 
  132     fileName += extWithDot;
 
  146   QRegularExpression rx( QStringLiteral( 
"[/\\\\\\?%\\*\\:\\|\"<>]" ) );
 
  148   s.replace( rx, QStringLiteral( 
"_" ) );
 
  154   if ( path.isEmpty() )
 
  158   QFileInfo fi( path );
 
  160     currentPath = fi.dir();
 
  162     currentPath = QDir( path );
 
  164   QSet< QString > visited;
 
  165   while ( !currentPath.exists() )
 
  167     const QString parentPath = QDir::cleanPath( currentPath.absolutePath() + QStringLiteral( 
"/.." ) );
 
  168     if ( visited.contains( parentPath ) )
 
  171     if ( parentPath.isEmpty() || parentPath == QLatin1String( 
"." ) )
 
  173     currentPath = QDir( parentPath );
 
  174     visited << parentPath;
 
  177   const QString res = QDir::cleanPath( currentPath.absolutePath() );
 
  179   if ( res == QDir::currentPath() )
 
  182   return res == QLatin1String( 
"." ) ? QString() : res;
 
  185 QStringList 
QgsFileUtils::findFile( 
const QString &file, 
const QString &basePath, 
int maxClimbs, 
int searchCeilling, 
const QString ¤tDir )
 
  188   QString originalFolder;
 
  190   const QString fileName( basePath.isEmpty() ? QFileInfo( file ).fileName() : file );
 
  191   const QString baseFolder( basePath.isEmpty() ? QFileInfo( file ).path() : basePath );
 
  193   if ( QFileInfo( baseFolder ).isDir() )
 
  195     folder = QDir( baseFolder ) ;
 
  196     originalFolder = folder.absolutePath();
 
  200     folder = QDir( QFileInfo( baseFolder ).absolutePath() );
 
  201     originalFolder = folder.absolutePath();
 
  204   QStringList searchedFolder = QStringList();
 
  205   QString existingBase;
 
  206   QString backupDirectory = QDir::currentPath();
 
  207   QStringList foundFiles;
 
  209   if ( !currentDir.isEmpty() && backupDirectory != currentDir && QDir( currentDir ).exists() )
 
  210     QDir::setCurrent( currentDir );
 
  213   while ( !folder.exists() && folder.absolutePath().count( 
'/' ) > searchCeilling )
 
  216     existingBase = folder.path();
 
  217     if ( !folder.cdUp() )
 
  218       folder = QFileInfo( existingBase ).absoluteDir(); 
 
  222     if ( depth > ( maxClimbs + 4 ) ) 
 
  225   bool folderExists = folder.exists();
 
  227   if ( depth > maxClimbs )
 
  230   if ( folder.absolutePath().count( 
'/' ) < searchCeilling )
 
  231     searchCeilling = folder.absolutePath().count( 
'/' ) - 1;
 
  233   while ( depth <= maxClimbs && folderExists && folder.absolutePath().count( 
'/' ) >= searchCeilling )
 
  236     QDirIterator localFinder( folder.path(), QStringList() << fileName, QDir::Files, QDirIterator::NoIteratorFlags );
 
  237     searchedFolder.append( folder.absolutePath() );
 
  238     if ( localFinder.hasNext() )
 
  240       foundFiles << localFinder.next();
 
  245     const QFileInfoList subdirs = folder.entryInfoList( QDir::AllDirs );
 
  246     for ( 
const QFileInfo &subdir : subdirs )
 
  248       if ( ! searchedFolder.contains( subdir.absolutePath() ) )
 
  250         QDirIterator subDirFinder( subdir.path(), QStringList() << fileName, QDir::Files, QDirIterator::Subdirectories );
 
  251         if ( subDirFinder.hasNext() )
 
  253           QString possibleFile = subDirFinder.next();
 
  254           if ( !subDirFinder.hasNext() )
 
  256             foundFiles << possibleFile;
 
  260           foundFiles << possibleFile;
 
  261           while ( subDirFinder.hasNext() )
 
  263             foundFiles << subDirFinder.next();
 
  271     if ( depth > maxClimbs )
 
  274     folderExists = folder.cdUp();
 
  277   if ( QDir::currentPath() == currentDir && currentDir != backupDirectory )
 
  278     QDir::setCurrent( backupDirectory );
 
  284 std::unique_ptr< wchar_t[] > pathToWChar( 
const QString &path )
 
  286   const QString nativePath = QDir::toNativeSeparators( path );
 
  288   std::unique_ptr< wchar_t[] > pathArray( 
new wchar_t[
static_cast< uint
>( nativePath.length() + 1 )] );
 
  289   nativePath.toWCharArray( pathArray.get() );
 
  290   pathArray[
static_cast< size_t >( nativePath.length() )] = 0;
 
  298   auto pathType = [ = ]( 
const QString & path ) -> DriveType
 
  300     std::unique_ptr< wchar_t[] > pathArray = pathToWChar( path );
 
  301     const UINT type = GetDriveTypeW( pathArray.get() );
 
  307       case DRIVE_NO_ROOT_DIR:
 
  310       case DRIVE_REMOVABLE:
 
  330   const QString originalPath = QDir::cleanPath( path );
 
  331   QString currentPath = originalPath;
 
  333   while ( currentPath != prevPath )
 
  335     prevPath = currentPath;
 
  336     currentPath = QFileInfo( currentPath ).path();
 
  337     const DriveType type = pathType( currentPath );
 
  338     if ( type != Unknown && type != Invalid )
 
  352   if ( path.contains( QLatin1String( 
"fake_slow_path_for_unit_tests" ) ) )
 
  384   for ( 
const QString &provider : providers )
 
  390       for ( 
const QString &possibleSidecar : possibleSidecars )
 
  392         if ( QFile::exists( possibleSidecar ) )
 
  393           res.insert( possibleSidecar );
 
  402   if ( !QFile::exists( oldPath ) )
 
  404     error = QObject::tr( 
"File does not exist" );
 
  408   const QFileInfo oldPathInfo( oldPath );
 
  412     const QString qmdPath = oldPathInfo.dir().filePath( oldPathInfo.completeBaseName() + QStringLiteral( 
".qmd" ) );
 
  413     if ( QFile::exists( qmdPath ) )
 
  414       sidecars.insert( qmdPath );
 
  418     const QString qmlPath = oldPathInfo.dir().filePath( oldPathInfo.completeBaseName() + QStringLiteral( 
".qml" ) );
 
  419     if ( QFile::exists( qmlPath ) )
 
  420       sidecars.insert( qmlPath );
 
  423   const QFileInfo newPathInfo( newPath );
 
  427   errors.reserve( sidecars.size() );
 
  429   for ( 
const QString &sidecar : std::as_const( sidecars ) )
 
  431     const QFileInfo sidecarInfo( sidecar );
 
  432     const QString newSidecarName = newPathInfo.dir().filePath( newPathInfo.completeBaseName() + 
'.' + sidecarInfo.suffix() );
 
  433     if ( newSidecarName != sidecar && QFile::exists( newSidecarName ) )
 
  436       errors.append( QDir::toNativeSeparators( newSidecarName ) );
 
  441     error = QObject::tr( 
"Destination files already exist %1" ).arg( errors.join( QLatin1String( 
", " ) ) );
 
  445   if ( !QFile::rename( oldPath, newPath ) )
 
  447     error = QObject::tr( 
"Could not rename %1" ).arg( QDir::toNativeSeparators( oldPath ) );
 
  451   for ( 
const QString &sidecar : std::as_const( sidecars ) )
 
  453     const QFileInfo sidecarInfo( sidecar );
 
  454     const QString newSidecarName = newPathInfo.dir().filePath( newPathInfo.completeBaseName() + 
'.' + sidecarInfo.suffix() );
 
  455     if ( newSidecarName == sidecar )
 
  458     if ( !QFile::rename( sidecar, newSidecarName ) )
 
  460       errors.append( QDir::toNativeSeparators( sidecar ) );
 
  466     error = QObject::tr( 
"Could not rename %1" ).arg( errors.join( QLatin1String( 
", " ) ) );
 
  475   struct rlimit rescLimit;
 
  476   if ( getrlimit( RLIMIT_NOFILE, &rescLimit ) == 0 )
 
  478     return rescLimit.rlim_cur;
 
  487   int res = 
static_cast<int>( QDir( 
"/proc/self/fd" ).entryList().size() );
 
  501   constexpr 
int SOME_MARGIN = 20;
 
  502   return nFileCount > 0 && nFileLimit > 0 && nFileCount + filesToBeOpened > nFileLimit - SOME_MARGIN;
 
@ Removable
Removable drive.
@ IncludeMetadataFile
Indicates that any associated .qmd metadata file should be included with the operation.
@ IncludeStyleFile
Indicates that any associated .qml styling file should be included with the operation.
static QString stringToSafeFilename(const QString &string)
Converts a string to a safe filename, replacing characters which are not safe for filenames with an '...
static QStringList findFile(const QString &file, const QString &basepath=QString(), int maxClimbs=4, int searchCeiling=4, const QString ¤tDir=QString())
Will check basepath in an outward spiral up to maxClimbs levels to check if file exists.
static int openedFileCount()
Returns the number of currently opened files by the process.
static QString wildcardsFromFilter(const QString &filter)
Given a filter string like "GeoTIFF Files (*.tiff *.tif)", extracts the wildcard portion of this filt...
static bool renameDataset(const QString &oldPath, const QString &newPath, QString &error, Qgis::FileOperationFlags flags=Qgis::FileOperationFlag::IncludeMetadataFile|Qgis::FileOperationFlag::IncludeStyleFile)
Renames the dataset at oldPath to newPath, renaming both the file at oldPath and all associated sidec...
static QSet< QString > sidecarFilesForPath(const QString &path)
Returns a list of the sidecar files which exist for the dataset a the specified path.
static bool pathIsSlowDevice(const QString &path)
Returns true if the specified path is assumed to reside on a slow device, e.g.
static bool isCloseToLimitOfOpenedFiles(int filesToBeOpened=1)
Returns whether when opening new file(s) will reach, or nearly reach, the limit of simultaneously ope...
static bool fileMatchesFilter(const QString &fileName, const QString &filter)
Returns true if the given fileName matches a file filter string.
static Qgis::DriveType driveType(const QString &path) SIP_THROW(QgsNotSupportedException)
Returns the drive type for the given path.
static QString ensureFileNameHasExtension(const QString &fileName, const QStringList &extensions)
Ensures that a fileName ends with an extension from the provided list of extensions.
static QString representFileSize(qint64 bytes)
Returns the human size from bytes.
static QString addExtensionFromFilter(const QString &fileName, const QString &filter)
Ensures that a fileName ends with an extension from the specified filter string.
static int openedFileLimit()
Returns the limit of simultaneously opened files by the process.
static QString findClosestExistingPath(const QString &path)
Returns the top-most existing folder from path.
static QStringList extensionsFromFilter(const QString &filter)
Returns a list of the extensions contained within a file filter string.
Custom exception class which is raised when an operation is not supported.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
QStringList providerList() const
Returns list of available providers by their keys.
QgsProviderMetadata * providerMetadata(const QString &providerKey) const
Returns metadata of the provider or nullptr if not found.