www.pudn.com > mitab.rar > mitab_ogr_datasource.cpp


/********************************************************************** 
 * $Id: mitab_ogr_datasource.cpp,v 1.11 2006/01/27 14:27:35 fwarmerdam Exp $ 
 * 
 * Name:     mitab_ogr_datasource.cpp 
 * Project:  MapInfo Mid/Mif, Tab ogr support 
 * Language: C++ 
 * Purpose:  Implementation of OGRTABDataSource. 
 * Author:   Stephane Villeneuve, stephane.v@videotron.ca 
 *           and Frank Warmerdam, warmerdam@pobox.com 
 * 
 ********************************************************************** 
 * Copyright (c) 1999, 2000, Stephane Villeneuve 
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a 
 * copy of this software and associated documentation files (the "Software"), 
 * to deal in the Software without restriction, including without limitation 
 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 
 * and/or sell copies of the Software, and to permit persons to whom the 
 * Software is furnished to do so, subject to the following conditions: 
 *  
 * The above copyright notice and this permission notice shall be included 
 * in all copies or substantial portions of the Software. 
 *  
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL 
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER  
 * DEALINGS IN THE SOFTWARE. 
 ********************************************************************** 
 * 
 * $Log: mitab_ogr_datasource.cpp,v $ 
 * Revision 1.11  2006/01/27 14:27:35  fwarmerdam 
 * fixed ogr bounds setting problems (bug 1198) 
 * 
 * Revision 1.10  2005/09/20 04:40:02  fwarmerdam 
 * fixed CPLReadDir memory leak 
 * 
 * Revision 1.9  2004/10/15 01:52:30  fwarmerdam 
 * Modified CreateLayer() to use  -1000,-1000,1000,1000 bounds for GEOGCS 
 * much like in mitab_bounds.cpp.  This ensures that geographic files in 
 * the range 0-360 works as well as -180 to 180. 
 * 
 * Revision 1.8  2004/07/07 15:42:46  fwarmerdam 
 * fixed up some single layer creation issues 
 * 
 * Revision 1.7  2004/02/27 21:06:03  fwarmerdam 
 * Better support for "single file" creation ... don't allow other layers to 
 * be created.  But *do* single file to satisfy the first layer creation request 
 * made.  Also, allow creating a datasource "on" an existing directory. 
 * 
 * Revision 1.6  2003/03/21 14:20:49  warmerda 
 * fixed email 
 * 
 * Revision 1.5  2002/02/08 16:52:16  warmerda 
 * added support for FORMAT=MIF option for creating layers 
 * 
 * Revision 1.4  2001/02/06 22:13:54  warmerda 
 * fixed memory leak in OGRTABDataSource::CreateLayer() 
 * 
 * Revision 1.3  2001/01/22 16:03:58  warmerda 
 * expanded tabs 
 * 
 * Revision 1.2  2000/07/04 01:46:23  warmerda 
 * Avoid warnings on unused arguments. 
 * 
 * Revision 1.1  2000/01/26 18:17:09  warmerda 
 * New 
 * 
 **********************************************************************/ 
 
#include "mitab_ogr_driver.h" 
 
 
/*======================================================================= 
 *                 OGRTABDataSource 
 * 
 * We need one single OGRDataSource/Driver set of classes to handle all 
 * the MapInfo file types.  They all deal with the IMapInfoFile abstract 
 * class. 
 *=====================================================================*/ 
 
/************************************************************************/ 
/*                         OGRTABDataSource()                           */ 
/************************************************************************/ 
 
OGRTABDataSource::OGRTABDataSource() 
 
{ 
    m_pszName = NULL; 
    m_pszDirectory = NULL; 
    m_nLayerCount = 0; 
    m_papoLayers = NULL; 
    m_papszOptions = NULL; 
    m_bCreateMIF = FALSE; 
    m_bSingleFile = FALSE; 
    m_bSingleLayerAlreadyCreated = FALSE; 
} 
 
/************************************************************************/ 
/*                         ~OGRTABDataSource()                          */ 
/************************************************************************/ 
 
OGRTABDataSource::~OGRTABDataSource() 
 
{ 
    CPLFree( m_pszName );  
    CPLFree( m_pszDirectory ); 
 
    for( int i = 0; i < m_nLayerCount; i++ ) 
        delete m_papoLayers[i]; 
 
    CPLFree( m_papoLayers ); 
    CSLDestroy( m_papszOptions ); 
} 
 
/************************************************************************/ 
/*                               Create()                               */ 
/*                                                                      */ 
/*      Create a new dataset (directory or file).                       */ 
/************************************************************************/ 
 
int OGRTABDataSource::Create( const char * pszName, char **papszOptions ) 
 
