Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[GRASS] alloc enough space for Map_info on Windows, fixes #13002
  • Loading branch information
blazek committed Jun 20, 2015
1 parent d31ba26 commit cb7f9b4
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 38 deletions.
29 changes: 15 additions & 14 deletions src/providers/grass/qgis.v.in.cpp
Expand Up @@ -119,15 +119,16 @@ int main( int argc, char **argv )
bool isPolygon = QGis::singleType( wkbFlatType ) == QGis::WKBPolygon;

QString finalName = QString( mapOption->answer );
struct Map_info finalMap, tmpMap;
Vect_open_new( &finalMap, mapOption->answer, 0 );
struct Map_info * map = &finalMap;
struct Map_info *finalMap = QgsGrass::vectNewMapStruct();
struct Map_info *tmpMap = QgsGrass::vectNewMapStruct();
Vect_open_new( finalMap, mapOption->answer, 0 );
struct Map_info * map = finalMap;
QDateTime now = QDateTime::currentDateTime();
QString tmpName = QString( "%1_tmp_%2" ).arg( mapOption->answer ).arg( now.toString( "yyyyMMddhhmmss" ) );
if ( isPolygon )
{
Vect_open_new( &tmpMap, tmpName.toUtf8().data(), 0 );
map = &tmpMap;
Vect_open_new( tmpMap, tmpName.toUtf8().data(), 0 );
map = tmpMap;
}

QgsFields srcFields;
Expand All @@ -149,8 +150,8 @@ int main( int argc, char **argv )
fields.append( QgsField( key, QVariant::Int ) );
fields.extend( srcFields );

struct field_info *fieldInfo = Vect_default_field_info( &finalMap, 1, NULL, GV_1TABLE );
if ( Vect_map_add_dblink( &finalMap, 1, NULL, fieldInfo->table, key.toLatin1().data(),
struct field_info *fieldInfo = Vect_default_field_info( finalMap, 1, NULL, GV_1TABLE );
if ( Vect_map_add_dblink( finalMap, 1, NULL, fieldInfo->table, key.toLatin1().data(),
fieldInfo->database, fieldInfo->driver ) != 0 )
{
G_fatal_error( "Cannot add link" );
Expand All @@ -176,7 +177,7 @@ int main( int argc, char **argv )
qint32 featureCount = 0;
while ( true )
{
exitIfCanceled( stdinStream, isPolygon, tmpName, &tmpMap, finalName, &finalMap );
exitIfCanceled( stdinStream, isPolygon, tmpName, tmpMap, finalName, finalMap );
stdinStream >> feature;
stdoutStream << ( bool )true; // feature received
stdoutFile.flush();
Expand Down Expand Up @@ -333,7 +334,7 @@ int main( int argc, char **argv )
// read once more to assign centroids to polygons
while ( true )
{
exitIfCanceled( stdinStream, isPolygon, tmpName, &tmpMap, finalName, &finalMap );
exitIfCanceled( stdinStream, isPolygon, tmpName, tmpMap, finalName, finalMap );
stdinStream >> feature;
stdoutStream << ( bool )true; // feature received
stdoutFile.flush();
Expand All @@ -359,8 +360,8 @@ int main( int argc, char **argv )
}
}

Vect_copy_map_lines( &tmpMap, &finalMap );
Vect_close( &tmpMap );
Vect_copy_map_lines( tmpMap, finalMap );
Vect_close( tmpMap );
Vect_delete( tmpName.toUtf8().data() );

foreach ( QgsFeature centroid, centroids.values() )
Expand All @@ -374,14 +375,14 @@ int main( int argc, char **argv )
{
Vect_cat_set( cats, 1, attribute.toInt() );
}
writePoint( &finalMap, GV_CENTROID, point, cats );
writePoint( finalMap, GV_CENTROID, point, cats );
}
}
}

db_close_database_shutdown_driver( driver );
Vect_build( &finalMap );
Vect_close( &finalMap );
Vect_build( finalMap );
Vect_close( finalMap );

