OGRLayer * OGRShapeDataSource::ICreateLayer( const char * pszLayerName, OGRSpatialReference *poSRS, OGRwkbGeometryType eType, char ** papszOptions ) { // To ensure that existing layers are created. GetLayerCount(); /* -------------------------------------------------------------------- */ /* Check that the layer doesn't already exist. */ /* -------------------------------------------------------------------- */ if (GetLayerByName(pszLayerName) != NULL) { CPLError( CE_Failure, CPLE_AppDefined, "Layer '%s' already exists", pszLayerName); return NULL; } /* -------------------------------------------------------------------- */ /* Verify we are in update mode. */ /* -------------------------------------------------------------------- */ if( !bDSUpdate ) { CPLError( CE_Failure, CPLE_NoWriteAccess, "Data source %s opened read-only. " "New layer %s cannot be created.", pszName, pszLayerName ); return NULL; } /* -------------------------------------------------------------------- */ /* Figure out what type of layer we need. */ /* -------------------------------------------------------------------- */ int nShapeType = -1; if( wkbFlatten(eType) == wkbUnknown || eType == wkbLineString ) nShapeType = SHPT_ARC; else if( eType == wkbPoint ) nShapeType = SHPT_POINT; else if( eType == wkbPolygon ) nShapeType = SHPT_POLYGON; else if( eType == wkbMultiPoint ) nShapeType = SHPT_MULTIPOINT; else if( eType == wkbPoint25D ) nShapeType = SHPT_POINTZ; else if( eType == wkbPointM ) nShapeType = SHPT_POINTM; else if( eType == wkbPointZM ) nShapeType = SHPT_POINTZ; else if( eType == wkbLineString25D ) nShapeType = SHPT_ARCZ; else if( eType == wkbLineStringM ) nShapeType = SHPT_ARCM; else if( eType == wkbLineStringZM ) nShapeType = SHPT_ARCZ; else if( eType == wkbMultiLineString ) nShapeType = SHPT_ARC; else if( eType == wkbMultiLineString25D ) nShapeType = SHPT_ARCZ; else if( eType == wkbMultiLineStringM ) nShapeType = SHPT_ARCM; else if( eType == wkbMultiLineStringZM ) nShapeType = SHPT_ARCZ; else if( eType == wkbPolygon25D ) nShapeType = SHPT_POLYGONZ; else if( eType == wkbPolygonM ) nShapeType = SHPT_POLYGONM; else if( eType == wkbPolygonZM ) nShapeType = SHPT_POLYGONZ; else if( eType == wkbMultiPolygon ) nShapeType = SHPT_POLYGON; else if( eType == wkbMultiPolygon25D ) nShapeType = SHPT_POLYGONZ; else if( eType == wkbMultiPolygonM ) nShapeType = SHPT_POLYGONM; else if( eType == wkbMultiPolygonZM ) nShapeType = SHPT_POLYGONZ; else if( eType == wkbMultiPoint25D ) nShapeType = SHPT_MULTIPOINTZ; else if( eType == wkbMultiPointM ) nShapeType = SHPT_MULTIPOINTM; else if( eType == wkbMultiPointZM ) nShapeType = SHPT_MULTIPOINTZ; else if( eType == wkbNone ) nShapeType = SHPT_NULL; /* -------------------------------------------------------------------- */ /* Has the application overridden this with a special creation */ /* option? */ /* -------------------------------------------------------------------- */ const char *pszOverride = CSLFetchNameValue( papszOptions, "SHPT" ); if( pszOverride == NULL ) { /* ignore */; } else if( EQUAL(pszOverride,"POINT") ) { nShapeType = SHPT_POINT; eType = wkbPoint; } else if( EQUAL(pszOverride,"ARC") ) { nShapeType = SHPT_ARC; eType = wkbLineString; } else if( EQUAL(pszOverride,"POLYGON") ) { nShapeType = SHPT_POLYGON; eType = wkbPolygon; } else if( EQUAL(pszOverride,"MULTIPOINT") ) { nShapeType = SHPT_MULTIPOINT; eType = wkbMultiPoint; } else if( EQUAL(pszOverride,"POINTZ") ) { nShapeType = SHPT_POINTZ; eType = wkbPoint25D; } else if( EQUAL(pszOverride,"ARCZ") ) { nShapeType = SHPT_ARCZ; eType = wkbLineString25D; } else if( EQUAL(pszOverride,"POLYGONZ") ) { nShapeType = SHPT_POLYGONZ; eType = wkbPolygon25D; } else if( EQUAL(pszOverride,"MULTIPOINTZ") ) { nShapeType = SHPT_MULTIPOINTZ; eType = wkbMultiPoint25D; } else if( EQUAL(pszOverride,"POINTM") ) { nShapeType = SHPT_POINTM; eType = wkbPointM; } else if( EQUAL(pszOverride,"ARCM") ) { nShapeType = SHPT_ARCM; eType = wkbLineStringM; } else if( EQUAL(pszOverride,"POLYGONM") ) { nShapeType = SHPT_POLYGONM; eType = wkbPolygonM; } else if( EQUAL(pszOverride,"MULTIPOINTM") ) { nShapeType = SHPT_MULTIPOINTM; eType = wkbMultiPointM; } else if( EQUAL(pszOverride,"POINTZM") ) { nShapeType = SHPT_POINTZ; eType = wkbPointZM; } else if( EQUAL(pszOverride,"ARCZM") ) { nShapeType = SHPT_ARCZ; eType = wkbLineStringZM; } else if( EQUAL(pszOverride,"POLYGONZM") ) { nShapeType = SHPT_POLYGONZ; eType = wkbPolygonZM; } else if( EQUAL(pszOverride,"MULTIPOINTZM") ) { nShapeType = SHPT_MULTIPOINTZ; eType = wkbMultiPointZM; } else if( EQUAL(pszOverride,"NONE") || EQUAL(pszOverride,"NULL") ) { nShapeType = SHPT_NULL; eType = wkbNone; } else { CPLError( CE_Failure, CPLE_NotSupported, "Unknown SHPT value of `%s' passed to Shapefile layer" "creation. Creation aborted.", pszOverride ); return NULL; } if( nShapeType == -1 ) { CPLError( CE_Failure, CPLE_NotSupported, "Geometry type of `%s' not supported in shapefiles. " "Type can be overridden with a layer creation option " "of SHPT=POINT/ARC/POLYGON/MULTIPOINT/POINTZ/ARCZ/POLYGONZ/" "MULTIPOINTZ.", OGRGeometryTypeToName(eType) ); return NULL; } /* -------------------------------------------------------------------- */ /* What filename do we use, excluding the extension? */ /* -------------------------------------------------------------------- */ char *pszFilenameWithoutExt = NULL; if( bSingleFileDataSource && nLayers == 0 ) { char *pszPath = CPLStrdup(CPLGetPath(pszName)); char *pszFBasename = CPLStrdup(CPLGetBasename(pszName)); pszFilenameWithoutExt = CPLStrdup(CPLFormFilename(pszPath, pszFBasename, NULL)); CPLFree( pszFBasename ); CPLFree( pszPath ); } else if( bSingleFileDataSource ) { // This is a very weird use case : the user creates/open a datasource // made of a single shapefile 'foo.shp' and wants to add a new layer // to it, 'bar'. So we create a new shapefile 'bar.shp' in the same // directory as 'foo.shp' // So technically, we will not be any longer a single file // datasource ... Ahem ahem. char *pszPath = CPLStrdup(CPLGetPath(pszName)); pszFilenameWithoutExt = CPLStrdup(CPLFormFilename(pszPath, pszLayerName, NULL)); CPLFree( pszPath ); } else { pszFilenameWithoutExt = CPLStrdup(CPLFormFilename(pszName, pszLayerName, NULL)); } /* -------------------------------------------------------------------- */ /* Create the shapefile. */ /* -------------------------------------------------------------------- */ const bool l_b2GBLimit = CPLTestBool(CSLFetchNameValueDef( papszOptions, "2GB_LIMIT", "FALSE" )); SHPHandle hSHP = NULL; if( nShapeType != SHPT_NULL ) { char *pszFilename = CPLStrdup(CPLFormFilename( NULL, pszFilenameWithoutExt, "shp" )); hSHP = SHPCreateLL( pszFilename, nShapeType, const_cast<SAHooks *>(VSI_SHP_GetHook(l_b2GBLimit)) ); if( hSHP == NULL ) { CPLError( CE_Failure, CPLE_OpenFailed, "Failed to open Shapefile `%s'.", pszFilename ); CPLFree( pszFilename ); CPLFree( pszFilenameWithoutExt ); return NULL; } SHPSetFastModeReadObject( hSHP, TRUE ); CPLFree( pszFilename ); } /* -------------------------------------------------------------------- */ /* Has a specific LDID been specified by the caller? */ /* -------------------------------------------------------------------- */ const char *pszLDID = CSLFetchNameValue( papszOptions, "ENCODING" ); /* -------------------------------------------------------------------- */ /* Create a DBF file. */ /* -------------------------------------------------------------------- */ char *pszFilename = CPLStrdup(CPLFormFilename( NULL, pszFilenameWithoutExt, "dbf" )); DBFHandle hDBF = DBFCreateLL( pszFilename, (pszLDID != NULL) ? pszLDID : "LDID/87", const_cast<SAHooks *>(VSI_SHP_GetHook(b2GBLimit)) ); if( hDBF == NULL ) { CPLError( CE_Failure, CPLE_OpenFailed, "Failed to open Shape DBF file `%s'.", pszFilename ); CPLFree( pszFilename ); CPLFree( pszFilenameWithoutExt ); SHPClose(hSHP); return NULL; } CPLFree( pszFilename ); /* -------------------------------------------------------------------- */ /* Create the .prj file, if required. */ /* -------------------------------------------------------------------- */ if( poSRS != NULL ) { CPLString osPrjFile = CPLFormFilename( NULL, pszFilenameWithoutExt, "prj"); // The shape layer needs its own copy. poSRS = poSRS->Clone(); poSRS->morphToESRI(); char *pszWKT = NULL; VSILFILE *fp = NULL; if( poSRS->exportToWkt( &pszWKT ) == OGRERR_NONE && (fp = VSIFOpenL( osPrjFile, "wt" )) != NULL ) { VSIFWriteL( pszWKT, strlen(pszWKT), 1, fp ); VSIFCloseL( fp ); } CPLFree( pszWKT ); poSRS->morphFromESRI(); } /* -------------------------------------------------------------------- */ /* Create the layer object. */ /* -------------------------------------------------------------------- */ // OGRShapeLayer constructor expects a filename with an extension (that // could be random actually), otherwise this is going to cause problems with // layer names that have a dot (not speaking about the one before the shp) pszFilename = CPLStrdup(CPLFormFilename( NULL, pszFilenameWithoutExt, "shp" )); OGRShapeLayer *poLayer = new OGRShapeLayer( this, pszFilename, hSHP, hDBF, poSRS, true, true, eType ); CPLFree( pszFilenameWithoutExt ); CPLFree( pszFilename ); poLayer->SetResizeAtClose( CPLFetchBool( papszOptions, "RESIZE", false ) ); poLayer->CreateSpatialIndexAtClose( CPLFetchBool( papszOptions, "SPATIAL_INDEX", false ) ); poLayer->SetModificationDate( CSLFetchNameValue( papszOptions, "DBF_DATE_LAST_UPDATE" ) ); poLayer->SetAutoRepack( CPLFetchBool( papszOptions, "AUTO_REPACK", true ) ); /* -------------------------------------------------------------------- */ /* Add layer to data source layer list. */ /* -------------------------------------------------------------------- */ AddLayer(poLayer); return poLayer; }
bool OGRShapeDataSource::OpenFile( const char *pszNewName, bool bUpdate ) { const char *pszExtension = CPLGetExtension( pszNewName ); if( !EQUAL(pszExtension,"shp") && !EQUAL(pszExtension,"shx") && !EQUAL(pszExtension,"dbf") ) return false; /* -------------------------------------------------------------------- */ /* SHPOpen() should include better (CPL based) error reporting, */ /* and we should be trying to distinguish at this point whether */ /* failure is a result of trying to open a non-shapefile, or */ /* whether it was a shapefile and we want to report the error */ /* up. */ /* */ /* Care is taken to suppress the error and only reissue it if */ /* we think it is appropriate. */ /* -------------------------------------------------------------------- */ CPLPushErrorHandler( CPLQuietErrorHandler ); SHPHandle hSHP = bUpdate ? DS_SHPOpen( pszNewName, "r+" ) : DS_SHPOpen( pszNewName, "r" ); CPLPopErrorHandler(); if( hSHP == NULL && (!EQUAL(CPLGetExtension(pszNewName),"dbf") || strstr(CPLGetLastErrorMsg(),".shp") == NULL) ) { CPLString osMsg = CPLGetLastErrorMsg(); CPLError( CE_Failure, CPLE_OpenFailed, "%s", osMsg.c_str() ); return false; } CPLErrorReset(); /* -------------------------------------------------------------------- */ /* Open the .dbf file, if it exists. To open a dbf file, the */ /* filename has to either refer to a successfully opened shp */ /* file or has to refer to the actual .dbf file. */ /* -------------------------------------------------------------------- */ DBFHandle hDBF = NULL; if( hSHP != NULL || EQUAL(CPLGetExtension(pszNewName), "dbf") ) { if( bUpdate ) { hDBF = DS_DBFOpen( pszNewName, "r+" ); if( hSHP != NULL && hDBF == NULL ) { for( int i = 0; i < 2; i++ ) { VSIStatBufL sStat; const char* pszDBFName = CPLResetExtension(pszNewName, (i == 0 ) ? "dbf" : "DBF"); VSILFILE* fp = NULL; if( VSIStatExL( pszDBFName, &sStat, VSI_STAT_EXISTS_FLAG) == 0 ) { fp = VSIFOpenL(pszDBFName, "r+"); if( fp == NULL ) { CPLError( CE_Failure, CPLE_OpenFailed, "%s exists, " "but cannot be opened in update mode", pszDBFName ); SHPClose(hSHP); return false; } VSIFCloseL(fp); break; } } } } else { hDBF = DS_DBFOpen( pszNewName, "r" ); } } else { hDBF = NULL; } if( hDBF == NULL && hSHP == NULL ) return false; /* -------------------------------------------------------------------- */ /* Create the layer object. */ /* -------------------------------------------------------------------- */ OGRShapeLayer *poLayer = new OGRShapeLayer( this, pszNewName, hSHP, hDBF, NULL, false, bUpdate, wkbNone ); poLayer->SetModificationDate( CSLFetchNameValue( papszOpenOptions, "DBF_DATE_LAST_UPDATE" ) ); poLayer->SetAutoRepack( CPLFetchBool( papszOpenOptions, "AUTO_REPACK", true ) ); /* -------------------------------------------------------------------- */ /* Add layer to data source layer list. */ /* -------------------------------------------------------------------- */ AddLayer(poLayer); return true; }