46  for ( 
const auto &resolver : customResolvers )
 
   47    filename = resolver.second( filename );
 
   49  if ( filename.isEmpty() )
 
   52  QString src = filename;
 
   53  if ( src.startsWith( QLatin1String( 
"inbuilt:" ) ) )
 
   59  if ( src.startsWith( QLatin1String( 
"localized:" ) ) )
 
   61    QStringList parts = src.split( 
"|" );
 
   64    if ( !parts[0].isEmpty() )
 
   66      return parts.join( 
"|" );
 
   73  if ( src.startsWith( QLatin1String( 
"attachment:" ) ) )
 
   76    return QDir( mAttachmentDir ).absoluteFilePath( src.mid( 11 ) );
 
   79  if ( mBaseFileName.isNull() )
 
   86  if ( ! vsiPrefix.isEmpty() )
 
   90    if ( src.startsWith( QLatin1String( 
"/vsi" ), Qt::CaseInsensitive ) )
 
   91      src.remove( 0, vsiPrefix.size() );
 
   97  if ( !src.startsWith( QLatin1String( 
"./" ) ) && !src.startsWith( QLatin1String( 
"../" ) ) )
 
  100    if ( src.startsWith( 
"\\\\" ) ||
 
  101         src.startsWith( 
"//" ) ||
 
  102         ( src[0].isLetter() && src[1] == 
':' ) )
 
  105      return vsiPrefix + src;
 
  111      return vsiPrefix + src;
 
  120    const QFileInfo pfi( mBaseFileName );
 
  121    const QString home = pfi.absolutePath();
 
  122    if ( home.isEmpty() )
 
  123      return vsiPrefix + src;
 
  125    const QFileInfo fi( home + 
'/' + src );
 
  129      return vsiPrefix + src;
 
  133      return vsiPrefix + QDir::cleanPath( fi.absoluteFilePath() );
 
  137  QString srcPath = src;
 
  138  QString projPath = mBaseFileName;
 
  140  if ( projPath.isEmpty() )
 
  142    return vsiPrefix + src;
 
  148  thread_local const QRegularExpression delimiterRe( R
"re(delimiter=([^&]+))re" ); 
  149  const QRegularExpressionMatch match = delimiterRe.match( srcPath );
 
  150  if ( match.hasMatch() )
 
  152    const QString delimiter = match.captured( 0 ).replace( 
'\\', QLatin1String( 
"%5C" ) );
 
  153    srcPath.replace( match.captured( 0 ), delimiter );
 
  156  srcPath.replace( 
'\\', 
'/' );
 
  157  projPath.replace( 
'\\', 
'/' );
 
  159  bool uncPath = projPath.startsWith( 
"//" );
 
  163  projPath = QFileInfo( projPath ).absoluteFilePath();
 
  165  const QStringList srcElems = srcPath.split( 
'/', Qt::SkipEmptyParts );
 
  166  QStringList projElems = projPath.split( 
'/', Qt::SkipEmptyParts );
 
  171    projElems.insert( 0, 
"" );
 
  172    projElems.insert( 0, 
"" );
 
  177  projElems.removeLast();
 
  180  projElems << srcElems;
 
  181  projElems.removeAll( QStringLiteral( 
"." ) );
 
  185  while ( ( pos = projElems.indexOf( QLatin1String( 
".." ) ) ) > 0 )
 
  188    projElems.removeAt( pos - 1 );
 
  189    projElems.removeAt( pos - 1 );
 
  192#if !defined(Q_OS_WIN) 
  194  projElems.prepend( QString() );
 
  197  return vsiPrefix + projElems.join( QLatin1Char( 
'/' ) );
 
 
  209  const size_t prevCount = sCustomResolvers()->size();
 
  210  sCustomResolvers()->erase( std::remove_if( sCustomResolvers()->begin(), sCustomResolvers()->end(), [
id]( std::pair< QString, std::function< QString( 
const QString & ) > > &a )
 
  212    return a.first == id;
 
  213  } ), sCustomResolvers()->end() );
 
  214  return prevCount != sCustomResolvers()->size();
 
 
  226  const size_t prevCount = sCustomWriters()->size();
 
  227  sCustomWriters()->erase( std::remove_if( sCustomWriters()->begin(), sCustomWriters()->end(), [
id]( std::pair< QString, std::function< QString( 
const QString & ) > > &a )
 
  229    return a.first == id;
 
  230  } ), sCustomWriters()->end() );
 
  231  return prevCount != sCustomWriters()->size();
 
 
  243  if ( !localizedPath.isEmpty() )
 
  244    return QStringLiteral( 
"localized:" ) + localizedPath;
 
  247  for ( 
const auto &writer :  customWriters )
 
  248    src = writer.second( src );
 
  256  if ( !mAttachmentDir.isEmpty() && src.startsWith( mAttachmentDir ) )
 
  259    return QStringLiteral( 
"attachment:" ) + QFileInfo( src ).fileName();
 
  262  if ( mBaseFileName.isEmpty() )
 
  268  const QFileInfo pfi( QFileInfo( mBaseFileName ).path() );
 
  270  QString projPath = pfi.absoluteFilePath();
 
  274  if ( projPath.isEmpty() )
 
  275    projPath = pfi.absoluteFilePath();
 
  277  if ( projPath.isEmpty() )
 
  283  const QUrl url { src };
 
  284  QString srcPath { src };
 
  287  if ( url.isLocalFile( ) )
 
  289    srcPath = url.path();
 
  290    urlQuery = url.query();
 
  293  const QFileInfo srcFileInfo( srcPath );
 
  296  if ( !srcFileInfo.isAbsolute() )
 
  300  if ( srcFileInfo.exists() )
 
  302    srcPath = QDir::cleanPath( srcFileInfo.absoluteFilePath() );
 
  306  if ( ! vsiPrefix.isEmpty() )
 
  308    srcPath.remove( 0, vsiPrefix.size() );
 
  311#if defined( Q_OS_WIN ) 
  312  const Qt::CaseSensitivity cs = Qt::CaseInsensitive;
 
  314  srcPath.replace( 
'\\', 
'/' );
 
  316  if ( srcPath.startsWith( 
"//" ) )
 
  319    srcPath = 