{ 
    VSIStatBuf  sStat; 
 
    CPLAssert( m_pszName == NULL ); 
     
    m_pszName = CPLStrdup( pszName ); 
    m_papszOptions = CSLDuplicate( papszOptions ); 
 
    if( CSLFetchNameValue(papszOptions,"FORMAT") != NULL  
        && EQUAL(CSLFetchNameValue(papszOptions,"FORMAT"),"MIF") ) 
        m_bCreateMIF = TRUE; 
    else if( EQUAL(CPLGetExtension(pszName),"mif") 
             || EQUAL(CPLGetExtension(pszName),"mid") ) 
        m_bCreateMIF = TRUE; 
 
/* -------------------------------------------------------------------- */ 
/*      Create a new empty directory.                                   */ 
/* -------------------------------------------------------------------- */ 
    if( strlen(CPLGetExtension(pszName)) == 0 ) 
    { 
        if( VSIStat( pszName, &sStat ) == 0 ) 
        { 
            if( !VSI_ISDIR(sStat.st_mode) ) 
            { 
                CPLError( CE_Failure, CPLE_OpenFailed, 
                          "Attempt to create dataset named %s,\n" 
                          "but that is an existing file.\n", 
                          pszName ); 
                return FALSE; 
            } 
        } 
        else 
        { 
            if( VSIMkdir( pszName, 0755 ) != 0 ) 
            { 
                CPLError( CE_Failure, CPLE_AppDefined, 
                          "Unable to create directory %s.\n", 
                          pszName ); 
                return FALSE; 
            } 
        } 
         
        m_pszDirectory = CPLStrdup(pszName); 
    } 
 
/* -------------------------------------------------------------------- */ 
/*      Create a new single file.                                       */ 
/* -------------------------------------------------------------------- */ 
    else 
    { 
        IMapInfoFile    *poFile; 
 
        if( m_bCreateMIF ) 
            poFile = new MIFFile; 
        else 
            poFile = new TABFile; 
 
        if( poFile->Open( pszName, "wb", FALSE ) != 0 ) 
        { 
            delete poFile; 
            return FALSE; 
        } 
         
        m_nLayerCount = 1; 
        m_papoLayers = (IMapInfoFile **) CPLMalloc(sizeof(void*)); 
        m_papoLayers[0] = poFile; 
         
        m_pszDirectory = CPLStrdup( CPLGetPath(pszName) ); 
        m_bSingleFile = TRUE; 
    } 
 
    return TRUE; 
} 
 
/************************************************************************/ 
/*                                Open()                                */ 
/*                                                                      */ 
/*      Open an existing file, or directory of files.                   */ 
/************************************************************************/ 
 
int OGRTABDataSource::Open( const char * pszName, int bTestOpen ) 
 
{ 
    VSIStatBuf  stat; 
 
    CPLAssert( m_pszName == NULL ); 
     
    m_pszName = CPLStrdup( pszName ); 
 
/* -------------------------------------------------------------------- */ 
/*      Is this a file or directory?                                    */ 
/* -------------------------------------------------------------------- */ 
    if( VSIStat( pszName, &stat ) != 0  
        || (!VSI_ISDIR(stat.st_mode) && !VSI_ISREG(stat.st_mode)) ) 
    { 
        if( !bTestOpen ) 
        { 
            CPLError( CE_Failure, CPLE_OpenFailed, 
                      "%s is not a file or directory.\n" 
                      "Unable to open as a Mapinfo dataset.\n", 
                      pszName ); 
        } 
 
        return FALSE; 
    } 
 
/* -------------------------------------------------------------------- */ 
/*      If it is a file, try to open as a Mapinfo file.                 */ 
/* -------------------------------------------------------------------- */ 
    if( VSI_ISREG(stat.st_mode) ) 
    { 
        IMapInfoFile    *poFile; 
 
        poFile = IMapInfoFile::SmartOpen( pszName, bTestOpen ); 
        if( poFile == NULL ) 
            return FALSE; 
 
        m_nLayerCount = 1; 
        m_papoLayers = (IMapInfoFile **) CPLMalloc(sizeof(void*)); 
        m_papoLayers[0] = poFile; 
 
        m_pszDirectory = CPLStrdup( CPLGetPath(pszName) ); 
    } 
 
/* -------------------------------------------------------------------- */ 
/*      Otherwise, we need to scan the whole directory for files        */ 
/*      ending in .tab or .mif.                                         */ 
/* -------------------------------------------------------------------- */ 
    else 
    { 
        char    **papszFileList = CPLReadDir( pszName ); 
         
        m_pszDirectory = CPLStrdup( pszName ); 
 
        for( int iFile = 0; 
             papszFileList != NULL && papszFileList[iFile] != NULL; 
             iFile++ ) 
        { 
            IMapInfoFile *poFile; 
            const char  *pszExtension = CPLGetExtension(papszFileList[iFile]); 
            char        *pszSubFilename; 
 
            if( !EQUAL(pszExtension,"tab") && !EQUAL(pszExtension,"mif") ) 
                continue; 
 
            pszSubFilename = CPLStrdup( 
                CPLFormFilename( m_pszDirectory, papszFileList[iFile], NULL )); 
 
            poFile = IMapInfoFile::SmartOpen( pszSubFilename, bTestOpen ); 
            CPLFree( pszSubFilename ); 
             
            if( poFile == NULL ) 
            { 
                CSLDestroy( papszFileList ); 
                return FALSE; 
            } 
 
            m_nLayerCount++; 
            m_papoLayers = (IMapInfoFile **) 
                CPLRealloc(m_papoLayers,sizeof(void*)*m_nLayerCount); 
            m_papoLayers[m_nLayerCount-1] = poFile; 
        } 
 
        CSLDestroy( papszFileList ); 
 
        if( m_nLayerCount == 0 ) 
        { 
            if( !bTestOpen ) 
                CPLError( CE_Failure, CPLE_OpenFailed, 
                          "No mapinfo files found in directory %s.\n", 
                          m_pszDirectory ); 
             
            return FALSE; 
        } 
    } 
 
    return TRUE; 
} 
 
