18 #include "qgsconfig.h" 
   20 #include <QRegularExpression> 
   24 #include <QDirIterator> 
   29 #pragma comment(lib,"Shell32.lib")
 
   35   list << QObject::tr( 
"KB" ) << QObject::tr( 
"MB" ) << QObject::tr( 
"GB" ) << QObject::tr( 
"TB" );
 
   37   QStringListIterator i( list );
 
   38   QString unit = QObject::tr( 
"bytes" );
 
   40   while ( bytes >= 1024.0 && i.hasNext() )
 
   45   return QStringLiteral( 
"%1 %2" ).arg( QString::number( bytes ), unit );
 
   50   const QRegularExpression rx( QStringLiteral( 
"\\*\\.([a-zA-Z0-9]+)" ) );
 
   51   QStringList extensions;
 
   52   QRegularExpressionMatchIterator matches = rx.globalMatch( filter );
 
   54   while ( matches.hasNext() )
 
   56     const QRegularExpressionMatch match = matches.next();
 
   57     if ( match.hasMatch() )
 
   59       QStringList newExtensions = match.capturedTexts();
 
   60       newExtensions.pop_front(); 
 
   61       extensions.append( newExtensions );
 
   69   const QRegularExpression globPatternsRx( QStringLiteral( 
".*\\((.*?)\\)$" ) );
 
   70   const QRegularExpressionMatch matches = globPatternsRx.match( filter );
 
   71   if ( matches.hasMatch() )
 
   72     return matches.captured( 1 );
 
   79   QFileInfo fi( fileName );
 
   80   const QString name = fi.fileName();
 
   81   const QStringList parts = filter.split( QStringLiteral( 
";;" ) );
 
   82   for ( 
const QString &part : parts )
 
   84 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) 
   85     const QStringList globPatterns = 
wildcardsFromFilter( part ).split( 
' ', QString::SkipEmptyParts );
 
   87     const QStringList globPatterns = 
wildcardsFromFilter( part ).split( 
' ', Qt::SkipEmptyParts );
 
   89     for ( 
const QString &glob : globPatterns )
 
   91       const QString re = QRegularExpression::wildcardToRegularExpression( glob );
 
   93       const QRegularExpression globRx( re );
 
   94       if ( globRx.match( name ).hasMatch() )
 
  103   if ( extensions.empty() || f.isEmpty() )
 
  106   QString fileName = f;
 
  108   for ( 
const QString &extension : std::as_const( extensions ) )
 
  110     const QString extWithDot = extension.startsWith( 
'.' ) ? extension : 
'.' + extension;
 
  111     if ( fileName.endsWith( extWithDot, Qt::CaseInsensitive ) )
 
  120     const QString extension = extensions.at( 0 );
 
  121     const QString extWithDot = extension.startsWith( 
'.' ) ? extension : 
'.' + extension;
 
  122     fileName += extWithDot;
 
  136   QRegularExpression rx( QStringLiteral( 
"[/\\\\\\?%\\*\\:\\|\"<>]" ) );
 
  138   s.replace( rx, QStringLiteral( 
"_" ) );
 
  144   if ( path.isEmpty() )
 
  148   QFileInfo fi( path );
 
  150     currentPath = fi.dir();
 
  152     currentPath = QDir( path );
 
  154   QSet< QString > visited;
 
  155   while ( !currentPath.exists() )
 
  157     const QString parentPath = QDir::cleanPath( currentPath.absolutePath() + QStringLiteral( 
"/.." ) );
 
  158     if ( visited.contains( parentPath ) )
 
  161     if ( parentPath.isEmpty() || parentPath == QLatin1String( 
"." ) )
 
  163     currentPath = QDir( parentPath );
 
  164     visited << parentPath;
 
  167   const QString res = QDir::cleanPath( currentPath.absolutePath() );
 
  169   if ( res == QDir::currentPath() )
 
  172   return res == QLatin1String( 
"." ) ? QString() : res;
 
  175 QStringList 
