Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
add preliminary support for GDAL/OGR VSIFileHandler (.zip and .gz fil…
…es) - full support requires new QgsCollectionItem class
  • Loading branch information
etiennesky committed Apr 2, 2012
1 parent 8b351e2 commit df90065
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 13 deletions.
3 changes: 2 additions & 1 deletion src/app/qgisapp.cpp
Expand Up @@ -6822,7 +6822,8 @@ bool QgisApp::addRasterLayers( QStringList const &theFileNameQStringList, bool g
QFileInfo myFileInfo( *myIterator );
// get the directory the .adf file was in
QString myDirNameQString = myFileInfo.path();
QString myBaseNameQString = myFileInfo.completeBaseName();
//extract basename with extension
QString myBaseNameQString = myFileInfo.completeBaseName() + "." + myFileInfo.suffix();
//only allow one copy of a ai grid file to be loaded at a
//time to prevent the user selecting all adfs in 1 dir which
//actually represent 1 coverage,
Expand Down
23 changes: 21 additions & 2 deletions src/providers/gdal/qgsgdaldataitems.cpp
Expand Up @@ -106,20 +106,26 @@ QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem )
QFileInfo info( thePath );
if ( info.isFile() )
{
// Filter files by extension
// get supported extensions
if ( extensions.isEmpty() )
{
QString filterString;
buildSupportedRasterFileFilterAndExtensions( filterString, extensions, wildcards );
QgsDebugMsg( "extensions: " + extensions.join( " " ) );
QgsDebugMsg( "wildcards: " + wildcards.join( " " ) );
}

// skip *.aux.xml files (GDAL auxilary metadata files)
// unless that extension is in the list (*.xml might be though)
if ( thePath.right( 8 ) == ".aux.xml" &&
extensions.indexOf( "aux.xml" ) < 0 )
return 0;

// skip .tar.gz files
if ( thePath.right( 7 ) == ".tar.gz" )
return 0;

// Filter files by extension
if ( extensions.indexOf( info.suffix().toLower() ) < 0 )
{
bool matches = false;
Expand All @@ -136,6 +142,19 @@ QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem )
return 0;
}

// try to open using VSIFileHandler
// TODO use the file name of the file inside the zip for layer name
if ( thePath.right( 4 ) == ".zip" )
{
if ( thePath.left( 8 ) != "/vsizip/" )
thePath = "/vsizip/" + thePath;
}
else if ( thePath.right( 3 ) == ".gz" )
{
if ( thePath.left( 9 ) != "/vsigzip/" )
thePath = "/vsigzip/" + thePath;
}

GDALAllRegister();
GDALDatasetH hDS = GDALOpen( TO8F( thePath ), GA_ReadOnly );

Expand All @@ -150,7 +169,7 @@ QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem )
QgsDebugMsg( "GdalDataset opened " + thePath );

//extract basename with extension
QString name = info.completeBaseName() + "." + QFileInfo( thePath ).suffix();
QString name = info.completeBaseName() + "." + info.suffix();
QString uri = thePath;

QgsLayerItem * item = new QgsGdalLayerItem( parentItem, name, thePath, uri,
Expand Down
52 changes: 48 additions & 4 deletions src/providers/gdal/qgsgdalprovider.cpp
Expand Up @@ -105,13 +105,29 @@ 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.right( 4 ) == ".zip" )
{
if ( uri.left( 8 ) != "/vsizip/" )
setDataSourceUri( "/vsizip/" + uri );
QgsDebugMsg( QString( "Trying /vsizip syntax, uri= %1" ).arg( dataSourceUri() ) );
}
else if ( uri.right( 3 ) == ".gz" )
{
if ( uri.left( 9 ) != "/vsigzip/" )
setDataSourceUri( "/vsigzip/" + uri );
QgsDebugMsg( QString( "Trying /vsigzip syntax, uri= %1" ).arg( dataSourceUri() ) );
}

//mGdalBaseDataset = GDALOpen( QFile::encodeName( uri ).constData(), GA_ReadOnly );
mGdalBaseDataset = GDALOpen( TO8F( uri ), GA_ReadOnly );
mGdalBaseDataset = GDALOpen( TO8F( dataSourceUri() ), GA_ReadOnly );

