Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
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;
}