QgsFileUtils::findFile( 
const QString &file, 
const QString &basePath, 
int maxClimbs, 
int searchCeilling, 
const QString ¤tDir )
 
  178   QString originalFolder;
 
  180   const QString fileName( basePath.isEmpty() ? QFileInfo( file ).fileName() : file );
 
  181   const QString baseFolder( basePath.isEmpty() ? QFileInfo( file ).path() : basePath );
 
  183   if ( QFileInfo( baseFolder ).isDir() )
 
  185     folder = QDir( baseFolder ) ;
 
  186     originalFolder = folder.absolutePath();
 
  190     folder = QDir( QFileInfo( baseFolder ).absolutePath() );
 
  191     originalFolder = folder.absolutePath();
 
  194   QStringList searchedFolder = QStringList();
 
  195   QString existingBase;
 
  196   QString backupDirectory = QDir::currentPath();
 
  197   QStringList foundFiles;
 
  199   if ( !currentDir.isEmpty() && backupDirectory != currentDir && QDir( currentDir ).exists() )
 
  200     QDir::setCurrent( currentDir );
 
  203   while ( !folder.exists() && folder.absolutePath().count( 
'/' ) > searchCeilling )
 
  206     existingBase = folder.path();
 
  207     if ( !folder.cdUp() )
 
  208       folder = QFileInfo( existingBase ).absoluteDir(); 
 
  212     if ( depth > ( maxClimbs + 4 ) ) 
 
  215   bool folderExists = folder.exists();
 
  217   if ( depth > maxClimbs )
 
  220   if ( folder.absolutePath().count( 
'/' ) < searchCeilling )
 
  221     searchCeilling = folder.absolutePath().count( 
'/' ) - 1;
 
  223   while ( depth <= maxClimbs && folderExists && folder.absolutePath().count( 
'/' ) >= searchCeilling )
 
  226     QDirIterator localFinder( folder.path(), QStringList() << fileName, QDir::Files, QDirIterator::NoIteratorFlags );
 
  227     searchedFolder.append( folder.absolutePath() );
 
  228     if ( localFinder.hasNext() )
 
  230       foundFiles << localFinder.next();
 
  235     const QFileInfoList subdirs = folder.entryInfoList( QDir::AllDirs );
 
  236     for ( 
const QFileInfo &subdir : subdirs )
 
  238       if ( ! searchedFolder.contains( subdir.absolutePath() ) )
 
  240         QDirIterator subDirFinder( subdir.path(), QStringList() << fileName, QDir::Files, QDirIterator::Subdirectories );
 
  241         if ( subDirFinder.hasNext() )
 
  243           QString possibleFile = subDirFinder.next();
 
  244           if ( !subDirFinder.hasNext() )
 
  246             foundFiles << possibleFile;
 
  250           foundFiles << possibleFile;
 
  251           while ( subDirFinder.hasNext() )
 
  253             foundFiles << subDirFinder.next();
 
  261     if ( depth > maxClimbs )
 
  264     folderExists = folder.cdUp();
 
  267   if ( QDir::currentPath() == currentDir && currentDir != backupDirectory )
 
  268     QDir::setCurrent( backupDirectory );
 
  274 std::unique_ptr< wchar_t[] > pathToWChar( 
const QString &path )
 
  276   const QString nativePath = QDir::toNativeSeparators( path );
 
  278   std::unique_ptr< wchar_t[] > pathArray( 
new wchar_t[
static_cast< uint
>( nativePath.length() + 1 )] );
 
  279   nativePath.toWCharArray( pathArray.get() );
 
  280   pathArray[
static_cast< size_t >( nativePath.length() )] = 0;
 
  288   auto pathType = [ = ]( 
const QString & path ) -> DriveType
 
  290     std::unique_ptr< wchar_t[] > pathArray = pathToWChar( path );
 
  291     const UINT type = GetDriveTypeW( pathArray.get() );
 
  297       case DRIVE_NO_ROOT_DIR:
 
  300       case DRIVE_REMOVABLE:
 
  320   const QString originalPath = QDir::cleanPath( path );
 
  321   QString currentPath = originalPath;
 
  323   while ( currentPath != prevPath )
 
  325     prevPath = currentPath;
 
  326     currentPath = QFileInfo( currentPath ).path();
 
  327     const DriveType type = pathType( currentPath );
 
  328     if ( type != Unknown && type != Invalid )
 
  342   if ( path.contains( QLatin1String( 
"fake_slow_path_for_unit_tests" ) ) )
 
@ Removable
Removable drive.
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 QString wildcardsFromFilter(const QString &filter)
Given a filter string like "GeoTIFF Files (*.tiff *.tif)", extracts the wildcard portion of this filt...
static bool pathIsSlowDevice(const QString &path)
Returns true if the specified path is assumed to reside on a slow device, e.g.
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 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.