"\\\\" + srcPath.mid( 2 );
 
  322  projPath.replace( 
'\\', 
'/' );
 
  323  if ( projPath.startsWith( 
"//" ) )
 
  326    projPath = 
"\\\\" + projPath.mid( 2 );
 
  329  const Qt::CaseSensitivity cs = Qt::CaseSensitive;
 
  332  QStringList projElems = projPath.split( 
'/', Qt::SkipEmptyParts );
 
  333  QStringList srcElems = srcPath.split( 
'/', Qt::SkipEmptyParts );
 
  335  projElems.removeAll( QStringLiteral( 
"." ) );
 
  336  srcElems.removeAll( QStringLiteral( 
"." ) );
 
  340  while ( !srcElems.isEmpty() &&
 
  341          !projElems.isEmpty() &&
 
  342          srcElems[0].compare( projElems[0], cs ) == 0 )
 
  344    srcElems.removeFirst();
 
  345    projElems.removeFirst();
 
  355  if ( !projElems.isEmpty() )
 
  358    for ( 
int i = 0; i < projElems.size(); i++ )
 
  360      srcElems.insert( 0, QStringLiteral( 
".." ) );
 
  367    srcElems.insert( 0, QStringLiteral( 
"." ) );
 
  371  QString returnPath { vsiPrefix + srcElems.join( QLatin1Char( 
'/' ) ) };
 
  372  if ( ! urlQuery.isEmpty() )
 
  374    returnPath.append( 
'?' );
 
  375    returnPath.append( urlQuery );