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.