CPLErrorReset();
if ( mGdalBaseDataset == NULL )
{
QgsDebugMsg( QString( "Cannot open GDAL dataset %1: %2" ).arg( uri ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
QgsDebugMsg( QString( "Cannot open GDAL dataset %1: %2" ).arg( dataSourceUri() ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
return;
}

Expand Down Expand Up @@ -1818,12 +1834,23 @@ void buildSupportedRasterFileFilterAndExtensions( QString & theFileFiltersString
{
catchallFilter << QString( GDALGetDescription( myGdalDriver ) );
}
}
} // each loaded GDAL driver

myGdalDriverExtension = myGdalDriverLongName = ""; // reset for next driver

} // each loaded GDAL driver

// VSIFileHandler (see qgsogrprovider.cpp)
#if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1600
if ( 1 )
{
QString glob = "*.zip";
glob += " *.gz";
theFileFiltersString += ";;[GDAL] " + QObject::tr( "GDAL/OGR VSIFileHandler" ) + " (" + glob.toLower() + " " + glob.toUpper() + ")";
theExtensions << "zip" << "gz";
}
#endif

QgsDebugMsg( "Raster filter list built: " + theFileFiltersString );
} // buildSupportedRasterFileFilter_()

Expand All @@ -1835,9 +1862,26 @@ QGISEXTERN bool isValidRasterFileName( QString const & theFileNameQString, QStri

CPLErrorReset();

QString fileName = theFileNameQString;

// Try to open using VSIFileHandler (see qgsogrprovider.cpp)
// TODO suppress error messages and report in debug, like in OGR provider
if ( fileName.right( 4 ) == ".zip" )
{
if ( fileName.left( 8 ) != "/vsizip/" )
fileName = "/vsizip/" + fileName;
QgsDebugMsg( QString( "Trying /vsizip syntax, fileName= %1" ).arg( fileName ) );
}
if ( fileName.right( 3 ) == ".gz" )
{
if ( fileName.left( 9 ) != "/vsigzip/" )
fileName = "/vsigzip/" + fileName;
QgsDebugMsg( QString( "Trying /vsigzip syntax, fileName= %1" ).arg( fileName ) );
}

//open the file using gdal making sure we have handled locale properly
//myDataset = GDALOpen( QFile::encodeName( theFileNameQString ).constData(), GA_ReadOnly );
myDataset = GDALOpen( TO8F( theFileNameQString ), GA_ReadOnly );
myDataset = GDALOpen( TO8F( fileName ), GA_ReadOnly );
if ( myDataset == NULL )
{
if ( CPLGetLastErrorNo() != CPLE_OpenFailed )
Expand Down
22 changes: 20 additions & 2 deletions src/providers/ogr/qgsogrdataitems.cpp
Expand Up @@ -229,9 +229,14 @@ QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem )
if ( !info.isFile() )
return 0;

QStringList myExtensions = fileExtensions();

// skip .tar.gz files
if ( thePath.right( 7 ) == ".tar.gz" )
return 0;

// We have to filter by extensions, otherwise e.g. all Shapefile files are displayed
// because OGR drive can open also .dbf, .shx.
QStringList myExtensions = fileExtensions();
if ( myExtensions.indexOf( info.suffix().toLower() ) < 0 )
{
bool matches = false;
Expand All @@ -256,6 +261,18 @@ QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem )
return 0;
}

// try to open using the /vsizip mechanism
if ( thePath.right( 4 ) == ".zip" )
{
if ( thePath.left( 8 ) != "/vsizip/" )
thePath = "/vsizip/" + thePath;
}
else if ( thePath.right( 3 ) == ".gz" )
{
if ( thePath.left( 9 ) != "/vsigzip/" )
thePath = "/vsigzip/" + thePath;
}

OGRRegisterAll();
OGRSFDriverH hDriver;
OGRDataSourceH hDataSource = OGROpen( TO8F( thePath ), false, &hDriver );
Expand All @@ -272,7 +289,8 @@ QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem )

