Ticket #1735: gdal_svn_bna.patch

File gdal_svn_bna.patch, 63.9 kB (added by rouault, 11 months ago)
  • ogr/ogrsf_frmts/ogr_formats.html

    old new  
    2020</td><td> Yes 
    2121</td></tr> 
    2222 
     23<tr><td> <a href="drv_bna.html">Atlas BNA</a> 
     24</td><td> Yes 
     25</td><td> No 
     26</td></tr> 
     27 
    2328<tr><td> <a href="drv_csv.html">Comma Separated Value (.csv)</a> 
    2429</td><td> Yes 
    2530</td><td> No 
  • ogr/ogrsf_frmts/bna/makefile.vc

    old new  
    22OBJ     =       ogrbnadriver.obj ogrbnadatasource.obj ogrbnalayer.obj \ 
    33                ogrbnaparser.obj 
    44 
    5 EXTRAFLAGS =    -I.. -I..\.. 
     5EXTRAFLAGS =    -I.. -I..\.. $(GEOS_CFLAGS) 
    66 
    77GDAL_ROOT       =       ..\..\.. 
    88 
  • ogr/ogrsf_frmts/bna/ogrbnadatasource.cpp

    old new  
    4242{ 
    4343    papoLayers = NULL; 
    4444    nLayers = 0; 
     45     
     46    fpOutput = NULL; 
    4547 
    4648    pszName = NULL; 
     49     
     50    pszCoordinateSeparator = NULL; 
    4751 
    4852    bUpdate = FALSE; 
    4953} 
     
    5559OGRBNADataSource::~OGRBNADataSource() 
    5660 
    5761{ 
     62    if ( fpOutput != NULL ) 
     63    { 
     64        VSIFClose( fpOutput); 
     65    } 
     66 
    5867    for( int i = 0; i < nLayers; i++ ) 
    5968        delete papoLayers[i]; 
    6069    CPLFree( papoLayers ); 
     70     
     71    CPLFree( pszCoordinateSeparator ); 
    6172 
    6273    CPLFree( pszName ); 
    6374} 
     
    7081 
    7182{ 
    7283    if( EQUAL(pszCap,ODsCCreateLayer) ) 
    73         return FALSE; 
     84        return TRUE; 
    7485    else if( EQUAL(pszCap,ODsCDeleteLayer) ) 
    7586        return FALSE; 
    7687    else 
     
    91102} 
    92103 
    93104/************************************************************************/ 
     105/*                            CreateLayer()                             */ 
     106/************************************************************************/ 
     107 
     108OGRLayer * OGRBNADataSource::CreateLayer( const char * pszLayerName, 
     109                                          OGRSpatialReference *poSRS, 
     110                                          OGRwkbGeometryType eType, 
     111                                          char ** papszOptions ) 
     112 
     113{ 
     114    BNAFeatureType bnaFeatureType; 
     115     
     116    switch(eType) 
     117    { 
     118        case wkbPolygon: 
     119        case wkbPolygon25D: 
     120        case wkbMultiPolygon: 
     121        case wkbMultiPolygon25D: 
     122            bnaFeatureType = BNA_POLYGON; 
     123            break; 
     124         
     125        case wkbPoint: 
     126        case wkbPoint25D: 
     127            bnaFeatureType = BNA_POINT; 
     128            break; 
     129             
     130        case wkbLineString: 
     131        case wkbLineString25D: 
     132            bnaFeatureType = BNA_POLYLINE; 
     133            break; 
     134             
     135        default: 
     136            CPLError( CE_Failure, CPLE_NotSupported, 
     137                    "Geometry type of `%s' not supported in BNAs.\n", 
     138                    OGRGeometryTypeToName(eType) ); 
     139            return NULL; 
     140    } 
     141     
     142    nLayers++; 
     143    papoLayers = (OGRBNALayer **) CPLRealloc(papoLayers, nLayers * sizeof(OGRBNALayer*)); 
     144    papoLayers[nLayers-1] = new OGRBNALayer( pszName, pszLayerName, bnaFeatureType, eType, TRUE, this ); 
     145     
     146    return papoLayers[nLayers-1]; 
     147} 
     148 
     149/************************************************************************/ 
    94150/*                                Open()                                */ 
    95151/************************************************************************/ 
    96152 
     
    115171// -------------------------------------------------------------------- 
    116172    if( !EQUAL( CPLGetExtension(pszFilename), "bna" ) ) 
    117173        return FALSE; 
    118  
    119     FILE* f = VSIFOpen(pszFilename, "rb"); 
    120     if (f
     174     
     175    FILE* fp = VSIFOpen(pszFilename, "r"); 
     176    if (fp
    121177    { 
    122178        BNARecord* record; 
    123179        int curLine = 0; 
    124         record = BNA_GetNextRecord(f, &ok, &curLine, 0, BNA_READ_NONE); 
     180        const char* layerRadixName[] = { "points", "polygons", "lines", "ellipses"}; 
     181        OGRwkbGeometryType wkbGeomTypes[] = { wkbPoint, wkbMultiPolygon, wkbLineString, wkbPolygon }; 
     182        int i; 
     183#if defined(BNA_FAST_DS_OPEN) 
     184        record = BNA_GetNextRecord(fp, &ok, &curLine, FALSE, BNA_READ_NONE); 
    125185        BNA_FreeRecord(record); 
    126186 
    127187        if (ok) 
     
    129189            nLayers = 4; 
    130190 
    131191            papoLayers = (OGRBNALayer **) CPLMalloc(nLayers * sizeof(OGRBNALayer*)); 
    132             papoLayers[0] = new OGRBNALayer( pszFilename, "points", BNA_POINT, wkbPoint ); 
    133             papoLayers[1] = new OGRBNALayer( pszFilename, "lines", BNA_POLYLINE, wkbLineString ); 
    134             papoLayers[2] = new OGRBNALayer( pszFilename, "polygons", BNA_POLYGON, wkbMultiPolygon ); 
    135             papoLayers[3] = new OGRBNALayer( pszFilename, "ellipses", BNA_ELLIPSE, wkbPolygon ); 
     192            for(i=0;i<4;i++) 
     193                papoLayers[i] = new OGRBNALayer( pszFilename, 
     194                                                 layerRadixName[i], 
     195                                                 (BNAFeatureType)i, wkbGeomTypes[i], FALSE, this ); 
    136196        } 
     197#else 
     198        int nFeatures[4] = { 0, 0, 0, 0 }; 
     199        OffsetAndLine* offsetAndLineFeaturesTable[4] = { NULL, NULL, NULL, NULL }; 
     200        int nIDs[4] = {0, 0, 0, 0}; 
     201        int partialIndexTable = TRUE; 
    137202 
    138         VSIFClose(f); 
     203        while(1) 
     204        { 
     205            int offset = VSIFTell(fp); 
     206            int line = curLine; 
     207            record =  BNA_GetNextRecord(fp, &ok, &curLine, FALSE, BNA_READ_NONE); 
     208            if (ok == FALSE) 
     209            { 
     210                BNA_FreeRecord(record); 
     211                if (line != 0) 
     212                    ok = TRUE; 
     213                break; 
     214            } 
     215            if (record == NULL) 
     216            { 
     217                /* end of file */ 
     218                ok = TRUE; 
     219 
     220                /* and we have finally build the whole index table */ 
     221                partialIndexTable = FALSE; 
     222                break; 
     223            } 
     224 
     225            if (record->nIDs > nIDs[record->featureType]) 
     226                nIDs[record->featureType] = record->nIDs; 
     227 
     228            nFeatures[record->featureType]++; 
     229            offsetAndLineFeaturesTable[record->featureType] = 
     230                (OffsetAndLine*)CPLRealloc(offsetAndLineFeaturesTable[record->featureType], 
     231                                           nFeatures[record->featureType] * sizeof(OffsetAndLine)); 
     232            offsetAndLineFeaturesTable[record->featureType][nFeatures[record->featureType]-1].offset = offset; 
     233            offsetAndLineFeaturesTable[record->featureType][nFeatures[record->featureType]-1].line = line; 
     234 
     235            BNA_FreeRecord(record); 
     236        } 
     237 
     238        nLayers = (nFeatures[0] != 0) + (nFeatures[1] != 0) + (nFeatures[2] != 0) + (nFeatures[3] != 0); 
     239        papoLayers = (OGRBNALayer **) CPLMalloc(nLayers * sizeof(OGRBNALayer*)); 
     240        int iLayer = 0; 
     241        for(i=0;i<4;i++) 
     242        { 
     243            if (nFeatures[i]) 
     244            { 
     245                papoLayers[iLayer] = new OGRBNALayer( pszFilename, 
     246                                                      layerRadixName[i], 
     247                                                      (BNAFeatureType)i, 
     248                                                      wkbGeomTypes[i], 
     249                                                      FALSE, 
     250                                                      this, 
     251                                                      nIDs[i]); 
     252                papoLayers[iLayer]->SetFeatureIndexTable(nFeatures[i], 
     253                                                        offsetAndLineFeaturesTable[i], 
     254                                                        partialIndexTable); 
     255                iLayer++; 
     256            } 
     257        } 
     258#endif 
     259        VSIFClose(fp); 
    139260    } 
    140261 
    141262    return ok; 
    142263} 
    143264 
     265 
     266/************************************************************************/ 
     267/*                               Create()                               */ 
     268/************************************************************************/ 
     269 
     270int OGRBNADataSource::Create( const char *pszFilename,  
     271                              char **papszOptions ) 
     272{ 
     273    if( fpOutput != NULL) 
     274    { 
     275        CPLAssert( FALSE ); 
     276        return FALSE; 
     277    } 
     278 
     279/* -------------------------------------------------------------------- */ 
     280/*     Do not override exiting file.                                    */ 
     281/* -------------------------------------------------------------------- */ 
     282    VSIStatBufL sStatBuf; 
     283 
     284    if( VSIStatL( pszFilename, &sStatBuf ) == 0 ) 
     285        return FALSE; 
     286     
     287/* -------------------------------------------------------------------- */ 
     288/*      Create the output file.                                         */ 
     289/* -------------------------------------------------------------------- */ 
     290    pszName = CPLStrdup( pszFilename ); 
     291 
     292    if( EQUAL(pszFilename,"stdout") ) 
     293        fpOutput = stdout; 
     294    else 
     295        fpOutput = VSIFOpen( pszFilename, "w" ); 
     296    if( fpOutput == NULL ) 
     297    { 
     298        CPLError( CE_Failure, CPLE_OpenFailed,  
     299                  "Failed to create BNA file %s.",  
     300                  pszFilename ); 
     301        return FALSE; 
     302    } 
     303     
     304    /* EOL token */ 
     305    const char *pszCRLFFormat = CSLFetchNameValue( papszOptions, "LINEFORMAT"); 
     306 
     307    if( pszCRLFFormat == NULL ) 
     308    { 
     309#ifdef WIN32 
     310        bUseCRLF = TRUE; 
     311#else 
     312        bUseCRLF = FALSE; 
     313#endif 
     314    } 
     315    else if( EQUAL(pszCRLFFormat,"CRLF") ) 
     316        bUseCRLF = TRUE; 
     317    else if( EQUAL(pszCRLFFormat,"LF") ) 
     318        bUseCRLF = FALSE; 
     319    else 
     320    { 
     321        CPLError( CE_Warning, CPLE_AppDefined,  
     322                  "LINEFORMAT=%s not understood, use one of CRLF or LF.", 
     323                  pszCRLFFormat ); 
     324#ifdef WIN32 
     325        bUseCRLF = TRUE; 
     326#else 
     327        bUseCRLF = FALSE; 
     328#endif 
     329    } 
     330 
     331    /* Multi line or single line format ? */ 
     332    bMultiLine = CSLFetchBoolean( papszOptions, "MULTILINE", TRUE); 
     333     
     334    /* Number of identifiers per record */ 
     335    const char* pszNbOutID = CSLFetchNameValue ( papszOptions, "NB_IDS"); 
     336    if (pszNbOutID == NULL) 
     337    { 
     338        nbOutID = NB_MIN_BNA_IDS; 
     339    } 
     340    else if (EQUAL(pszNbOutID, "NB_SOURCE_FIELDS")) 
     341    { 
     342        nbOutID = -1; 
     343    } 
     344    else 
     345    { 
     346        nbOutID = atoi(pszNbOutID); 
     347        if (nbOutID <= 0) 
     348        { 
     349            CPLError( CE_Warning, CPLE_AppDefined,  
     350                  "NB_ID=%s not understood. Must be >=%d and <=%d or equal to NB_SOURCE_FIELDS", 
     351                  pszNbOutID, NB_MIN_BNA_IDS, NB_MAX_BNA_IDS ); 
     352            nbOutID = NB_MIN_BNA_IDS; 
     353        } 
     354        if (nbOutID > NB_MAX_BNA_IDS) 
     355        { 
     356            CPLError( CE_Warning, CPLE_AppDefined,  
     357                  "NB_ID=%s not understood. Must be >=%d and <=%d or equal to NB_SOURCE_FIELDS", 
     358                  pszNbOutID, NB_MIN_BNA_IDS, NB_MAX_BNA_IDS ); 
     359            nbOutID = NB_MAX_BNA_IDS; 
     360        } 
     361    } 
     362     
     363    /* Ellipses export as ellipses or polygons ? */ 
     364    bEllipsesAsEllipses = CSLFetchBoolean( papszOptions, "ELLIPSES_AS_ELLIPSES", TRUE); 
     365     
     366    /* Number of coordinate pairs per line */ 
     367    const char* pszNbPairPerLine = CSLFetchNameValue( papszOptions, "NB_PAIRS_PER_LINE"); 
     368    if (pszNbPairPerLine) 
     369    { 
     370        nbPairPerLine = atoi(pszNbPairPerLine); 
     371        if (nbPairPerLine <= 0) 
     372            nbPairPerLine = (bMultiLine == FALSE) ? 1000000000 : 1; 
     373        if (bMultiLine == FALSE) 
     374        { 
     375            CPLError( CE_Warning, CPLE_AppDefined, "NB_PAIR_PER_LINE option is ignored when MULTILINE=NO"); 
     376        } 
     377    } 
     378    else 
     379    { 
     380        nbPairPerLine = (bMultiLine == FALSE) ? 1000000000 : 1; 
     381    } 
     382     
     383    /* Coordinate precision */ 
     384    const char* pszCoordinatePrecision = CSLFetchNameValue( papszOptions, "COORDINATE_PRECISION"); 
     385    if (pszCoordinatePrecision) 
     386    { 
     387        coordinatePrecision = atoi(pszCoordinatePrecision); 
     388        if (coordinatePrecision <= 0) 
     389            coordinatePrecision = 0; 
     390        else if (coordinatePrecision >= 20) 
     391            coordinatePrecision = 20; 
     392    } 
     393    else 
     394    { 
     395        coordinatePrecision = 10; 
     396    } 
     397     
     398    pszCoordinateSeparator = (char*)CSLFetchNameValue( papszOptions, "COORDINATE_SEPARATOR"); 
     399    if (pszCoordinateSeparator == NULL) 
     400        pszCoordinateSeparator = CPLStrdup(","); 
     401    else 
     402        pszCoordinateSeparator = CPLStrdup(pszCoordinateSeparator); 
     403 
     404    return TRUE; 
     405} 
  • ogr/ogrsf_frmts/bna/ogrbnadriver.cpp

    old new  
    6868} 
    6969 
    7070/************************************************************************/ 
     71/*                          CreateDataSource()                          */ 
     72/************************************************************************/ 
     73 
     74OGRDataSource *OGRBNADriver::CreateDataSource( const char * pszName, 
     75                                                 char **papszOptions ) 
     76 
     77{ 
     78    OGRBNADataSource   *poDS = new OGRBNADataSource(); 
     79 
     80    if( !poDS->Create( pszName, papszOptions ) ) 
     81    { 
     82        delete poDS; 
     83        poDS = NULL; 
     84    } 
     85 
     86    return poDS; 
     87} 
     88 
     89/************************************************************************/ 
     90/*                          DeleteDataSource()                          */ 
     91/************************************************************************/ 
     92 
     93OGRErr OGRBNADriver::DeleteDataSource( const char *pszFilename ) 
     94 
     95{ 
     96    if( VSIUnlink( pszFilename ) == 0 ) 
     97        return OGRERR_NONE; 
     98    else 
     99        return OGRERR_FAILURE; 
     100} 
     101 
     102/************************************************************************/ 
    71103/*                           TestCapability()                           */ 
    72104/************************************************************************/ 
    73105 
     
    75107 
    76108{ 
    77109    if( EQUAL(pszCap,ODrCCreateDataSource) ) 
    78         return FALSE; 
     110        return TRUE; 
    79111    else if( EQUAL(pszCap,ODrCDeleteDataSource) ) 
    80         return FALSE; 
     112        return TRUE; 
    81113    else 
    82114        return FALSE; 
    83115} 
  • ogr/ogrsf_frmts/bna/ogrbnalayer.cpp

    old new  
    11/****************************************************************************** 
    2  * $Id: ogrbnalayer.cpp 10646 2007-01-18 02:38:10Z warmerdam $ 
     2 * $Id: ogrbnalayer.cpp 
    33 * 
    44 * Project:  BNA Translator 
    55 * Purpose:  Implements OGRBNALayer class. 
     
    4646OGRBNALayer::OGRBNALayer( const char *pszFilename, 
    4747                          const char* layerName, 
    4848                          BNAFeatureType bnaFeatureType, 
    49                           OGRwkbGeometryType eLayerGeomType ) 
     49                          OGRwkbGeometryType eLayerGeomType, 
     50                          int bWriter, 
     51                          OGRBNADataSource* poDS, 
     52                          int nIDs) 
    5053 
    5154{ 
    5255    eof = FALSE; 
    5356    failed = FALSE; 
    5457    curLine = 0; 
    5558    nNextFID = 0; 
     59     
     60    this->bWriter = bWriter; 
     61    this->poDS = poDS; 
     62    this->nIDs = nIDs; 
    5663 
    5764    nFeatures = 0; 
    5865    partialIndexTable = TRUE; 
     
    6875    poFeatureDefn->SetGeomType( eLayerGeomType ); 
    6976    this->bnaFeatureType = bnaFeatureType; 
    7077 
    71     int i; 
    72     for(i=0;i<NB_MAX_BNA_IDS;i++) 
     78    if (! bWriter ) 
    7379    { 
    74         if (i < (int) (sizeof(iKnowHowToCount)/sizeof(iKnowHowToCount[0])) ) 
     80        int i; 
     81        for(i=0;i<nIDs;i++) 
    7582        { 
    76             sprintf(tmp, "%s ID", iKnowHowToCount[i]); 
    77             OGRFieldDefn oFieldID(tmp, OFTString ); 
    78             poFeatureDefn->AddFieldDefn( &oFieldID ); 
     83            if (i < (int) (sizeof(iKnowHowToCount)/sizeof(iKnowHowToCount[0])) ) 
     84            { 
     85                sprintf(tmp, "%s ID", iKnowHowToCount[i]); 
     86                OGRFieldDefn oFieldID(tmp, OFTString ); 
     87                poFeatureDefn->AddFieldDefn( &oFieldID ); 
     88            } 
     89            else 
     90            { 
     91                sprintf(tmp, "%dth ID", i+1); 
     92                OGRFieldDefn oFieldID(tmp, OFTString ); 
     93                poFeatureDefn->AddFieldDefn( &oFieldID ); 
     94            } 
    7995        } 
    80         else 
     96 
     97        if (bnaFeatureType == BNA_ELLIPSE) 
    8198        { 
    82             sprintf(tmp, "%dth ID", i+1); 
    83             OGRFieldDefn oFieldID(tmp, OFTString ); 
    84             poFeatureDefn->AddFieldDefn( &oFieldID ); 
     99            OGRFieldDefn oFieldMajorRadius( "Major radius", OFTReal ); 
     100            poFeatureDefn->AddFieldDefn( &oFieldMajorRadius ); 
     101 
     102            OGRFieldDefn oFieldMinorRadius( "Minor radius", OFTReal ); 
     103            poFeatureDefn->AddFieldDefn( &oFieldMinorRadius ); 
    85104        } 
     105 
     106        fpBNA = VSIFOpen( pszFilename, "r" ); 
     107        if( fpBNA == NULL ) 
     108            return; 
    86109    } 
    87      
    88     if (bnaFeatureType == BNA_ELLIPSE) 
     110    else 
    89111    { 
    90         OGRFieldDefn oFieldMajorRadius( "Major radius", OFTReal ); 
    91         poFeatureDefn->AddFieldDefn( &oFieldMajorRadius ); 
    92        
    93         OGRFieldDefn oFieldMinorRadius( "Minor radius", OFTReal ); 
    94         poFeatureDefn->AddFieldDefn( &oFieldMinorRadius ); 
     112        fpBNA = NULL; 
    95113    } 
    96  
    97     fpBNA = VSIFOpen( pszFilename, "rb" ); 
    98     if( fpBNA == NULL ) 
    99         return; 
    100114} 
    101115 
    102116/************************************************************************/ 
     
    115129} 
    116130 
    117131/************************************************************************/ 
     132/*                         SetFeatureIndexTable()                       */ 
     133/************************************************************************/ 
     134void  OGRBNALayer::SetFeatureIndexTable(int nFeatures, OffsetAndLine* offsetAndLineFeaturesTable, int partialIndexTable) 
     135{ 
     136    this->nFeatures = nFeatures; 
     137    this->offsetAndLineFeaturesTable = offsetAndLineFeaturesTable; 
     138    this->partialIndexTable = partialIndexTable; 
     139} 
     140 
     141/************************************************************************/ 
    118142/*                            ResetReading()                            */ 
    119143/************************************************************************/ 
    120144 
     
    154178        record =  BNA_GetNextRecord(fpBNA, &ok, &curLine, TRUE, bnaFeatureType); 
    155179        if (ok == FALSE) 
    156180        { 
     181            BNA_FreeRecord(record); 
    157182            failed = TRUE; 
    158183            return NULL; 
    159184        } 
     
    161186        { 
    162187            /* end of file */ 
    163188            eof = TRUE; 
    164          
     189 
    165190            /* and we have finally build the whole index table */ 
    166191            partialIndexTable = FALSE; 
    167192            return NULL; 
     
    169194 
    170195        if (record->featureType == bnaFeatureType) 
    171196        { 
    172             break; 
     197            if (nNextFID >= nFeatures) 
     198            { 
     199                nFeatures++; 
     200                offsetAndLineFeaturesTable = 
     201                    (OffsetAndLine*)CPLRealloc(offsetAndLineFeaturesTable, nFeatures * sizeof(OffsetAndLine)); 
     202                offsetAndLineFeaturesTable[nFeatures-1].offset = offset; 
     203                offsetAndLineFeaturesTable[nFeatures-1].line = line; 
     204            } 
     205 
     206            poFeature = BuildFeatureFromBNARecord(record, nNextFID++); 
     207 
     208            BNA_FreeRecord(record); 
     209 
     210            if(   (m_poFilterGeom == NULL 
     211                || FilterGeometry( poFeature->GetGeometryRef() ) ) 
     212            && (m_poAttrQuery == NULL 
     213                || m_poAttrQuery->Evaluate( poFeature )) ) 
     214            { 
     215                 return poFeature; 
     216            } 
     217 
     218            delete poFeature; 
    173219        } 
    174220        else 
    175221        { 
    176222            BNA_FreeRecord(record); 
    177223        } 
    178224    } 
     225} 
     226 
     227 
     228void OGRBNALayer::WriteFeatureAttributes(FILE* fp, OGRFeature *poFeature ) 
     229{ 
     230    int i; 
     231    OGRFieldDefn *poField; 
     232    int nbOutID = poDS->GetNbOutId(); 
     233    if (nbOutID < 0) 
     234        nbOutID = poFeatureDefn->GetFieldCount(); 
     235    for(i=0;i<nbOutID;i++) 
     236    {  
     237        if (i < poFeatureDefn->GetFieldCount()) 
     238        { 
     239            poField = poFeatureDefn->GetFieldDefn( i ); 
     240            if( poFeature->IsFieldSet( i ) ) 
     241            { 
     242                const char *pszRaw = poFeature->GetFieldAsString( i ); 
     243                VSIFPrintf( fp, "\"%s\",", pszRaw); 
     244            } 
     245            else 
     246            { 
     247                VSIFPrintf( fp, "\"\","); 
     248            } 
     249        } 
     250        else 
     251        { 
     252            VSIFPrintf( fp, "\"\","); 
     253        } 
     254    } 
     255} 
     256 
     257/************************************************************************/ 
     258/*                           CreateFeature()                            */ 
     259/************************************************************************/ 
     260 
     261OGRErr OGRBNALayer::CreateFeature( OGRFeature *poFeature ) 
     262 
     263{ 
     264    int i,j,k,n; 
     265    OGRGeometry     *poGeom = poFeature->GetGeometryRef(); 
     266    char eol[3]; 
     267    const char* partialEol = (poDS->GetMultiLine()) ? eol : poDS->GetCoordinateSeparator(); 
    179268     
    180     if (nNextFID >= nFeatures
     269    if (poDS->GetUseCRLF()
    181270    { 
    182         nFeatures++; 
    183         offsetAndLineFeaturesTable = 
    184             (OffsetAndLine*)CPLRealloc(offsetAndLineFeaturesTable, nFeatures * sizeof(OffsetAndLine)); 
    185         offsetAndLineFeaturesTable[nFeatures-1].offset = offset; 
    186         offsetAndLineFeaturesTable[nFeatures-1].line = line; 
     271        eol[0] = 13; 
     272        eol[1] = 10; 
     273        eol[2] = 0; 
    187274    } 
     275    else 
     276    { 
     277        eol[0] = 10; 
     278        eol[1] = 0; 
     279    } 
     280     
     281    if ( ! bWriter ) 
     282    { 
     283        return OGRERR_FAILURE; 
     284    } 
     285     
     286    if( poFeature->GetFID() == OGRNullFID ) 
     287        poFeature->SetFID( nFeatures++ ); 
     288     
     289    FILE* fp = poDS->GetOutputFP(); 
     290    int nbPairPerLine = poDS->GetNbPairPerLine(); 
     291    char formatCoordinates[32]; 
     292    sprintf(formatCoordinates, "%%s%%.%df%s%%.%df", 
     293            poDS->GetCoordinatePrecision(), poDS->GetCoordinateSeparator(), poDS->GetCoordinatePrecision()); 
    188294 
    189     poFeature = BuildFeatureFromBNARecord(record, nNextFID++); 
     295    switch( poGeom->getGeometryType() ) 
     296    { 
     297        case wkbPoint: 
     298        case wkbPoint25D: 
     299        { 
     300            OGRPoint* point = (OGRPoint*)poGeom; 
     301            WriteFeatureAttributes(fp, poFeature); 
     302            VSIFPrintf( fp, "1"); 
     303            VSIFPrintf( fp, formatCoordinates, partialEol, point->getX(), point->getY()); 
     304            VSIFPrintf( fp, "%s", eol); 
     305            break; 
     306        } 
     307             
     308        case wkbPolygon: 
     309        case wkbPolygon25D: 
     310        { 
     311            OGRPolygon* polygon = (OGRPolygon*)poGeom; 
     312            OGRLinearRing* ring = polygon->getExteriorRing(); 
     313            double firstX = ring->getX(0); 
     314            double firstY = ring->getY(0); 
     315            int nBNAPoints = ring->getNumPoints(); 
     316            int is_ellipse = FALSE; 
     317             
     318            /* This code tries to detect an ellipse in a polygon geometry */ 
     319            /* This will only work presumably on ellipses already read from a BNA file */ 
     320            /* Mostly a BNA to BNA feature... */ 
     321            if (poDS->GetEllipsesAsEllipses() && 
     322                polygon->getNumInteriorRings() == 0 && 
     323                nBNAPoints == 361) 
     324            { 
     325                double oppositeX = ring->getX(180); 
     326                double oppositeY = ring->getY(180); 
     327                double quarterX = ring->getX(90); 
     328                double quarterY = ring->getY(90); 
     329                double antiquarterX = ring->getX(270); 
     330                double antiquarterY = ring->getY(270); 
     331                double center1X = 0.5*(firstX + oppositeX); 
     332                double center1Y = 0.5*(firstY + oppositeY); 
     333                double center2X = 0.5*(quarterX + antiquarterX); 
     334                double center2Y = 0.5*(quarterY + antiquarterY); 
     335                if (fabs(center1X - center2X) < 1e-5 && fabs(center1Y - center2Y) < 1e-5 && 
     336                    fabs(oppositeY - firstY) < 1e-5 && 
     337                    fabs(quarterX - antiquarterX) < 1e-5) 
     338                { 
     339                    double major_radius = fabs(firstX - center1X); 
     340                    double minor_radius = fabs(quarterY - center1Y); 
     341                    is_ellipse = TRUE; 
     342                    for(i=0;i<360;i++) 
     343                    { 
     344                        if (!(fabs(center1X + major_radius * cos(i * (M_PI / 180)) - ring->getX(i)) < 1e-5 && 
     345                              fabs(center1Y + minor_radius * sin(i * (M_PI / 180)) - ring->getY(i)) < 1e-5)) 
     346                        { 
     347                            is_ellipse = FALSE; 
     348                            break; 
     349                        } 
     350                    } 
     351                    if ( is_ellipse == TRUE ) 
     352                    { 
     353                        WriteFeatureAttributes(fp, poFeature); 
     354                        VSIFPrintf( fp, "2"); 
     355                        VSIFPrintf( fp, formatCoordinates, partialEol, center1X, center1Y); 
     356                        VSIFPrintf( fp, formatCoordinates,  partialEol, major_radius, minor_radius); 
     357                        VSIFPrintf( fp, "%s", eol); 
     358                    } 
     359                } 
     360            } 
    190361 
    191     BNA_FreeRecord(record); 
     362            if ( is_ellipse == FALSE) 
     363            { 
     364                int nInteriorRings = polygon->getNumInteriorRings(); 
     365                for(i=0;i<nInteriorRings;i++) 
     366                { 
     367                    nBNAPoints += polygon->getInteriorRing(i)->getNumPoints() + 1; 
     368                } 
     369                if (nBNAPoints <= 3) 
     370                { 
     371                    CPLError( CE_Failure, CPLE_AppDefined, "Invalid geometry" ); 
     372                    return OGRERR_FAILURE; 
     373                } 
     374                WriteFeatureAttributes(fp, poFeature); 
     375                VSIFPrintf( fp, "%d", nBNAPoints); 
     376                n = ring->getNumPoints(); 
     377                int nbPair = 0; 
     378                for(i=0;i<n;i++) 
     379                { 
     380                    VSIFPrintf( fp, formatCoordinates, 
     381                                ((nbPair % nbPairPerLine) == 0) ? partialEol : " ", ring->getX(i), ring->getY(i)); 
     382                    nbPair++; 
     383                } 
     384                for(i=0;i<nInteriorRings;i++) 
     385                { 
     386                    ring = polygon->getInteriorRing(i); 
     387                    n = ring->getNumPoints(); 
     388                    for(j=0;i<n;i++) 
     389                    { 
     390                        VSIFPrintf( fp, formatCoordinates, 
     391                                    ((nbPair % nbPairPerLine) == 0) ? partialEol : " ", ring->getX(j), ring->getY(j)); 
     392                        nbPair++; 
     393                    } 
     394                    VSIFPrintf( fp, formatCoordinates, 
     395                                ((nbPair % nbPairPerLine) == 0) ? partialEol : " ", firstX, firstY); 
     396                    nbPair++; 
     397                } 
     398                VSIFPrintf( fp, "%s", eol); 
     399            } 
     400            break; 
     401        } 
    192402 
    193     return poFeature; 
     403        case wkbMultiPolygon: 
     404        case wkbMultiPolygon25D: 
     405        { 
     406            OGRMultiPolygon* multipolygon = (OGRMultiPolygon*)poGeom; 
     407            int N = multipolygon->getNumGeometries(); 
     408            int nBNAPoints = 0; 
     409            double firstX = 0, firstY = 0;  
     410            for(i=0;i<N;i++) 
     411            { 
     412                OGRPolygon* polygon = (OGRPolygon*)multipolygon->getGeometryRef(i); 
     413                OGRLinearRing* ring = polygon->getExteriorRing(); 
     414                if (nBNAPoints) 
     415                    nBNAPoints ++; 
     416                else 
     417                { 
     418                    firstX = ring->getX(0); 
     419                    firstY = ring->getY(0); 
     420                } 
     421                nBNAPoints += ring->getNumPoints(); 
     422                int nInteriorRings = polygon->getNumInteriorRings(); 
     423                for(j=0;j<nInteriorRings;j++) 
     424                { 
     425                    nBNAPoints += polygon->getInteriorRing(j)->getNumPoints() + 1; 
     426                } 
     427            } 
     428            if (nBNAPoints <= 3) 
     429            { 
     430                CPLError( CE_Failure, CPLE_AppDefined, "Invalid geometry" ); 
     431                return OGRERR_FAILURE; 
     432            } 
     433            WriteFeatureAttributes(fp, poFeature); 
     434            VSIFPrintf( fp, "%d", nBNAPoints); 
     435            int nbPair = 0; 
     436            for(i=0;i<N;i++) 
     437            { 
     438                OGRPolygon* polygon = (OGRPolygon*)multipolygon->getGeometryRef(i); 
     439                OGRLinearRing* ring = polygon->getExteriorRing(); 
     440                n = ring->getNumPoints(); 
     441                int nInteriorRings = polygon->getNumInteriorRings(); 
     442                for(j=0;j<n;j++) 
     443                { 
     444                    VSIFPrintf( fp, formatCoordinates, 
     445                                ((nbPair % nbPairPerLine) == 0) ? partialEol : " ",ring->getX(j), ring->getY(j)); 
     446                    nbPair++; 
     447                } 
     448                if (i != 0) 
     449                { 
     450                    VSIFPrintf( fp, formatCoordinates, 
     451                                ((nbPair % nbPairPerLine) == 0) ? partialEol : " ",firstX, firstY); 
     452                    nbPair++; 
     453                } 
     454                for(j=0;j<nInteriorRings;j++) 
     455                { 
     456                    ring = polygon->getInteriorRing(j); 
     457                    n = ring->getNumPoints(); 
     458                    for(k=0;k<n;k++) 
     459                    { 
     460                        VSIFPrintf( fp, formatCoordinates,  
     461                                    ((nbPair % nbPairPerLine) == 0) ? partialEol : " ", ring->getX(k), ring->getY(k)); 
     462                        nbPair++; 
     463                    } 
     464                    VSIFPrintf( fp, formatCoordinates, 
     465                                ((nbPair % nbPairPerLine) == 0) ? partialEol : " ", firstX, firstY); 
     466                    nbPair++; 
     467                } 
     468            } 
     469            VSIFPrintf( fp, "%s", eol); 
     470            break; 
     471        } 
     472 
     473        case wkbLineString: 
     474        case wkbLineString25D: 
     475        { 
     476            OGRLineString* line = (OGRLineString*)poGeom; 
     477            int n = line->getNumPoints(); 
     478            int i; 
     479            if (n < 2) 
     480            { 
     481                CPLError( CE_Failure, CPLE_AppDefined, "Invalid geometry" ); 
     482                return OGRERR_FAILURE; 
     483            } 
     484            WriteFeatureAttributes(fp, poFeature); 
     485            VSIFPrintf( fp, "-%d", n); 
     486            int nbPair = 0; 
     487            for(i=0;i<n;i++) 
     488            { 
     489                VSIFPrintf( fp, formatCoordinates, 
     490                            ((nbPair % nbPairPerLine) == 0) ? partialEol : " ", line->getX(i), line->getY(i)); 
     491                nbPair++; 
     492            } 
     493            VSIFPrintf( fp, "%s", eol); 
     494            break; 
     495        } 
     496             
     497        default: 
     498        { 
     499            CPLError( CE_Failure, CPLE_AppDefined, 
     500                      "Unsupported geometry type : %s.", 
     501                      poGeom->getGeometryName() ); 
     502 
     503            return OGRERR_UNSUPPORTED_GEOMETRY_TYPE; 
     504        } 
     505    } 
     506     
     507    return OGRERR_NONE; 
    194508} 
    195509 
     510 
     511 
    196512/************************************************************************/ 
    197 /*                           BuildFeatureFromBNARecord()                          */ 
     513/*                            CreateField()                             */ 
    198514/************************************************************************/ 
     515 
     516OGRErr OGRBNALayer::CreateField( OGRFieldDefn *poField, int bApproxOK ) 
     517 
     518{ 
     519    if( !bWriter || nFeatures != 0) 
     520        return OGRERR_FAILURE; 
     521 
     522    poFeatureDefn->AddFieldDefn( poField ); 
     523 
     524    return OGRERR_NONE; 
     525} 
     526 
     527/************************************************************************/ 
     528/*                           MakeMultiPolygon()                         */ 
     529/************************************************************************/ 
     530 
     531/* This is indeed of general use and may relate really closely with bug #1217 */ 
     532/* If it works correctly, maybe a candidate for upper level exposition */  
     533 
     534enum 
     535{ 
     536    CONTAINS, 
     537    IS_CONTAINED_BY, 
     538    NOT_RELATED 
     539}; 
     540 
     541static OGRMultiPolygon *  MakeMultiPolygon (OGRPolygon** polygons, 
     542                                            int nbPolygons, 
     543                                            int* pIsValidGeometry) 
     544{ 
     545    int i, j; 
     546    OGRMultiPolygon* multipolygon = new OGRMultiPolygon(); 
     547     
     548    if (nbPolygons == 1) 
     549    { 
     550        multipolygon->addGeometry(polygons[0]); 
     551    } 
     552    else 
     553    { 
     554#ifndef HAVE_GEOS 
     555        static int firstTime = 1; 
     556        if (firstTime) 
     557        { 
     558            CPLError(CE_Warning, CPLE_AppDefined,  
     559                     "GDAL should be built with GEOS support enabled in order the " 
     560                     "BNA driver to provide reliable results on complex polygons."); 
     561            firstTime = 0; 
     562        } 
     563#endif 
     564 
     565        OGREnvelope* envelopes = new OGREnvelope[nbPolygons]; 
     566        int** relations = new int*[nbPolygons]; 
     567        double* areas = new double[nbPolygons]; 
     568        int go_on = 1; 
     569        for(i=0;i<nbPolygons;i++) 
     570        { 
     571            relations[i] = new int[nbPolygons]; 
     572            polygons[i]->getEnvelope(&envelopes[i]); 
     573            areas[i] = polygons[i]->get_Area(); 
     574        } 
     575         
     576        /* This a several step algorithm : 
     577           1) Compute in a matrix how polygons relate to each other 
     578              (this is the moment for detecting pathological intersections and exiting) 
     579           2) For each polygon, find the smallest enclosing polygon 
     580           3) For each polygon, compute its inclusion depth (0 means toplevel) 
     581           4) For each polygon of odd depth (= inner ring), add it to its outer ring 
     582         
     583           Complexity : O(nbPolygons^2) 
     584        */ 
     585         
     586        /* Compute how each polygon relate to the other ones 
     587           To save a bit of computation we always begin the computation by a test on the 
     588           enveloppe. We also take into account the areas to avoid some useless tests. 
     589           (A contains B implies envelop(A) contains envelop(B) and area(A) > area(B)) 
     590           In practise, we can hope that few full geometry intersection of inclusion test is done: 
     591             * if the polygons are well separated geographically 
     592                (a set of islands for example), no full geometry intersection or inclusion 
     593                test is done. (the envelopes don't intersect each other) 
     594             * if the polygons are 'lake inside an island inside a lake inside an area' and 
     595               that each polygon is much smaller than its enclosing one, their bounding boxes 
     596               are stricly contained into each oter, and thus, no full geometry intersection or inclusion 
     597               test is done 
     598        */ 
     599        for(i=0;go_on && i<nbPolygons;i++) 
     600        { 
     601            for(j=i+1;go_on && j<nbPolygons;j++) 
     602            { 
     603                if (envelopes[i].Contains(envelopes[j]) 
     604                    && areas[i] > areas[j] 
     605#ifdef HAVE_GEOS 
     606                    && polygons[i]->Contains(polygons[j]) 
     607#endif 
     608                   ) 
     609                { 
     610                    relations[i][j] = CONTAINS; 
     611                    relations[j][i] = IS_CONTAINED_BY; 
     612                } 
     613                else if (envelopes[j].Contains(envelopes[i]) 
     614                         && areas[j] > areas[i] 
     615#ifdef HAVE_GEOS 
     616                         && polygons[j]->Contains(polygons[i]) 
     617#endif 
     618                        ) 
     619                { 
     620                    relations[j][i] = CONTAINS; 
     621                    rela