/************************************************************************/ 
/*                           GetLayerCount()                            */ 
/************************************************************************/ 
 
int OGRTABDataSource::GetLayerCount() 
 
{ 
    if( m_bSingleFile && !m_bSingleLayerAlreadyCreated ) 
        return 0; 
    else 
        return m_nLayerCount; 
} 
 
/************************************************************************/ 
/*                              GetLayer()                              */ 
/************************************************************************/ 
 
OGRLayer *OGRTABDataSource::GetLayer( int iLayer ) 
 
{ 
    if( iLayer < 0 || iLayer >= GetLayerCount() ) 
        return NULL; 
    else 
        return m_papoLayers[iLayer]; 
} 
 
/************************************************************************/ 
/*                            CreateLayer()                             */ 
/************************************************************************/ 
 
OGRLayer * 
OGRTABDataSource::CreateLayer( const char * pszLayerName, 
                               OGRSpatialReference *poSRSIn, 
                               OGRwkbGeometryType /* eGeomTypeIn */, 
                               char ** /* papszOptions */ ) 
 
{ 
    IMapInfoFile        *poFile; 
    char                *pszFullFilename; 
 
/* -------------------------------------------------------------------- */ 
/*      If it's a single file mode file, then we may have already       */ 
/*      instantiated the low level layer.   We would just need to       */ 
/*      reset the coordinate system and (potentially) bounds.           */ 
/* -------------------------------------------------------------------- */ 
    if( m_bSingleFile ) 
    { 
        if( m_bSingleLayerAlreadyCreated ) 
        { 
            CPLError( CE_Failure, CPLE_AppDefined,  
                      "Unable to create new layers in this single file dataset."); 
            return NULL; 
        } 
 
        m_bSingleLayerAlreadyCreated = TRUE; 
 
        poFile = (IMapInfoFile *) m_papoLayers[0]; 
    } 
 
/* -------------------------------------------------------------------- */ 
/*      We need to initially create the file, and add it as a layer.    */ 
/* -------------------------------------------------------------------- */ 
    else 
    { 
        if( m_bCreateMIF ) 
        { 
            pszFullFilename = CPLStrdup( CPLFormFilename( m_pszDirectory, 
                                                          pszLayerName, "mif" ) ); 
             
            poFile = new MIFFile; 
        } 
        else 
        { 
            pszFullFilename = CPLStrdup( CPLFormFilename( m_pszDirectory, 
                                                          pszLayerName, "tab" ) ); 
             
            poFile = new TABFile; 
        } 
         
        if( poFile->Open( pszFullFilename, "wb", FALSE ) != 0 ) 
        { 
            CPLFree( pszFullFilename ); 
            delete poFile; 
            return FALSE; 
        } 
 
        m_nLayerCount++; 
        m_papoLayers = (IMapInfoFile **) 
            CPLRealloc(m_papoLayers,sizeof(void*)*m_nLayerCount); 
        m_papoLayers[m_nLayerCount-1] = poFile; 
 
        CPLFree( pszFullFilename ); 
    } 
 
/* -------------------------------------------------------------------- */ 
/*      Assign the coordinate system (if provided) and set              */ 
/*      reasonable bounds.                                              */ 
/* -------------------------------------------------------------------- */ 
    if( poSRSIn != NULL ) 
        poFile->SetSpatialRef( poSRSIn ); 
 
    if( !poFile->IsBoundsSet() && !m_bCreateMIF ) 
    { 
        if( poSRSIn != NULL && poSRSIn->GetRoot() != NULL 
            && EQUAL(poSRSIn->GetRoot()->GetValue(),"GEOGCS") ) 
            poFile->SetBounds( -1000, -1000, 1000, 1000 ); 
        else 
            poFile->SetBounds( -30000000, -15000000, 30000000, 15000000 ); 
    } 
 
    return poFile; 
} 
 
/************************************************************************/ 
/*                           TestCapability()                           */ 
/************************************************************************/ 
 
int OGRTABDataSource::TestCapability( const char * pszCap ) 
 
{ 
    if( EQUAL(pszCap,ODsCCreateLayer) ) 
        return !m_bSingleFile || !m_bSingleLayerAlreadyCreated; 
    else 
        return FALSE; 
}