if ( numLayers == 1 )
{
QString name = info.completeBaseName();
//extract basename with extension
QString name = info.completeBaseName() + "." + QFileInfo( thePath ).suffix();
item = dataItemForLayer( parentItem, name, thePath, hDataSource, 0 );
}
else if ( numLayers > 1 )
Expand Down
54 changes: 50 additions & 4 deletions src/providers/ogr/qgsogrprovider.cpp
Expand Up @@ -259,15 +259,41 @@ QgsOgrProvider::QgsOgrProvider( QString const & uri )
}
}

bool openReadOnly = false;

// Try to open using VSIFileHandler
// see http://trac.osgeo.org/gdal/wiki/UserDocs/ReadInZip
if ( mFilePath.right( 4 ) == ".zip" )
{
// 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.left( 8 ) != "/vsizip/" )
mFilePath = "/vsizip/" + mFilePath;
QgsDebugMsg( QString( "Trying /vsizip syntax, mFilePath= %1" ).arg( mFilePath ) );
}
else if ( mFilePath.right( 3 ) == ".gz" )
{
if ( mFilePath.left( 9 ) != "/vsigzip/" )
mFilePath = "/vsigzip/" + mFilePath;
QgsDebugMsg( QString( "Trying /vsigzip syntax, mFilePath= %1" ).arg( mFilePath ) );
}

QgsDebugMsg( "mFilePath: " + mFilePath );
QgsDebugMsg( "mLayerIndex: " + QString::number( mLayerIndex ) );
QgsDebugMsg( "mLayerName: " + mLayerName );
QgsDebugMsg( "mSubsetString: " + mSubsetString );
CPLSetConfigOption( "OGR_ORGANIZE_POLYGONS", "ONLY_CCW" ); // "SKIP" returns MULTIPOLYGONs for multiringed POLYGONs

ogrDataSource = OGROpen( TO8F( mFilePath ), true, &ogrDriver );
// first try to open in update mode (unless specified otherwise)
if ( ! openReadOnly )
ogrDataSource = OGROpen( TO8F( mFilePath ), true, &ogrDriver );

if ( !ogrDataSource )
{

QgsDebugMsg( "OGR failed to opened in update mode, trying in read-only mode" );

// try to open read-only
ogrDataSource = OGROpen( TO8F( mFilePath ), false, &ogrDriver );

Expand All @@ -279,8 +305,7 @@ QgsOgrProvider::QgsOgrProvider( QString const & uri )
if ( ogrDataSource )
{

QgsDebugMsg( "Data source is valid" );
QgsDebugMsg( "OGR Driver was " + QString( OGR_Dr_GetName( ogrDriver ) ) );
QgsDebugMsg( "OGR opened using Driver " + QString( OGR_Dr_GetName( ogrDriver ) ) );

ogrDriverName = OGR_Dr_GetName( ogrDriver );

Expand All @@ -299,6 +324,11 @@ QgsOgrProvider::QgsOgrProvider( QString const & uri )
if ( ogrLayer )
{
valid = setSubsetString( mSubsetString );
QgsDebugMsg( "Data source is valid" );
}
else
{
QgsMessageLog::logMessage( tr( "Data source is invalid, no layer found (%1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ), tr( "OGR" ) );
}
}
else
Expand Down Expand Up @@ -1742,7 +1772,23 @@ QString createFilters( QString type )
QgsDebugMsg( QString( "Unknown driver %1 for file filters." ).arg( driverName ) );
}

} // each loaded GDAL driver
} // each loaded OGR driver

// 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 shape (zip) and spatialite (zip and gz).
// Ideally we should add a new subclass of QgsCollectionItem (or QgsDirItem), say QgsZipItem
// and read the files inside the zip (requires unzip.h or cpl_minizip_unzip.h)
// and also add support for /vsitar/ (requires cpl_vsil_tar.cpp).
#if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1600
if ( 1 )
{
myFileFilters += createFileFilter_( QObject::tr( "GDAL/OGR VSIFileHandler" ), "*.zip *.gz" );
myExtensions << "zip" << "gz";
}
#endif

// can't forget the default case

Expand Down

0 comments on commit df90065

Please sign in to comment.