stdoutStream << ( bool )true; // to keep caller waiting until finished
stdoutFile.flush();
Expand Down
67 changes: 44 additions & 23 deletions src/providers/grass/qgsgrass.cpp
Expand Up @@ -1007,7 +1007,11 @@ QStringList GRASS_LIB_EXPORT QgsGrass::vectorLayers( const QString& gisdbase, co
/* Open vector */
QgsGrass::resetError();
//Vect_set_open_level( 2 );
struct Map_info map;

// TODO: We are currently using vectDestroyMapStruct in G_CATCH blocks because we know
// that it does cannot call another G_fatal_error, but once we switch to hypothetical Vect_destroy_map_struct
// it should be verified if it can still be in G_CATCH
struct Map_info *map = vectNewMapStruct();
int level = -1;

// Vect_open_old_head GRASS is raising fatal error if topo exists but it is in different (older) version.
Expand All @@ -1016,17 +1020,12 @@ QStringList GRASS_LIB_EXPORT QgsGrass::vectorLayers( const QString& gisdbase, co

G_TRY
{
// TODO: With Vect_open_old_head it crashes on Windows + GRASS 7 in Vect_cidx_get_type_count() when the first
// type is found. Try to open full map on win for now.
#if defined(Q_OS_WIN) && GRASS_VERSION_MAJOR >= 7
level = Vect_open_old( &map, ( char * ) mapName.toUtf8().data(), ( char * ) mapset.toUtf8().data() );
#else
level = Vect_open_old_head( &map, ( char * ) mapName.toUtf8().data(), ( char * ) mapset.toUtf8().data() );
#endif
level = Vect_open_old_head( map, ( char * ) mapName.toUtf8().data(), ( char * ) mapset.toUtf8().data() );
}
G_CATCH( QgsGrass::Exception &e )
{
QgsDebugMsg( QString( "Cannot open GRASS vector: %1" ).arg( e.what() ) );
vectDestroyMapStruct( map );
GRASS_UNLOCK
throw e;
}
Expand All @@ -1042,8 +1041,9 @@ QStringList GRASS_LIB_EXPORT QgsGrass::vectorLayers( const QString& gisdbase, co
// crash on win http://trac.osgeo.org/qgis/ticket/2003
// disabled on win test it
#ifndef Q_OS_WIN
Vect_close( &map );
Vect_close( map );
#endif
vectDestroyMapStruct( map );
GRASS_UNLOCK
throw QgsGrass::Exception( QObject::tr( "Cannot open vector on level 2" ) );
}
Expand All @@ -1052,6 +1052,7 @@ QStringList GRASS_LIB_EXPORT QgsGrass::vectorLayers( const QString& gisdbase, co
QgsDebugMsg( "Cannot open vector" );
// Do not open QMessageBox here!
//QMessageBox::warning( 0, QObject::tr( "Warning" ), QObject::tr( "Cannot open vector %1 in mapset %2" ).arg( mapName ).arg( mapset ) );
vectDestroyMapStruct( map );
GRASS_UNLOCK
throw QgsGrass::Exception( QObject::tr( "Cannot open vector" ) );
}
Expand All @@ -1061,18 +1062,18 @@ QStringList GRASS_LIB_EXPORT QgsGrass::vectorLayers( const QString& gisdbase, co
G_TRY
{
// Get layers
int ncidx = Vect_cidx_get_num_fields( &map );
int ncidx = Vect_cidx_get_num_fields( map );

for ( int i = 0; i < ncidx; i++ )
{
int field = Vect_cidx_get_field_number( &map, i );
int field = Vect_cidx_get_field_number( map, i );
QString fs;
fs.sprintf( "%d", field );

QgsDebugMsg( QString( "i = %1 layer = %2" ).arg( i ).arg( field ) );

/* Points */
int npoints = Vect_cidx_get_type_count( &map, field, GV_POINT );
int npoints = Vect_cidx_get_type_count( map, field, GV_POINT );
QgsDebugMsg( QString( "npoints = %1" ).arg( npoints ) );
if ( npoints > 0 )
{
Expand All @@ -1088,7 +1089,7 @@ QStringList GRASS_LIB_EXPORT QgsGrass::vectorLayers( const QString& gisdbase, co
else
tp = GV_LINE | GV_BOUNDARY;

int nlines = Vect_cidx_get_type_count( &map, field, tp );
int nlines = Vect_cidx_get_type_count( map, field, tp );
QgsDebugMsg( QString( "nlines = %1" ).arg( nlines ) );
if ( nlines > 0 )
{
Expand All @@ -1097,7 +1098,7 @@ QStringList GRASS_LIB_EXPORT QgsGrass::vectorLayers( const QString& gisdbase, co
}

/* Faces */
int nfaces = Vect_cidx_get_type_count( &map, field, GV_FACE );
int nfaces = Vect_cidx_get_type_count( map, field, GV_FACE );
QgsDebugMsg( QString( "nfaces = %1" ).arg( nfaces ) );
if ( nfaces > 0 )
{
Expand All @@ -1106,7 +1107,7 @@ QStringList GRASS_LIB_EXPORT QgsGrass::vectorLayers( const QString& gisdbase, co
}

/* Polygons */
int nareas = Vect_cidx_get_type_count( &map, field, GV_AREA );
int nareas = Vect_cidx_get_type_count( map, field, GV_AREA );
QgsDebugMsg( QString( "nareas = %1" ).arg( nareas ) );
if ( nareas > 0 )
{
Expand All @@ -1122,34 +1123,33 @@ QStringList GRASS_LIB_EXPORT QgsGrass::vectorLayers( const QString& gisdbase, co
if ( listTopoLayers )
{
// add topology layers
if ( Vect_get_num_primitives( &map, GV_POINTS ) > 0 )
if ( Vect_get_num_primitives( map, GV_POINTS ) > 0 )
{
#if GRASS_VERSION_MAJOR < 7 /* no more point in GRASS 7 topo */
list.append( "topo_point" );
#endif
}
if ( Vect_get_num_primitives( &map, GV_LINES ) > 0 )
if ( Vect_get_num_primitives( map, GV_LINES ) > 0 )
{
list.append( "topo_line" );
}
if ( Vect_get_num_nodes( &map ) > 0 )
if ( Vect_get_num_nodes( map ) > 0 )
{
list.append( "topo_node" );
}
}

QgsDebugMsg( "close map" );
Vect_close( &map );
QgsDebugMsg( "map closed" );
Vect_close( map );
vectDestroyMapStruct( map );
GRASS_UNLOCK
}
G_CATCH( QgsGrass::Exception &e )
{
QgsDebugMsg( QString( "Cannot get vector layers: %1" ).arg( e.what() ) );
vectDestroyMapStruct( map );
GRASS_UNLOCK
throw e;
}

GRASS_UNLOCK
return list;
}

Expand Down Expand Up @@ -2200,3 +2200,24 @@ void GRASS_LIB_EXPORT QgsGrass::putEnv( QString name, QString value )
putenv( envChar );
}

struct Map_info GRASS_LIB_EXPORT *QgsGrass::vectNewMapStruct()
{
// In OSGeo4W there is GRASS compiled by MinGW while QGIS compiled by MSVC, the compilers
// may have different sizes of types, see issue #13002. Because there is no Vect_new_map_struct (GRASS 7.0.0, July 2015)
// the structure is allocated here using doubled (should be enough) space.
// TODO: replace by Vect_new_map_struct once it appears in GRASS
#if defined(WIN32)
return ( struct Map_info* ) qgsMalloc( 2*sizeof( struct Map_info ) );
#else
return ( struct Map_info* ) qgsMalloc( sizeof( struct Map_info ) );
#endif
}

void GRASS_LIB_EXPORT QgsGrass::vectDestroyMapStruct( struct Map_info *map )
{
// TODO: replace by Vect_destroy_map_struct once it appears in GRASS
// TODO: until switch to hypothetical Vect_destroy_map_struct verify that Vect_destroy_map_struct cannot
// call G_fatal_error, otherwise check and remove use of vectDestroyMapStruct from G_CATCH blocks
qgsFree( map );
map = 0;
}
5 changes: 5 additions & 0 deletions src/providers/grass/qgsgrass.h
Expand Up @@ -412,6 +412,11 @@ class QgsGrass
// path to QGIS GRASS modules like qgis.g.info etc.
static GRASS_LIB_EXPORT QString qgisGrassModulePath() { return QgsApplication::libexecPath() + "grass/modules"; }

// Allocate struct Map_info
static GRASS_LIB_EXPORT struct Map_info * vectNewMapStruct();
// Free struct Map_info
static GRASS_LIB_EXPORT void vectDestroyMapStruct( struct Map_info *map );

private:
static int initialized; // Set to 1 after initialization
static bool active; // is active mode
Expand Down
4 changes: 3 additions & 1 deletion src/providers/grass/qgsgrassprovider.cpp
Expand Up @@ -783,7 +783,7 @@ int QgsGrassProvider::openMap( QString gisdbase, QString location, QString mapse
map.nUsers = 1;
map.version = 1;
map.update = 0;
map.map = ( struct Map_info * ) malloc( sizeof( struct Map_info ) );
map.map = QgsGrass::vectNewMapStruct();

// Set GRASS location
QgsGrass::setLocation( gisdbase, location );
Expand Down Expand Up @@ -982,6 +982,8 @@ void QgsGrassProvider::closeMap( int mapId )

if ( mapsetunset )
G__setenv(( char * )"MAPSET", "" );

// TODO: verify if vectDestroyMapStruct(map->map) could/should be called
}
map->valid = false;
}
Expand Down

0 comments on commit cb7f9b4

Please sign in to comment.