add support for .tar/.tgz files and relevant tests ; delay scan of .tgz files and large .zip files until requested

This commit is contained in:
Etienne Tourigny 2012-06-08 01:27:19 -03:00 committed by Juergen E. Fischer
parent 4aab209400
commit a4a85cbf37
11 changed files with 303 additions and 176 deletions

View File

@ -477,7 +477,6 @@ QVector<QgsDataItem*> QgsDirectoryItem::createChildren( )
QVector<QgsDataItem*> children;
QDir dir( mPath );
QSettings settings;
bool scanZip = ( settings.value( "/qgis/scanZipInBrowser", QVariant( "basic" ) ).toString() != "no" );
QStringList entries = dir.entryList( QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name | QDir::IgnoreCase );
foreach( QString subdir, entries )
@ -497,8 +496,10 @@ QVector<QgsDataItem*> QgsDirectoryItem::createChildren( )
QString path = dir.absoluteFilePath( name );
QFileInfo fileInfo( path );
QString vsiPrefix = QgsZipItem::vsiPrefix( path );
// vsizip support was added to GDAL/OGR 1.6 but GDAL_VERSION_NUM not available here
if ( fileInfo.suffix() == "zip" && scanZip )
if (( settings.value( "/qgis/scanZipInBrowser", QVariant( "basic" ) ).toString() != "no" ) &&
( vsiPrefix == "/vsizip/" || vsiPrefix == "/vsitar/" ) )
{
QgsDataItem * item = QgsZipItem::itemFromPath( this, path, name );
if ( item )
@ -747,6 +748,7 @@ QgsZipItem::QgsZipItem( QgsDataItem* parent, QString name, QString path )
{
mType = Collection; //Zip??
mIcon = iconZip();
mVsiPrefix = vsiPrefix( path );
if ( mProviderNames.size() == 0 )
{
@ -796,7 +798,6 @@ QgsZipItem::QgsZipItem( QgsDataItem* parent, QString name, QString path )
}
}
}
}
QgsZipItem::~QgsZipItem()
@ -879,13 +880,12 @@ QVector<QgsDataItem*> QgsZipItem::createChildren( )
QVector<QgsDataItem*> children;
QString tmpPath;
QString childPath;
QSettings settings;
QString scanZipSetting = settings.value( "/qgis/scanZipInBrowser", "basic" ).toString();
mZipFileList.clear();
QgsDebugMsg( QString( "path = %1 name= %2 scanZipSetting= %3" ).arg( path() ).arg( name() ).arg( scanZipSetting ) );
QgsDebugMsg( QString( "path = %1 name= %2 scanZipSetting= %3 vsiPrefix= %4" ).arg( path() ).arg( name() ).arg( scanZipSetting ).arg( mVsiPrefix ) );
// if scanZipBrowser == no: skip to the next file
if ( scanZipSetting == "no" )
@ -901,31 +901,14 @@ QVector<QgsDataItem*> QgsZipItem::createChildren( )
// return children;
// }
// get list of files inside zip file
QgsDebugMsg( QString( "Open file %1 with gdal vsi" ).arg( path() ) );
char **papszSiblingFiles = VSIReadDirRecursive1( QString( "/vsizip/" + path() ).toLocal8Bit().constData() );
if ( papszSiblingFiles )
{
for ( int i = 0; i < CSLCount( papszSiblingFiles ); i++ )
{
tmpPath = papszSiblingFiles[i];
QgsDebugMsg( QString( "Read file %1" ).arg( tmpPath ) );
// skip directories (files ending with /)
if ( tmpPath.right( 1 ) != "/" )
mZipFileList << tmpPath;
}
CSLDestroy( papszSiblingFiles );
}
else
{
QgsDebugMsg( QString( "Error reading %1" ).arg( path() ) );
}
// first get list of files
getZipFileList();
// loop over files inside zip
foreach( QString fileName, mZipFileList )
{
QFileInfo info( fileName );
tmpPath = "/vsizip/" + path() + "/" + fileName;
tmpPath = mVsiPrefix + path() + "/" + fileName;
QgsDebugMsg( "tmpPath = " + tmpPath );
// foreach( dataItem_t *dataItem, mDataItemPtr )
@ -934,7 +917,7 @@ QVector<QgsDataItem*> QgsZipItem::createChildren( )
// ugly hack to remove .dbf file if there is a .shp file
if ( mProviderNames[i] == "ogr" )
{
if ( info.suffix() == "dbf" )
if ( info.suffix().toLower() == "dbf" )
{
if ( mZipFileList.indexOf( fileName.left( fileName.count() - 4 ) + ".shp" ) != -1 )
continue;
@ -976,20 +959,38 @@ QVector<QgsDataItem*> QgsZipItem::createChildren( )
return children;
}
QString QgsZipItem::vsiPrefix( QString path )
{
if ( path.startsWith( "/vsizip/", Qt::CaseInsensitive ) ||
path.endsWith( ".zip", Qt::CaseInsensitive ) )
return "/vsizip/";
else if ( path.startsWith( "/vsitar/", Qt::CaseInsensitive ) ||
path.endsWith( ".tar", Qt::CaseInsensitive ) ||
path.endsWith( ".tar.gz", Qt::CaseInsensitive ) ||
path.endsWith( ".tgz", Qt::CaseInsensitive ) )
return "/vsitar/";
else if ( path.startsWith( "/vsigzip/", Qt::CaseInsensitive ) ||
path.endsWith( ".gz", Qt::CaseInsensitive ) )
return "/vsigzip/";
else
return "";
}
QgsDataItem* QgsZipItem::itemFromPath( QgsDataItem* parent, QString path, QString name )
{
QSettings settings;
QString scanZipSetting = settings.value( "/qgis/scanZipInBrowser", "basic" ).toString();
QString vsizipPath = path;
QString vsiPath = path;
int zipFileCount = 0;
QStringList zipFileList;
QFileInfo fileInfo( path );
QString vsiPrefix = QgsZipItem::vsiPrefix( path );
QgsZipItem * zipItem = 0;
bool populated = false;
QgsDebugMsg( QString( "path = %1 name= %2 scanZipSetting= %3" ).arg( path ).arg( name ).arg( scanZipSetting ) );
QgsDebugMsg( QString( "path = %1 name= %2 scanZipSetting= %3 vsiPrefix= %4" ).arg( path ).arg( name ).arg( scanZipSetting ).arg( vsiPrefix ) );
// if scanZipBrowser == no: skip to the next file
// if scanZipBrowser == no: don't read the zip file
if ( scanZipSetting == "no" )
{
return 0;
@ -1007,29 +1008,47 @@ QgsDataItem* QgsZipItem::itemFromPath( QgsDataItem* parent, QString path, QStrin
if ( zipItem )
{
// force populate zipItem
zipItem->populate();
QgsDebugMsg( QString( "Got zipItem with %1 children, path=%2, name=%3" ).arg( zipItem->rowCount() ).arg( zipItem->path() ).arg( zipItem->name() ) );
// force populate zipItem if it has less than 10 items and is not a .tgz or .tar.gz file (slow loading)
// for other items populating will be delayed until item is opened
// this might be polluting the tree with empty items but is necessary for performance reasons
// could also accept all files smaller than a certain size and add options for file count and/or size
// first get list of files inside .zip or .tar files
if ( path.endsWith( ".zip", Qt::CaseInsensitive ) ||
path.endsWith( ".tar", Qt::CaseInsensitive ) )
{
zipFileList = zipItem->getZipFileList();
}
// force populate if less than 10 items
if ( zipFileList.count() > 0 && zipFileList.count() <= 10 )
{
zipItem->populate();
populated = true; // there is no QgsDataItem::isPopulated() function
QgsDebugMsg( QString( "Got zipItem with %1 children, path=%2, name=%3" ).arg( zipItem->rowCount() ).arg( zipItem->path() ).arg( zipItem->name() ) );
}
else
{
QgsDebugMsg( QString( "Delaying populating zipItem with path=%1, name=%2" ).arg( zipItem->path() ).arg( zipItem->name() ) );
}
}
// only display if has children
// other option would be to delay until item is opened, but we would be polluting the tree with empty items
if ( zipItem && zipItem->rowCount() > 1 )
// only display if has children or if is not populated
if ( zipItem && ( !populated || zipItem->rowCount() > 1 ) )
{
QgsDebugMsg( "returning zipItem" );
return zipItem;
}
// if 1 or 0 child found, create a single data item using the normal path or the full path given by QgsZipItem
// if 1 or 0 child found, create a single data item using the normal path or the full path given by QgsZipItem
else
{
if ( zipItem )
{
vsizipPath = zipItem->path();
zipFileCount = zipItem->getZipFileList().count();
vsiPath = zipItem->path();
zipFileCount = zipFileList.count();
delete zipItem;
}
QgsDebugMsg( QString( "will try to create a normal dataItem from path= %2 or %3" ).arg( path ).arg( vsizipPath ) );
QgsDebugMsg( QString( "will try to create a normal dataItem from path= %2 or %3" ).arg( path ).arg( vsiPath ) );
// try to open using registered providers (gdal and ogr)
for ( int i = 0; i < mProviderNames.size(); i++ )
@ -1047,7 +1066,7 @@ QgsDataItem* QgsZipItem::itemFromPath( QgsDataItem* parent, QString path, QStrin
item = dataItem( path, parent );
// try with /vsizip/
if ( ! item )
item = dataItem( vsizipPath, parent );
item = dataItem( vsiPath, parent );
if ( item )
return item;
}
@ -1056,3 +1075,43 @@ QgsDataItem* QgsZipItem::itemFromPath( QgsDataItem* parent, QString path, QStrin
return 0;
}
const QStringList & QgsZipItem::getZipFileList()
{
if ( ! mZipFileList.isEmpty() )
return mZipFileList;
QString tmpPath;
QSettings settings;
QString scanZipSetting = settings.value( "/qgis/scanZipInBrowser", "basic" ).toString();
QgsDebugMsg( QString( "path = %1 name= %2 scanZipSetting= %3 vsiPrefix= %4" ).arg( path() ).arg( name() ).arg( scanZipSetting ).arg( mVsiPrefix ) );
// if scanZipBrowser == no: skip to the next file
if ( scanZipSetting == "no" )
{
return mZipFileList;
}
// get list of files inside zip file
QgsDebugMsg( QString( "Open file %1 with gdal vsi" ).arg( mVsiPrefix + path() ) );
char **papszSiblingFiles = VSIReadDirRecursive1( QString( mVsiPrefix + path() ).toLocal8Bit().constData() );
if ( papszSiblingFiles )
{
for ( int i = 0; i < CSLCount( papszSiblingFiles ); i++ )
{
tmpPath = papszSiblingFiles[i];
QgsDebugMsg( QString( "Read file %1" ).arg( tmpPath ) );
// skip directories (files ending with /)
if ( tmpPath.right( 1 ) != "/" )
mZipFileList << tmpPath;
}
CSLDestroy( papszSiblingFiles );
}
else
{
QgsDebugMsg( QString( "Error reading %1" ).arg( path() ) );
}
return mZipFileList;
}

View File

@ -298,6 +298,7 @@ class CORE_EXPORT QgsZipItem : public QgsDataCollectionItem
Q_OBJECT
protected:
QString mVsiPrefix;
QStringList mZipFileList;
public:
@ -305,17 +306,17 @@ class CORE_EXPORT QgsZipItem : public QgsDataCollectionItem
~QgsZipItem();
QVector<QgsDataItem*> createChildren();
QStringList getFiles();
const QStringList & getZipFileList();
static QVector<dataItem_t *> mDataItemPtr;
static QStringList mProviderNames;
static QString vsiPrefix( QString uri );
static QgsDataItem* itemFromPath( QgsDataItem* parent, QString path, QString name );
static const QIcon &iconZip();
const QStringList & getZipFileList() const { return mZipFileList; }
};
#endif // QGSDATAITEM_H

View File

@ -642,6 +642,14 @@ QString QgsMapLayer::styleURI( )
// ideally we should look for .qml file inside zip file
myURI.remove( 0, 8 );
}
else if ( myURI.startsWith( "/vsitar/", Qt::CaseInsensitive ) &&
( myURI.endsWith( ".tar", Qt::CaseInsensitive ) ||
myURI.endsWith( ".tar.gz", Qt::CaseInsensitive ) ||
myURI.endsWith( ".tgz", Qt::CaseInsensitive ) ) )
{
// ideally we should look for .qml file inside tar file
myURI.remove( 0, 8 );
}
QFileInfo myFileInfo( myURI );
QString key;
@ -650,15 +658,18 @@ QString QgsMapLayer::styleURI( )
{
// if file is using the /vsizip/ or /vsigzip/ mechanism, cleanup the name
if ( myURI.endsWith( ".gz", Qt::CaseInsensitive ) )
{
myURI.chop( 3 );
myFileInfo.setFile( myURI );
}
else if ( myURI.endsWith( ".zip", Qt::CaseInsensitive ) )
{
myURI.chop( 4 );
myFileInfo.setFile( myURI );
}
else if ( myURI.endsWith( ".tar", Qt::CaseInsensitive ) )
myURI.chop( 4 );
else if ( myURI.endsWith( ".tar.gz", Qt::CaseInsensitive ) )
myURI.chop( 7 );
else if ( myURI.endsWith( ".tgz", Qt::CaseInsensitive ) )
myURI.chop( 4 );
else if ( myURI.endsWith( ".gz", Qt::CaseInsensitive ) )
myURI.chop( 3 );
myFileInfo.setFile( myURI );
// get the file name for our .qml style file
key = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".qml";
}

View File

@ -399,10 +399,10 @@ QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem )
// zip settings + info
QSettings settings;
QString scanZipSetting = settings.value( "/qgis/scanZipInBrowser", "basic" ).toString();
bool is_vsizip = ( thePath.startsWith( "/vsizip/" ) ||
thePath.endsWith( ".zip", Qt::CaseInsensitive ) );
bool is_vsigzip = ( thePath.startsWith( "/vsigzip/" ) ||
thePath.endsWith( ".gz", Qt::CaseInsensitive ) );
QString vsiPrefix = QgsZipItem::vsiPrefix( thePath );
bool is_vsizip = ( vsiPrefix == "/vsizip/" );
bool is_vsigzip = ( vsiPrefix == "/vsigzip/" );
bool is_vsitar = ( vsiPrefix == "/vsitar/" );
// get suffix, removing .gz if present
QString tmpPath = thePath; //path used for testing, not for layer creation
@ -414,10 +414,11 @@ QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem )
info.setFile( thePath );
QString name = info.fileName();
QgsDebugMsg( "thePath= " + thePath + " tmpPath= " + tmpPath + " name= " + name + " suffix= " + suffix );
QgsDebugMsg( "thePath= " + thePath + " tmpPath= " + tmpPath + " name= " + name
+ " suffix= " + suffix + " vsiPrefix= " + vsiPrefix );
// allow only normal files or VSIFILE items to continue
if ( !info.isFile() && !is_vsizip && !is_vsigzip )
if ( !info.isFile() && vsiPrefix == "" )
return 0;
// get supported extensions
@ -434,10 +435,6 @@ QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem )
!extensions.contains( "aux.xml" ) )
return 0;
// skip .tar.gz files
if ( thePath.endsWith( ".tar.gz", Qt::CaseInsensitive ) )
return 0;
// Filter files by extension
if ( !extensions.contains( suffix ) )
{
@ -455,30 +452,27 @@ QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem )
return 0;
}
// add /vsizip/ or /vsigzip/ to path if file extension is .zip or .gz
if ( is_vsigzip )
// fix vsifile path and name
if ( vsiPrefix != "" )
{
if ( !thePath.startsWith( "/vsigzip/" ) )
thePath = "/vsigzip/" + thePath;
}
else if ( is_vsizip )
{
if ( !thePath.startsWith( "/vsizip/" ) )
thePath = "/vsizip/" + thePath;
// add vsiPrefix to path if needed
if ( !thePath.startsWith( vsiPrefix ) )
thePath = vsiPrefix + thePath;
// if this is a /vsigzip/path_to_zip.zip/file_inside_zip remove the full path from the name
if ( thePath != "/vsizip/" + parentItem->path() )
if (( is_vsizip || is_vsitar ) && ( thePath != vsiPrefix + parentItem->path() ) )
{
name = thePath;
name = name.replace( "/vsizip/" + parentItem->path() + "/", "" );
name = name.replace( vsiPrefix + parentItem->path() + "/", "" );
}
}
// return a /vsizip/ item without testing if:
// zipfile and scan zip == "Basic scan"
// not zipfile and scan items == "Check extension"
if (( is_vsizip && scanZipSetting == "basic" ) ||
( !is_vsizip && ( settings.value( "/qgis/scanItemsInBrowser",
"extension" ).toString() == "extension" ) ) )
if ((( is_vsizip || is_vsitar ) && scanZipSetting == "basic" ) ||
( !is_vsizip && !is_vsitar &&
( settings.value( "/qgis/scanItemsInBrowser",
"extension" ).toString() == "extension" ) ) )
{
// if this is a VRT file make sure it is raster VRT to avoid duplicates
if ( suffix == "vrt" )

View File

@ -111,19 +111,12 @@ QgsGdalProvider::QgsGdalProvider( QString const & uri )
mGdalDataset = NULL;
// Try to open using VSIFileHandler (see qgsogrprovider.cpp)
// TODO suppress error messages and report in debug, like in OGR provider
// TODO use the file name of the file inside the zip, needs unzip.h
if ( uri.endsWith( ".zip", Qt::CaseInsensitive ) )
QString vsiPrefix = QgsZipItem::vsiPrefix( uri );
if ( vsiPrefix != "" )
{
if ( !uri.startsWith( "/vsizip/" ) )
setDataSourceUri( "/vsizip/" + uri );
QgsDebugMsg( QString( "Trying /vsizip syntax, uri= %1" ).arg( dataSourceUri() ) );
}
else if ( uri.endsWith( ".gz", Qt::CaseInsensitive ) )
{
if ( !uri.startsWith( "/vsigzip/" ) )
setDataSourceUri( "/vsigzip/" + uri );
QgsDebugMsg( QString( "Trying /vsigzip syntax, uri= %1" ).arg( dataSourceUri() ) );
if ( !uri.startsWith( vsiPrefix ) )
setDataSourceUri( vsiPrefix + uri );
QgsDebugMsg( QString( "Trying %1 syntax, uri= %2" ).arg( vsiPrefix ).arg( dataSourceUri() ) );
}
// The uri is either a file name or encoded parameters for WCS
@ -1920,8 +1913,9 @@ void buildSupportedRasterFileFilterAndExtensions( QString & theFileFiltersString
{
QString glob = "*.zip";
glob += " *.gz";
glob += " *.tar *.tar.gz *.tgz";
theFileFiltersString += ";;[GDAL] " + QObject::tr( "GDAL/OGR VSIFileHandler" ) + " (" + glob.toLower() + " " + glob.toUpper() + ")";
theExtensions << "zip" << "gz";
theExtensions << "zip" << "gz" << "tar" << "tar.gz" << "tgz";
}
#endif
@ -1940,21 +1934,12 @@ QGISEXTERN bool isValidRasterFileName( QString const & theFileNameQString, QStri
// Try to open using VSIFileHandler (see qgsogrprovider.cpp)
// TODO suppress error messages and report in debug, like in OGR provider
if ( fileName.endsWith( ".zip", Qt::CaseInsensitive ) )
QString vsiPrefix = QgsZipItem::vsiPrefix( fileName );
if ( vsiPrefix != "" )
{
if ( !fileName.startsWith( "/vsizip/" ) )
{
fileName = "/vsizip/" + fileName;
}
QgsDebugMsg( QString( "Trying /vsizip syntax, fileName= %1" ).arg( fileName ) );
}
if ( fileName.endsWith( ".gz", Qt::CaseInsensitive ) )
{
if ( !fileName.startsWith( "/vsigzip/" ) )
{
fileName = "/vsigzip/" + fileName;
}
QgsDebugMsg( QString( "Trying /vsigzip syntax, fileName= %1" ).arg( fileName ) );
if ( !fileName.startsWith( vsiPrefix ) )
fileName = vsiPrefix + fileName;
QgsDebugMsg( QString( "Trying %1 syntax, fileName= %2" ).arg( vsiPrefix ).arg( fileName ) );
}
//open the file using gdal making sure we have handled locale properly

View File

@ -240,10 +240,10 @@ QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem )
// zip settings + info
QSettings settings;
QString scanZipSetting = settings.value( "/qgis/scanZipInBrowser", "basic" ).toString();
bool is_vsizip = ( thePath.startsWith( "/vsizip/" ) ||
thePath.endsWith( ".zip", Qt::CaseInsensitive ) );
bool is_vsigzip = ( thePath.startsWith( "/vsigzip/" ) ||
thePath.endsWith( ".gz", Qt::CaseInsensitive ) );
QString vsiPrefix = QgsZipItem::vsiPrefix( thePath );
bool is_vsizip = ( vsiPrefix == "/vsizip/" );
bool is_vsigzip = ( vsiPrefix == "/vsigzip/" );
bool is_vsitar = ( vsiPrefix == "/vsitar/" );
// get suffix, removing .gz if present
QString tmpPath = thePath; //path used for testing, not for layer creation
@ -255,10 +255,11 @@ QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem )
info.setFile( thePath );
QString name = info.fileName();
QgsDebugMsg( "thePath= " + thePath + " tmpPath= " + tmpPath + " name= " + name + " suffix= " + suffix );
QgsDebugMsg( "thePath= " + thePath + " tmpPath= " + tmpPath + " name= " + name
+ " suffix= " + suffix + " vsiPrefix= " + vsiPrefix );
// allow only normal files or VSIFILE items to continue
if ( !info.isFile() && !is_vsizip && !is_vsigzip )
if ( !info.isFile() && vsiPrefix == "" )
return 0;
QStringList myExtensions = fileExtensions();
@ -272,10 +273,6 @@ QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem )
!myExtensions.contains( "shp.xml" ) )
return 0;
// skip .tar.gz files
if ( thePath.endsWith( ".tar.gz", Qt::CaseInsensitive ) )
return 0;
// We have to filter by extensions, otherwise e.g. all Shapefile files are displayed
// because OGR drive can open also .dbf, .shx.
if ( myExtensions.indexOf( suffix ) < 0 )
@ -302,30 +299,27 @@ QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem )
return 0;
}
// add /vsizip/ or /vsigzip/ to path if file extension is .zip or .gz
if ( is_vsigzip )
// fix vsifile path and name
if ( vsiPrefix != "" )
{
if ( !thePath.startsWith( "/vsigzip/" ) )
thePath = "/vsigzip/" + thePath;
}
else if ( is_vsizip )
{
if ( !thePath.startsWith( "/vsizip/" ) )
thePath = "/vsizip/" + thePath;
// add vsiPrefix to path if needed
if ( !thePath.startsWith( vsiPrefix ) )
thePath = vsiPrefix + thePath;
// if this is a /vsigzip/path_to_zip.zip/file_inside_zip remove the full path from the name
if ( thePath != "/vsizip/" + parentItem->path() )
if (( is_vsizip || is_vsitar ) && ( thePath != vsiPrefix + parentItem->path() ) )
{
name = thePath;
name = name.replace( "/vsizip/" + parentItem->path() + "/", "" );
name = name.replace( vsiPrefix + parentItem->path() + "/", "" );
}
}
// return a /vsizip/ item without testing if:
// zipfile and scan zip == "Basic scan"
// not zipfile and scan items == "Check extension"
if (( is_vsizip && scanZipSetting == "basic" ) ||
( !is_vsizip && ( settings.value( "/qgis/scanItemsInBrowser",
"extension" ).toString() == "extension" ) ) )
if ((( is_vsizip || is_vsitar ) && scanZipSetting == "basic" ) ||
( !is_vsizip && !is_vsitar &&
( settings.value( "/qgis/scanItemsInBrowser",
"extension" ).toString() == "extension" ) ) )
{
// if this is a VRT file make sure it is vector VRT to avoid duplicates
if ( suffix == "vrt" )

View File

@ -264,26 +264,18 @@ QgsOgrProvider::QgsOgrProvider( QString const & uri )
// Try to open using VSIFileHandler
// see http://trac.osgeo.org/gdal/wiki/UserDocs/ReadInZip
if ( mFilePath.endsWith( ".zip", Qt::CaseInsensitive ) )
QString vsiPrefix = QgsZipItem::vsiPrefix( uri );
if ( vsiPrefix != "" )
{
// GDAL>=1.8.0 has write support for zip, but read and write operations
// cannot be interleaved, so for now just use read-only.
openReadOnly = true;
if ( !mFilePath.startsWith( "/vsizip/" ) )
if ( !mFilePath.startsWith( vsiPrefix ) )
{
mFilePath = "/vsizip/" + mFilePath;
mFilePath = vsiPrefix + mFilePath;
setDataSourceUri( mFilePath );
}
QgsDebugMsg( QString( "Trying /vsizip syntax, mFilePath= %1" ).arg( mFilePath ) );
}
else if ( mFilePath.endsWith( ".gz", Qt::CaseInsensitive ) )
{
if ( !mFilePath.startsWith( "/vsigzip/" ) )
{
mFilePath = "/vsigzip/" + mFilePath;
setDataSourceUri( mFilePath );
}
QgsDebugMsg( QString( "Trying /vsigzip syntax, mFilePath= %1" ).arg( mFilePath ) );
QgsDebugMsg( QString( "Trying %1 syntax, mFilePath= %2" ).arg( vsiPrefix ).arg( mFilePath ) );
}
QgsDebugMsg( "mFilePath: " + mFilePath );
@ -1792,16 +1784,14 @@ QString createFilters( QString type )
// VSIFileHandler (.zip and .gz files)
// see http://trac.osgeo.org/gdal/wiki/UserDocs/ReadInZip
// Requires GDAL>=1.6.0 with libz support, let's assume we have it.
// For .zip this works only if there is one file (or dataset) in the root of the zip.
// Only tested with tiff, shape (zip) and spatialite (zip and gz).
// This does not work for some file types, see VSIFileHandler doc.
// Ideally we should also add support for /vsitar/ (requires cpl_vsil_tar.cpp).
#if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1600
QSettings settings;
if ( settings.value( "/qgis/scanZipInBrowser", "basic" ).toString() != "no" )
{
myFileFilters += createFileFilter_( QObject::tr( "GDAL/OGR VSIFileHandler" ), "*.zip *.gz" );
myExtensions << "zip" << "gz";
myFileFilters += createFileFilter_( QObject::tr( "GDAL/OGR VSIFileHandler" ), "*.zip *.gz *.tar *.tar.gz *.tgz" );
myExtensions << "zip" << "gz" << "tar" << "tar.gz" << "tgz";
}
#endif

View File

@ -53,6 +53,7 @@ class TestZipLayer: public QObject
bool testZipItem( QString myFileName, QString myChildName = "", QString myDriverName = "" );
// get layer transparency to test for .qml loading
int getLayerTransparency( QString myFileName, QString myProviderKey, QString myScanZipSetting = "basic" );
bool testZipItemTransparency( QString myFileName, QString myProviderKey, int myTarget );
private slots:
@ -65,20 +66,28 @@ class TestZipLayer: public QObject
// tests
// test for .zip and .gz files using all options
void testPassthruVectorZip();
void testPassthruVectorTar();
void testPassthruVectorGzip();
void testPassthruRasterZip();
void testPassthruRasterTar();
void testPassthruRasterGzip();
// test both "Basic Scan" and "Full scan" for .zip files
void testZipItemRaster();
void testTarItemRaster();
void testZipItemVector();
void testTarItemVector();
void testZipItemAll();
void testTarItemAll();
// test that styles are loaded from .qml files outside zip files
void testZipItemVectorTransparency();
void testGZipItemVectorTransparency();
void testTarItemVectorTransparency();
void testGzipItemVectorTransparency();
void testZipItemRasterTransparency();
void testGZipItemRasterTransparency();
void testTarItemRasterTransparency();
void testGzipItemRasterTransparency();
//make sure items inside subfolders can be read
void testZipItemSubfolder();
void testTarItemSubfolder();
//make sure .vrt items are loaded by proper provider (gdal/ogr)
void testZipItemVRT();
};
@ -225,6 +234,21 @@ int TestZipLayer::getLayerTransparency( QString myFileName, QString myProviderKe
return myTransparency;
}
bool TestZipLayer::testZipItemTransparency( QString myFileName, QString myProviderKey, int myTarget )
{
int myTransparency;
foreach( QString s, mScanZipSettings )
{
myTransparency = getLayerTransparency( myFileName, myProviderKey, s );
if ( myTransparency != myTarget )
{
QWARN( QString( "Transparency of %1 is %2, should be %3" ).arg( myFileName ).arg( myTransparency ).arg( myTarget ).toLocal8Bit().data() );
return false;
}
}
return true;
}
// slots
void TestZipLayer::initTestCase()
@ -257,7 +281,6 @@ void TestZipLayer::cleanupTestCase()
settings.setValue( "/qgis/scanZipInBrowser", mScanZipSetting );
}
void TestZipLayer::testPassthruVectorZip()
{
QSettings settings;
@ -275,6 +298,21 @@ void TestZipLayer::testPassthruVectorZip()
}
}
void TestZipLayer::testPassthruVectorTar()
{
QSettings settings;
QString myFileName = mDataDir + "points2.tar";
#if GDAL_VERSION_NUM < 1800
QSKIP( "This test requires GDAL >= 1.8", SkipSingle );
#endif
foreach( QString s, mScanZipSettings )
{
settings.setValue( "/qgis/scanZipInBrowser", s );
QVERIFY( s == settings.value( "/qgis/scanZipInBrowser" ).toString() );
QVERIFY( testZipItemPassthru( myFileName, "ogr" ) );
}
}
void TestZipLayer::testPassthruVectorGzip()
{
QSettings settings;
@ -300,6 +338,20 @@ void TestZipLayer::testPassthruRasterZip()
}
}
void TestZipLayer::testPassthruRasterTar()
{
#if GDAL_VERSION_NUM < 1800
QSKIP( "This test requires GDAL >= 1.8", SkipSingle );
#endif
QSettings settings;
foreach( QString s, mScanZipSettings )
{
settings.setValue( "/qgis/scanZipInBrowser", s );
QVERIFY( s == settings.value( "/qgis/scanZipInBrowser" ).toString() );
QVERIFY( testZipItemPassthru( mDataDir + "landsat_b1.tar", "gdal" ) );
}
}
void TestZipLayer::testPassthruRasterGzip()
{
QSettings settings;
@ -322,6 +374,20 @@ void TestZipLayer::testZipItemRaster()
}
}
void TestZipLayer::testTarItemRaster()
{
#if GDAL_VERSION_NUM < 1800
QSKIP( "This test requires GDAL >= 1.8", SkipSingle );
#endif
QSettings settings;
foreach( QString s, mScanZipSettings )
{
settings.setValue( "/qgis/scanZipInBrowser", s );
QVERIFY( s == settings.value( "/qgis/scanZipInBrowser" ).toString() );
QVERIFY( testZipItem( mDataDir + "testtar.tgz", "landsat_b1.tif" ) );
}
}
void TestZipLayer::testZipItemVector()
{
QSettings settings;
@ -333,6 +399,20 @@ void TestZipLayer::testZipItemVector()
}
}
void TestZipLayer::testTarItemVector()
{
#if GDAL_VERSION_NUM < 1800
QSKIP( "This test requires GDAL >= 1.8", SkipSingle );
#endif
QSettings settings;
foreach( QString s, mScanZipSettings )
{
settings.setValue( "/qgis/scanZipInBrowser", s );
QVERIFY( s == settings.value( "/qgis/scanZipInBrowser" ).toString() );
QVERIFY( testZipItem( mDataDir + "testtar.tgz", "points.shp" ) );
}
}
void TestZipLayer::testZipItemAll()
{
// test file contains invalid items (tmp1.tif, tmp1.txt and tmp1.xml)
@ -345,55 +425,57 @@ void TestZipLayer::testZipItemAll()
QVERIFY( testZipItem( mDataDir + "testzip.zip", "" ) );
}
void TestZipLayer::testTarItemAll()
{
#if GDAL_VERSION_NUM < 1800
QSKIP( "This test requires GDAL >= 1.8", SkipSingle );
#endif
QSettings settings;
settings.setValue( "/qgis/scanZipInBrowser", "full" );
QVERIFY( "full" == settings.value( "/qgis/scanZipInBrowser" ).toString() );
QVERIFY( testZipItem( mDataDir + "testtar.tgz", "" ) );
}
void TestZipLayer::testZipItemVectorTransparency()
{
#if GDAL_VERSION_NUM < 1800
QSKIP( "This test requires GDAL >= 1.8", SkipSingle );
#endif
int myTarget = 250;
int myTransparency;
foreach( QString s, mScanZipSettings )
{
myTransparency = getLayerTransparency( mDataDir + "points2.zip", "ogr", "basic" );
QVERIFY2(( myTransparency == myTarget ), QString( "Transparency is %1, should be %2" ).arg( myTransparency ).arg( myTarget ).toLocal8Bit().data() );
}
QVERIFY( testZipItemTransparency( mDataDir + "points2.zip", "ogr", 250 ) );
}
void TestZipLayer::testGZipItemVectorTransparency()
void TestZipLayer::testTarItemVectorTransparency()
{
#if GDAL_VERSION_NUM < 1800
QSKIP( "This test requires GDAL >= 1.8", SkipSingle );
#endif
QVERIFY( testZipItemTransparency( mDataDir + "points2.tar", "ogr", 250 ) );
}
void TestZipLayer::testGzipItemVectorTransparency()
{
#if GDAL_VERSION_NUM < 1700
QSKIP( "This test requires GDAL >= 1.7", SkipSingle );
#endif
int myTarget = 250;
int myTransparency;
foreach( QString s, mScanZipSettings )
{
myTransparency = getLayerTransparency( mDataDir + "points3.geojson.gz", "ogr", s );
QVERIFY2(( myTransparency == myTarget ), QString( "Transparency is %1, should be %2" ).arg( myTransparency ).arg( myTarget ).toLocal8Bit().data() );
}
QVERIFY( testZipItemTransparency( mDataDir + "points3.geojson.gz", "ogr", 250 ) );
}
void TestZipLayer::testZipItemRasterTransparency()
{
int myTarget = 250;
int myTransparency;
foreach( QString s, mScanZipSettings )
{
myTransparency = getLayerTransparency( mDataDir + "landsat_b1.zip", "gdal", s );
QVERIFY2(( myTransparency == myTarget ), QString( "Transparency is %1, should be %2" ).arg( myTransparency ).arg( myTarget ).toLocal8Bit().data() );
}
QVERIFY( testZipItemTransparency( mDataDir + "landsat_b1.zip", "gdal", 250 ) );
}
void TestZipLayer::testGZipItemRasterTransparency()
void TestZipLayer::testTarItemRasterTransparency()
{
int myTarget = 250;
int myTransparency;
foreach( QString s, mScanZipSettings )
{
myTransparency = getLayerTransparency( mDataDir + "landsat_b1.tif.gz", "gdal", s );
QVERIFY2(( myTransparency == myTarget ), QString( "Transparency is %1, should be %2" ).arg( myTransparency ).arg( myTarget ).toLocal8Bit().data() );
}
#if GDAL_VERSION_NUM < 1800
QSKIP( "This test requires GDAL >= 1.8", SkipSingle );
#endif
QVERIFY( testZipItemTransparency( mDataDir + "landsat_b1.tar", "gdal", 250 ) );
}
void TestZipLayer::testGzipItemRasterTransparency()
{
QVERIFY( testZipItemTransparency( mDataDir + "landsat_b1.tif.gz", "gdal", 250 ) );
}
void TestZipLayer::testZipItemSubfolder()
@ -407,6 +489,17 @@ void TestZipLayer::testZipItemSubfolder()
}
}
void TestZipLayer::testTarItemSubfolder()
{
QSettings settings;
foreach( QString s, mScanZipSettings )
{
settings.setValue( "/qgis/scanZipInBrowser", s );
QVERIFY( s == settings.value( "/qgis/scanZipInBrowser" ).toString() );
QVERIFY( testZipItem( mDataDir + "testtar.tgz", "folder/folder2/landsat_b2.tif" ) );
}
}
void TestZipLayer::testZipItemVRT()
{

BIN
tests/testdata/landsat_b1.tar vendored Normal file

Binary file not shown.

BIN
tests/testdata/points2.tar vendored Normal file

Binary file not shown.

BIN
tests/testdata/testtar.tgz vendored Normal file

Binary file not shown.