LTP GCOV extension - code coverage report
Current view: directory - ogr/ogrsf_frmts/ntf - ntffilereader.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 757
Code covered: 54.7 % Executed lines: 414

       1                 : /******************************************************************************
       2                 :  * $Id: ntffilereader.cpp 11589 2007-06-03 15:01:36Z warmerdam $
       3                 :  *
       4                 :  * Project:  NTF Translator
       5                 :  * Purpose:  NTFFileReader class implementation.
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 1999, Frank Warmerdam
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include <stdarg.h>
      31                 : #include "ntf.h"
      32                 : #include "cpl_conv.h"
      33                 : #include "cpl_string.h"
      34                 : #include "ogr_api.h"
      35                 : 
      36                 : CPL_CVSID("$Id: ntffilereader.cpp 11589 2007-06-03 15:01:36Z warmerdam $");
      37                 : 
      38                 : static int DefaultNTFRecordGrouper( NTFFileReader *, NTFRecord **,
      39                 :                                     NTFRecord * );
      40                 : 
      41                 : #ifndef PI
      42                 : #  define PI 3.14159265358979323846
      43                 : #endif
      44                 : 
      45                 : /************************************************************************/
      46                 : /*                            NTFFileReader                             */
      47                 : /************************************************************************/
      48                 : 
      49               2 : NTFFileReader::NTFFileReader( OGRNTFDataSource * poDataSource )
      50                 : 
      51                 : {
      52               2 :     fp = NULL;
      53                 : 
      54               2 :     nFCCount = 0;
      55               2 :     papszFCNum = NULL;
      56               2 :     papszFCName = NULL;
      57                 : 
      58               2 :     nPreSavedPos = nPostSavedPos = 0;
      59               2 :     nSavedFeatureId = nBaseFeatureId = 1;
      60               2 :     nFeatureCount = -1;
      61               2 :     poSavedRecord = NULL;
      62                 : 
      63               2 :     nAttCount = 0;
      64               2 :     pasAttDesc = NULL;
      65                 : 
      66               2 :     pszTileName = NULL;
      67               2 :     pszProduct = NULL;
      68               2 :     pszPVName = NULL;
      69               2 :     pszFilename = NULL;
      70                 : 
      71               2 :     apoCGroup[0] = NULL;
      72                 : 
      73               2 :     poDS = poDataSource;
      74                 : 
      75               2 :     memset( apoTypeTranslation, 0, sizeof(apoTypeTranslation) );
      76                 : 
      77               2 :     nProduct = NPC_UNKNOWN;
      78                 : 
      79               2 :     pfnRecordGrouper = DefaultNTFRecordGrouper;
      80                 : 
      81               2 :     dfXYMult = 1.0;
      82               2 :     dfZMult = 1.0;
      83               2 :     dfXOrigin = 0;
      84               2 :     dfYOrigin = 0;
      85               2 :     nNTFLevel = 0;
      86               2 :     dfTileXSize = 0;
      87               2 :     dfTileYSize = 0;
      88                 : 
      89               2 :     dfScale = 0.0;
      90               2 :     dfPaperToGround = 0.0;
      91                 : 
      92               2 :     nCoordWidth = 6;
      93               2 :     nZWidth = 6;
      94                 : 
      95             202 :     for( int i = 0; i < 100; i++ )
      96                 :     {
      97             200 :         anIndexSize[i] = 0;
      98             200 :         apapoRecordIndex[i] = NULL;
      99                 :     }
     100                 : 
     101               2 :     panColumnOffset = NULL;
     102               2 :     poRasterLayer = NULL;
     103               2 :     nRasterXSize = nRasterYSize = nRasterDataType = 1;
     104                 : 
     105               2 :     bIndexBuilt = FALSE;
     106               2 :     bIndexNeeded = FALSE;
     107                 : 
     108               2 :     if( poDS->GetOption("CACHE_LINES") != NULL
     109                 :         && EQUAL(poDS->GetOption("CACHE_LINES"),"OFF") )
     110               0 :         bCacheLines = FALSE;
     111                 :     else
     112               2 :         bCacheLines = TRUE;
     113                 : 
     114               2 :     nLineCacheSize = 0;
     115               2 :     papoLineCache = NULL;
     116               2 : }
     117                 : 
     118                 : /************************************************************************/
     119                 : /*                           ~NTFFileReader()                           */
     120                 : /************************************************************************/
     121                 : 
     122               2 : NTFFileReader::~NTFFileReader()
     123                 : 
     124                 : {
     125               2 :     CacheClean();
     126               2 :     DestroyIndex();
     127               2 :     ClearDefs();
     128               2 :     CPLFree( pszFilename );
     129               2 :     CPLFree( panColumnOffset );
     130               2 : }
     131                 : 
     132                 : /************************************************************************/
     133                 : /*                             SetBaseFID()                             */
     134                 : /************************************************************************/
     135                 : 
     136               2 : void NTFFileReader::SetBaseFID( long nNewBase )
     137                 : 
     138                 : {
     139               2 :     CPLAssert( nSavedFeatureId == 1 );
     140                 : 
     141               2 :     nBaseFeatureId = nNewBase;
     142               2 :     nSavedFeatureId = nBaseFeatureId;
     143               2 : }
     144                 : 
     145                 : /************************************************************************/
     146                 : /*                             ClearDefs()                              */
     147                 : /*                                                                      */
     148                 : /*      Clear attribute definitions and feature classes.  All the       */
     149                 : /*      stuff that would have to be cleaned up by Open(), and the       */
     150                 : /*      destructor.                                                     */
     151                 : /************************************************************************/
     152                 : 
     153               4 : void NTFFileReader::ClearDefs()
     154                 : 
     155                 : {
     156                 :     int         i;
     157                 : 
     158               4 :     Close();
     159                 :     
     160               4 :     ClearCGroup();
     161                 :     
     162               4 :     CSLDestroy( papszFCNum );
     163               4 :     papszFCNum = NULL;
     164               4 :     CSLDestroy( papszFCName );
     165               4 :     papszFCName = NULL;
     166               4 :     nFCCount = 0;
     167                 : 
     168              58 :     for( i = 0; i < nAttCount; i++ )
     169                 :     {
     170              54 :         if( pasAttDesc[i].poCodeList != NULL )
     171               0 :             delete pasAttDesc[i].poCodeList;
     172                 :     }
     173                 : 
     174               4 :     CPLFree( pasAttDesc );
     175               4 :     nAttCount = 0;
     176               4 :     pasAttDesc = NULL;
     177                 :     
     178               4 :     CPLFree( pszProduct );
     179               4 :     pszProduct = NULL;
     180                 : 
     181               4 :     CPLFree( pszPVName );
     182               4 :     pszPVName = NULL;
     183                 :     
     184               4 :     CPLFree( pszTileName );
     185               4 :     pszTileName = NULL;
     186               4 : }
     187                 : 
     188                 : /************************************************************************/
     189                 : /*                               Close()                                */
     190                 : /*                                                                      */
     191                 : /*      Close the file, but don't wipe out our knowledge about this     */
     192                 : /*      file.                                                           */
     193                 : /************************************************************************/
     194                 : 
     195              24 : void NTFFileReader::Close()
     196                 : 
     197                 : {
     198              24 :     if( poSavedRecord != NULL )
     199              10 :         delete poSavedRecord;
     200              24 :     poSavedRecord = NULL;
     201                 : 
     202              24 :     nPreSavedPos = nPostSavedPos = 0;
     203              24 :     nSavedFeatureId = nBaseFeatureId;
     204              24 :     if( fp != NULL )
     205                 :     {
     206              12 :         VSIFClose( fp );
     207              12 :         fp = NULL;
     208                 :     }
     209                 : 
     210              24 :     CacheClean();
     211              24 : }
     212                 : 
     213                 : /************************************************************************/
     214                 : /*                                Open()                                */
     215                 : /************************************************************************/
     216                 : 
     217              12 : int NTFFileReader::Open( const char * pszFilenameIn )
     218                 : 
     219                 : {
     220              12 :     if( pszFilenameIn != NULL )
     221                 :     {
     222               2 :         ClearDefs();
     223                 :     
     224               2 :         CPLFree( pszFilename );
     225               2 :         pszFilename = CPLStrdup( pszFilenameIn );
     226                 :     }
     227                 :     else
     228              10 :         Close();
     229                 :     
     230                 : /* -------------------------------------------------------------------- */
     231                 : /*      Open the file.                                                  */
     232                 : /* -------------------------------------------------------------------- */
     233              12 :     fp = VSIFOpen( pszFilename, "rb" );
     234                 : 
     235                 :     // notdef: we should likely issue a proper CPL error message based
     236                 :     // based on errno here. 
     237              12 :     if( fp == NULL )
     238                 :     {
     239                 :         CPLError( CE_Failure, CPLE_OpenFailed,
     240                 :                   "Unable to open file `%s' for read access.\n",
     241               0 :                   pszFilename );
     242               0 :         return FALSE;
     243                 :     }
     244                 : 
     245                 : /* -------------------------------------------------------------------- */
     246                 : /*      If we are just reopening an existing file we will just scan     */
     247                 : /*      past the section header ... no need to reform all the definitions.*/
     248                 : /* -------------------------------------------------------------------- */
     249              12 :     if( pszFilenameIn == NULL )
     250                 :     {
     251                 :         NTFRecord      *poRecord;
     252                 : 
     253            1670 :         for( poRecord = new NTFRecord( fp ); 
     254                 :              poRecord->GetType() != NRT_VTR && poRecord->GetType() != NRT_SHR;
     255                 :              poRecord = new NTFRecord( fp ) )
     256                 :         {
     257            1660 :             delete poRecord;
     258                 :         }
     259                 : 
     260              10 :         delete poRecord;
     261                 : 
     262              10 :         return TRUE;
     263                 :     }
     264                 : 
     265                 : /* -------------------------------------------------------------------- */
     266                 : /*      Read the first record, and verify it is a proper volume header. */
     267                 : /* -------------------------------------------------------------------- */
     268               2 :     NTFRecord      oVHR( fp );
     269                 : 
     270               2 :     if( oVHR.GetType() != NRT_VHR )
     271                 :     {
     272                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     273                 :                   "File `%s' appears to not be a UK NTF file.\n",
     274               0 :                   pszFilename );
     275               2 :         return FALSE;
     276                 :     }
     277                 : 
     278               2 :     nNTFLevel = atoi(oVHR.GetField( 57, 57 ));
     279               2 :     CPLAssert( nNTFLevel >= 1 && nNTFLevel <= 5 );
     280                 : 
     281                 : /* -------------------------------------------------------------------- */
     282                 : /*      Read records till we get the section header.                    */
     283                 : /* -------------------------------------------------------------------- */
     284                 :     NTFRecord      *poRecord;
     285                 : 
     286             332 :     for( poRecord = new NTFRecord( fp ); 
     287                 :          poRecord->GetType() != NRT_VTR && poRecord->GetType() != NRT_SHR;
     288                 :          poRecord = new NTFRecord( fp ) )
     289                 :     {
     290                 : /* -------------------------------------------------------------------- */
     291                 : /*      Handle feature class name records.                              */
     292                 : /* -------------------------------------------------------------------- */
     293             330 :         if( poRecord->GetType() == NRT_FCR )
     294                 :         {
     295                 :             const char      *pszData;
     296                 :             int             iChar;
     297                 :             char            szFCName[100];
     298                 : 
     299             274 :             nFCCount++;
     300                 : 
     301             274 :             papszFCNum = CSLAddString( papszFCNum, poRecord->GetField(3,6) );
     302                 : 
     303             274 :             szFCName[0] = '\0';
     304             274 :             pszData = poRecord->GetData();
     305                 :             
     306                 :             // CODE_COM
     307             274 :             for( iChar = 15; pszData[iChar] == ' ' && iChar > 5; iChar-- ) {}
     308                 : 
     309             274 :             if( iChar > 6 )
     310               0 :                 strcat( szFCName, poRecord->GetField(7,iChar+1) );
     311                 : 
     312                 :             // STCLASS
     313             274 :             for( iChar = 35; pszData[iChar] == ' ' && iChar > 15; iChar-- ) {}
     314                 : 
     315             274 :             if( iChar > 15 )
     316                 :             {
     317               0 :                 if( strlen(szFCName) > 0 )
     318               0 :                     strcat( szFCName, " : " );
     319               0 :                 strcat( szFCName, poRecord->GetField(17,iChar+1) );
     320                 :             }
     321                 : 
     322                 :             // FEATDES
     323             274 :             for( iChar = 36; 
     324                 :                  pszData[iChar] != '\0' && pszData[iChar] != '\\';
     325                 :                  iChar++ ) {}
     326                 : 
     327             274 :             if( iChar > 37 )
     328                 :             {
     329             274 :                 if( strlen(szFCName) > 0 )
     330               0 :                     strcat( szFCName, " : " );
     331             274 :                 strcat( szFCName, poRecord->GetField(37,iChar) );
     332                 :             }
     333                 : 
     334             274 :             papszFCName = CSLAddString(papszFCName, szFCName );
     335                 :         }
     336                 : 
     337                 : /* -------------------------------------------------------------------- */
     338                 : /*      Handle attribute description records.                           */
     339                 : /* -------------------------------------------------------------------- */
     340              56 :         else if( poRecord->GetType() == NRT_ADR )
     341                 :         {
     342              54 :             nAttCount++;
     343                 : 
     344                 :             pasAttDesc = (NTFAttDesc *) 
     345              54 :                 CPLRealloc( pasAttDesc, sizeof(NTFAttDesc) * nAttCount );
     346                 : 
     347              54 :             ProcessAttDesc( poRecord, pasAttDesc + nAttCount - 1 );
     348                 :         }
     349                 : 
     350                 : /* -------------------------------------------------------------------- */
     351                 : /*      Handle attribute description records.                           */
     352                 : /* -------------------------------------------------------------------- */
     353               2 :         else if( poRecord->GetType() == NRT_CODELIST )
     354                 :         {
     355                 :             NTFCodeList *poCodeList;
     356                 :             NTFAttDesc  *psAttDesc;
     357                 : 
     358               0 :             poCodeList = new NTFCodeList( poRecord );
     359               0 :             psAttDesc = GetAttDesc( poCodeList->szValType );
     360               0 :             if( psAttDesc == NULL )
     361                 :             {
     362                 :                 CPLDebug( "NTF", "Got CODELIST for %s without ATTDESC.", 
     363               0 :                           poCodeList->szValType );
     364               0 :                 delete poCodeList;
     365                 :             }
     366                 :             else
     367                 :             {
     368               0 :                 psAttDesc->poCodeList = poCodeList;
     369                 :             }
     370                 :         }
     371                 : 
     372                 : /* -------------------------------------------------------------------- */
     373                 : /*      Handle database header record.                                  */
     374                 : /* -------------------------------------------------------------------- */
     375               2 :         else if( poRecord->GetType() == NRT_DHR )
     376                 :         {
     377                 :             int         iChar;
     378               2 :             pszProduct = CPLStrdup(poRecord->GetField(3,22));
     379               2 :             for( iChar = strlen(pszProduct)-1;
     380                 :                  iChar > 0 && pszProduct[iChar] == ' ';
     381                 :                  pszProduct[iChar--] = '\0' ) {}
     382                 : 
     383               2 :             pszPVName = CPLStrdup(poRecord->GetField(76+3,76+22));
     384               2 :             for( iChar = strlen(pszPVName)-1;
     385                 :                  iChar > 0 && pszPVName[iChar] == ' ';
     386                 :                  pszPVName[iChar--] = '\0' ) {}
     387                 : 
     388                 :         }
     389                 : 
     390             330 :         delete poRecord;
     391                 :     }
     392                 : 
     393                 : /* -------------------------------------------------------------------- */
     394                 : /*      Did we fall off the end without finding what we were looking    */
     395                 : /*      for?                                                            */
     396                 : /* -------------------------------------------------------------------- */
     397               2 :     if( poRecord->GetType() == NRT_VTR )
     398                 :     {
     399               0 :         delete poRecord;
     400                 :         CPLError( CE_Failure, CPLE_AppDefined,
     401                 :                   "Cound not find section header record in %s.\n", 
     402               0 :                   pszFilename );
     403               0 :         return FALSE;
     404                 :     }
     405                 : 
     406                 : /* -------------------------------------------------------------------- */
     407                 : /*      Classify the product type.                                      */
     408                 : /* -------------------------------------------------------------------- */
     409               2 :     if( EQUALN(pszProduct,"LAND-LINE",9) && atof(pszPVName+5) < 1.3 )
     410               0 :         nProduct = NPC_LANDLINE;
     411               2 :     else if( EQUALN(pszProduct,"LAND-LINE",9) )
     412               0 :         nProduct = NPC_LANDLINE99;
     413               2 :     else if( EQUAL(pszProduct,"OS_LANDRANGER_CONT") ) // Panorama
     414               0 :         nProduct = NPC_LANDRANGER_CONT;
     415               2 :     else if( EQUAL(pszProduct,"L-F_PROFILE_CON") ) // Panorama
     416               0 :         nProduct = NPC_LANDFORM_PROFILE_CONT;
     417               2 :     else if( EQUALN(pszProduct,"Strategi",8) )
     418               1 :         nProduct = NPC_STRATEGI;
     419               1 :     else if( EQUALN(pszProduct,"Meridian_02",11) )
     420               1 :         nProduct = NPC_MERIDIAN2;
     421               0 :     else if( EQUALN(pszProduct,"Meridian_01",11) )
     422               0 :         nProduct = NPC_MERIDIAN;
     423               0 :     else if( EQUAL(pszProduct,NTF_BOUNDARYLINE) 
     424                 :              && EQUALN(pszPVName,"A10N_FC",7) )
     425               0 :         nProduct = NPC_BOUNDARYLINE;
     426               0 :     else if( EQUAL(pszProduct,NTF_BOUNDARYLINE) 
     427                 :              && EQUALN(pszPVName,"A20N_FC",7) )
     428               0 :         nProduct = NPC_BL2000;
     429               0 :     else if( EQUALN(pszProduct,"BaseData.GB",11) )
     430               0 :         nProduct = NPC_BASEDATA;
     431               0 :     else if( EQUALN(pszProduct,"OSCAR_ASSET",11) )
     432               0 :         nProduct = NPC_OSCAR_ASSET;
     433               0 :     else if( EQUALN(pszProduct,"OSCAR_TRAFF",11) )
     434               0 :         nProduct = NPC_OSCAR_TRAFFIC;
     435               0 :     else if( EQUALN(pszProduct,"OSCAR_ROUTE",11) )
     436               0 :         nProduct = NPC_OSCAR_ROUTE;
     437               0 :     else if( EQUALN(pszProduct,"OSCAR_NETWO",11) )
     438               0 :         nProduct = NPC_OSCAR_NETWORK;
     439               0 :     else if( EQUALN(pszProduct,"ADDRESS_POI",11) )
     440               0 :         nProduct = NPC_ADDRESS_POINT;
     441               0 :     else if( EQUALN(pszProduct,"CODE_POINT",10) )
     442                 :     {
     443               0 :         if( GetAttDesc( "RH" ) == NULL )
     444               0 :             nProduct = NPC_CODE_POINT;
     445                 :         else
     446               0 :             nProduct = NPC_CODE_POINT_PLUS;
     447                 :     }
     448               0 :     else if( EQUALN(pszProduct,"OS_LANDRANGER_DTM",17) )
     449               0 :         nProduct = NPC_LANDRANGER_DTM;
     450               0 :     else if( EQUALN(pszProduct,"L-F_PROFILE_DTM",15) )
     451               0 :         nProduct = NPC_LANDFORM_PROFILE_DTM;
     452               0 :     else if( EQUALN(pszProduct,"NEXTMap Britain DTM",19) )
     453               0 :         nProduct = NPC_LANDFORM_PROFILE_DTM; // Treat as landform
     454                 : 
     455               2 :     if( poDS->GetOption("FORCE_GENERIC") != NULL
     456                 :         && !EQUAL(poDS->GetOption("FORCE_GENERIC"),"OFF") )
     457               0 :         nProduct = NPC_UNKNOWN;
     458                 : 
     459                 :     // No point in caching lines if there are no polygons.
     460               2 :     if( nProduct != NPC_BOUNDARYLINE && nProduct != NPC_BL2000 )
     461               2 :         bCacheLines = FALSE;
     462                 :     
     463                 : /* -------------------------------------------------------------------- */
     464                 : /*      Handle the section header record.                               */
     465                 : /* -------------------------------------------------------------------- */
     466               2 :     nSavedFeatureId = nBaseFeatureId;
     467               2 :     nStartPos = VSIFTell(fp);
     468                 :     
     469               2 :     pszTileName = CPLStrdup(poRecord->GetField(3,12));        // SECT_REF
     470              14 :     while( pszTileName[strlen(pszTileName)-1] == ' ' )
     471              10 :         pszTileName[strlen(pszTileName)-1] = '\0';
     472                 : 
     473               2 :     nCoordWidth = atoi(poRecord->GetField(15,19));            // XYLEN
     474               2 :     if( nCoordWidth == 0 )
     475               0 :         nCoordWidth = 10;
     476                 :     
     477               2 :     nZWidth = atoi(poRecord->GetField(31,35));                // ZLEN
     478               2 :     if( nZWidth == 0 )
     479               2 :         nZWidth = 10;
     480                 :     
     481               2 :     dfXYMult = atoi(poRecord->GetField(21,30)) / 1000.0;      // XY_MULT
     482               2 :     dfXOrigin = atoi(poRecord->GetField(47,56));
     483               2 :     dfYOrigin = atoi(poRecord->GetField(57,66));
     484               2 :     dfTileXSize = atoi(poRecord->GetField(23+74,32+74));
     485               2 :     dfTileYSize = atoi(poRecord->GetField(33+74,42+74));
     486               2 :     dfZMult = atoi(poRecord->GetField(37,46)) / 1000.0;
     487                 : 
     488                 : /* -------------------------------------------------------------------- */
     489                 : /*      Setup scale and transformation factor for text height.          */
     490                 : /* -------------------------------------------------------------------- */
     491               2 :     if( poRecord->GetLength() >= 187 )
     492               0 :         dfScale = atoi(poRecord->GetField(148+31,148+39));
     493               2 :     else if( nProduct == NPC_STRATEGI )
     494               1 :         dfScale = 250000;
     495               2 :     else if( nProduct == NPC_MERIDIAN || nProduct == NPC_MERIDIAN2 )
     496               1 :         dfScale = 100000;
     497               0 :     else if( nProduct == NPC_LANDFORM_PROFILE_CONT )
     498               0 :         dfScale = 10000;
     499               0 :     else if( nProduct == NPC_LANDRANGER_CONT )
     500               0 :         dfScale = 50000;
     501               0 :     else if( nProduct == NPC_OSCAR_ASSET
     502                 :              || nProduct == NPC_OSCAR_TRAFFIC
     503                 :              || nProduct == NPC_OSCAR_NETWORK
     504                 :              || nProduct == NPC_OSCAR_ROUTE )
     505               0 :         dfScale = 10000;
     506               0 :     else if( nProduct == NPC_BASEDATA )
     507               0 :         dfScale = 625000;
     508               0 :     else if( nProduct == NPC_BOUNDARYLINE )
     509               0 :         dfScale = 10000;
     510                 :     else
     511               0 :         dfScale = 10000;
     512                 : 
     513               2 :     if( dfScale != 0.0 )
     514               2 :         dfPaperToGround = dfScale / 1000.0;
     515                 :     else
     516               0 :         dfPaperToGround = 0.0;
     517                 : 
     518               2 :     delete poRecord;
     519                 : 
     520                 : /* -------------------------------------------------------------------- */
     521                 : /*      Ensure we have appropriate layers defined.                      */
     522                 : /* -------------------------------------------------------------------- */
     523               2 :     CPLErrorReset();
     524                 : 
     525               2 :     if( !IsRasterProduct() )
     526               2 :         EstablishLayers();
     527                 :     else
     528               0 :         EstablishRasterAccess();
     529                 :     
     530               2 :     return CPLGetLastErrorType() != CE_Failure;
     531                 : }
     532                 : 
     533                 : /************************************************************************/
     534                 : /*                            DumpReadable()                            */
     535                 : /************************************************************************/
     536                 : 
     537               0 : void NTFFileReader::DumpReadable( FILE *fpLog )
     538                 : 
     539                 : {
     540               0 :     fprintf( fpLog, "Tile Name = %s\n", pszTileName );
     541               0 :     fprintf( fpLog, "Product = %s\n", pszProduct );
     542               0 :     fprintf( fpLog, "NTFLevel = %d\n", nNTFLevel );
     543               0 :     fprintf( fpLog, "XYLEN = %d\n", nCoordWidth );
     544               0 :     fprintf( fpLog, "XY_MULT = %g\n", dfXYMult );
     545               0 :     fprintf( fpLog, "X_ORIG = %g\n", dfXOrigin );
     546               0 :     fprintf( fpLog, "Y_ORIG = %g\n", dfYOrigin ); 
     547               0 :     fprintf( fpLog, "XMAX = %g\n", dfTileXSize );
     548               0 :     fprintf( fpLog, "YMAX = %g\n", dfTileYSize );
     549               0 : }
     550                 : 
     551                 : /************************************************************************/
     552                 : /*                          ProcessGeometry()                           */
     553                 : /*                                                                      */
     554                 : /*      Drop duplicate vertices from line strings ... they mess up      */
     555                 : /*      FME's polygon handling sometimes.                               */
     556                 : /************************************************************************/
     557                 : 
     558                 : OGRGeometry *NTFFileReader::ProcessGeometry( NTFRecord * poRecord,
     559           19828 :                                              int * pnGeomId )
     560                 : 
     561                 : {
     562                 :     int            nGType, nNumCoord;
     563           19828 :     OGRGeometry    *poGeometry = NULL;
     564                 : 
     565           19828 :     if( poRecord->GetType() == NRT_GEOMETRY3D )
     566               0 :         return ProcessGeometry3D( poRecord, pnGeomId );
     567                 : 
     568           19828 :     else if( poRecord->GetType() != NRT_GEOMETRY )
     569               0 :         return NULL;
     570                 : 
     571           19828 :     nGType = atoi(poRecord->GetField(9,9));            // GTYPE
     572           19828 :     nNumCoord = atoi(poRecord->GetField(10,13));       // NUM_COORD
     573           19828 :     if( pnGeomId != NULL )
     574           18486 :         *pnGeomId = atoi(poRecord->GetField(3,8));     // GEOM_ID
     575                 : 
     576                 : /* -------------------------------------------------------------------- */
     577                 : /*      Point                                                           */
     578                 : /* -------------------------------------------------------------------- */
     579           19828 :     if( nGType == 1 )
     580                 :     {
     581                 :         double      dfX, dfY;
     582                 :         
     583                 :         dfX = atoi(poRecord->GetField(14,14+GetXYLen()-1)) * GetXYMult() 
     584           10945 :             + GetXOrigin();
     585                 :         dfY = atoi(poRecord->GetField(14+GetXYLen(),14+GetXYLen()*2-1))
     586           10945 :             * GetXYMult() + GetYOrigin();
     587                 :       
     588           10945 :         poGeometry = new OGRPoint( dfX, dfY );
     589                 :     }
     590                 :     
     591                 : /* -------------------------------------------------------------------- */
     592                 : /*      Line (or arc)                                                   */
     593                 : /* -------------------------------------------------------------------- */
     594           17766 :     else if( nGType == 2 || nGType == 3 || nGType == 4 )
     595                 :     {
     596            8883 :         OGRLineString      *poLine = new OGRLineString;
     597            8883 :         double             dfX, dfY, dfXLast=0.0, dfYLast=0.0;
     598            8883 :         int                iCoord, nOutCount = 0;
     599                 : 
     600            8883 :         poGeometry = poLine;
     601            8883 :         poLine->setNumPoints( nNumCoord );
     602          106791 :         for( iCoord = 0; iCoord < nNumCoord; iCoord++ )
     603                 :         {
     604           97908 :             int            iStart = 14 + iCoord * (GetXYLen()*2+1);
     605                 : 
     606                 :             dfX = atoi(poRecord->GetField(iStart+0,
     607                 :                                           iStart+GetXYLen()-1)) 
     608           97908 :                 * GetXYMult() + GetXOrigin();
     609                 :             dfY = atoi(poRecord->GetField(iStart+GetXYLen(),
     610                 :                                           iStart+GetXYLen()*2-1)) 
     611           97908 :                 * GetXYMult() + GetYOrigin();
     612                 : 
     613           97908 :             if( iCoord == 0 )
     614                 :             {
     615            8883 :                 dfXLast = dfX;
     616            8883 :                 dfYLast = dfY;
     617            8883 :                 poLine->setPoint( nOutCount++, dfX, dfY );
     618                 :             }
     619           89025 :             else if( dfXLast != dfX || dfYLast != dfY )
     620                 :             {
     621           89009 :                 dfXLast = dfX;
     622           89009 :                 dfYLast = dfY;
     623           89009 :                 poLine->setPoint( nOutCount++, dfX, dfY );
     624                 :             }
     625                 :         }
     626            8883 :         poLine->setNumPoints( nOutCount );
     627                 : 
     628            8883 :         CacheAddByGeomId( atoi(poRecord->GetField(3,8)), poLine );
     629                 :     }
     630                 : 
     631                 : /* -------------------------------------------------------------------- */
     632                 : /*      Arc defined by three points on the arc.                         */
     633                 : /* -------------------------------------------------------------------- */
     634               0 :     else if( nGType == 5 && nNumCoord == 3 )
     635                 :     {
     636                 :         double  adfX[3], adfY[3];
     637                 :         int     iCoord;
     638                 : 
     639               0 :         for( iCoord = 0; iCoord < nNumCoord; iCoord++ )
     640                 :         {
     641               0 :             int            iStart = 14 + iCoord * (GetXYLen()*2+1);
     642                 : 
     643                 :             adfX[iCoord] = atoi(poRecord->GetField(iStart+0,
     644                 :                                                   iStart+GetXYLen()-1)) 
     645               0 :                 * GetXYMult() + GetXOrigin();
     646                 :             adfY[iCoord] = atoi(poRecord->GetField(iStart+GetXYLen(),
     647                 :                                                   iStart+GetXYLen()*2-1)) 
     648               0 :                 * GetXYMult() + GetYOrigin();
     649                 :         }
     650                 : 
     651                 :         poGeometry = NTFStrokeArcToOGRGeometry_Points( adfX[0], adfY[0], 
     652                 :                                                        adfX[1], adfY[1],
     653               0 :                                                        adfX[2], adfY[2], 72 );
     654                 :     }
     655                 : 
     656                 : /* -------------------------------------------------------------------- */
     657                 : /*      Circle                                                          */
     658                 : /* -------------------------------------------------------------------- */
     659               0 :     else if( nGType == 7 )
     660                 :     {
     661                 :         double  dfCenterX, dfCenterY, dfArcX, dfArcY, dfRadius;
     662               0 :         int     iCenterStart = 14;
     663               0 :         int     iArcStart = 14 + 2 * GetXYLen() + 1;
     664                 : 
     665                 :         dfCenterX = atoi(poRecord->GetField(iCenterStart,
     666                 :                                             iCenterStart+GetXYLen()-1))
     667               0 :             * GetXYMult() + GetXOrigin();
     668                 :         dfCenterY = atoi(poRecord->GetField(iCenterStart+GetXYLen(),
     669                 :                                             iCenterStart+GetXYLen()*2-1))
     670               0 :             * GetXYMult() + GetYOrigin();
     671                 :         
     672                 :         dfArcX = atoi(poRecord->GetField(iArcStart,
     673                 :                                          iArcStart+GetXYLen()-1))
     674               0 :             * GetXYMult() + GetXOrigin();
     675                 :         dfArcY = atoi(poRecord->GetField(iArcStart+GetXYLen(),
     676                 :                                          iArcStart+GetXYLen()*2-1))
     677               0 :             * GetXYMult() + GetYOrigin();
     678                 : 
     679                 :         dfRadius = sqrt( (dfCenterX - dfArcX) * (dfCenterX - dfArcX)
     680               0 :                          + (dfCenterY - dfArcY) * (dfCenterY - dfArcY) );
     681                 : 
     682                 :         poGeometry = NTFStrokeArcToOGRGeometry_Angles( dfCenterX, dfCenterY,
     683                 :                                                        dfRadius, 
     684                 :                                                        0.0, 360.0, 
     685               0 :                                                        72 );
     686                 :     }
     687                 : 
     688                 :     else
     689                 :     {
     690               0 :         fprintf( stderr, "GType = %d\n", nGType );
     691               0 :         CPLAssert( FALSE );
     692                 :     }
     693                 : 
     694           19828 :     if( poGeometry != NULL )
     695           19828 :         poGeometry->assignSpatialReference( poDS->GetSpatialRef() );
     696                 : 
     697           19828 :     return poGeometry;
     698                 : }
     699                 : 
     700                 : /************************************************************************/
     701                 : /*                         ProcessGeometry3D()                          */
     702                 : /************************************************************************/
     703                 : 
     704                 : OGRGeometry *NTFFileReader::ProcessGeometry3D( NTFRecord * poRecord,
     705               0 :                                                int * pnGeomId )
     706                 : 
     707                 : {
     708                 :     int            nGType, nNumCoord;
     709               0 :     OGRGeometry    *poGeometry = NULL;
     710                 : 
     711               0 :     if( poRecord->GetType() != NRT_GEOMETRY3D )
     712               0 :         return NULL;
     713                 : 
     714               0 :     nGType = atoi(poRecord->GetField(9,9));            // GTYPE
     715               0 :     nNumCoord = atoi(poRecord->GetField(10,13));       // NUM_COORD
     716               0 :     if( pnGeomId != NULL )
     717               0 :         *pnGeomId = atoi(poRecord->GetField(3,8));     // GEOM_ID
     718                 : 
     719               0 :     if( nGType == 1 )
     720                 :     {
     721                 :         double      dfX, dfY, dfZ;
     722                 :         
     723                 :         dfX = atoi(poRecord->GetField(14,14+GetXYLen()-1)) * GetXYMult() 
     724               0 :             + GetXOrigin();
     725                 :         dfY = atoi(poRecord->GetField(14+GetXYLen(),14+GetXYLen()*2-1))
     726               0 :             * GetXYMult() + GetYOrigin();
     727                 :         dfZ = atoi(poRecord->GetField(14+1+2*GetXYLen(),
     728               0 :                                       14+1+2*GetXYLen()+nZWidth-1)) * dfZMult;
     729                 : 
     730                 :       
     731               0 :         poGeometry = new OGRPoint( dfX, dfY, dfZ );
     732                 :     }
     733                 :     
     734               0 :     else if( nGType == 2 )
     735                 :     {
     736               0 :         OGRLineString      *poLine = new OGRLineString;
     737               0 :         double             dfX, dfY, dfZ, dfXLast=0.0, dfYLast=0.0;
     738               0 :         int                iCoord, nOutCount = 0;
     739                 : 
     740               0 :         poGeometry = poLine;
     741               0 :         poLine->setNumPoints( nNumCoord );
     742               0 :         for( iCoord = 0; iCoord < nNumCoord; iCoord++ )
     743                 :         {
     744               0 :             int            iStart = 14 + iCoord * (GetXYLen()*2+nZWidth+2);
     745                 : 
     746                 :             dfX = atoi(poRecord->GetField(iStart+0,
     747                 :                                           iStart+GetXYLen()-1)) 
     748               0 :                 * GetXYMult() + GetXOrigin();
     749                 :             dfY = atoi(poRecord->GetField(iStart+GetXYLen(),
     750                 :                                           iStart+GetXYLen()*2-1)) 
     751               0 :                 * GetXYMult() + GetYOrigin();
     752                 : 
     753                 :             dfZ = atoi(poRecord->GetField(iStart+1+2*GetXYLen(),
     754                 :                                           iStart+1+2*GetXYLen()+nZWidth-1))
     755               0 :                 * dfZMult;
     756                 : 
     757               0 :             if( iCoord == 0 )
     758                 :             {
     759               0 :                 dfXLast = dfX;
     760               0 :                 dfYLast = dfY;
     761               0 :                 poLine->setPoint( nOutCount++, dfX, dfY, dfZ );
     762                 :             }
     763               0 :             else if( dfXLast != dfX || dfYLast != dfY )
     764                 :             {
     765               0 :                 dfXLast = dfX;
     766               0 :                 dfYLast = dfY;
     767               0 :                 poLine->setPoint( nOutCount++, dfX, dfY, dfZ );
     768                 :             }
     769                 :         }
     770               0 :         poLine->setNumPoints( nOutCount );
     771                 : 
     772               0 :         CacheAddByGeomId( atoi(poRecord->GetField(3,8)), poLine );
     773                 :     }
     774                 : 
     775               0 :     if( poGeometry != NULL )
     776               0 :         poGeometry->assignSpatialReference( poDS->GetSpatialRef() );
     777                 :     
     778               0 :     return poGeometry;
     779                 : }
     780                 : 
     781                 : /************************************************************************/
     782                 : /*                           ProcessAttDesc()                           */
     783                 : /************************************************************************/
     784                 : 
     785              54 : int NTFFileReader::ProcessAttDesc( NTFRecord * poRecord, NTFAttDesc* psAD )
     786                 : 
     787                 : {
     788                 :     int      iChar;
     789                 :     const char *pszData;
     790                 : 
     791              54 :     if( poRecord->GetType() != NRT_ADR )
     792               0 :         return FALSE;
     793                 : 
     794              54 :     psAD->poCodeList = NULL;
     795              54 :     strcpy( psAD->val_type, poRecord->GetField( 3, 4 ));
     796              54 :     strcpy( psAD->fwidth, poRecord->GetField( 5, 7 ));
     797              54 :     strcpy( psAD->finter, poRecord->GetField( 8, 12 ));
     798                 :     
     799              54 :     pszData = poRecord->GetData();
     800              54 :     for( iChar = 12; 
     801                 :          pszData[iChar] != '\0' && pszData[iChar] != '\\';
     802                 :          iChar++ ) {}
     803                 : 
     804              54 :     strcpy( psAD->att_name, poRecord->GetField( 13, iChar ));
     805                 : 
     806              54 :     return TRUE;
     807                 : }
     808                 : 
     809                 : /************************************************************************/
     810                 : /*                         ProcessAttRecGroup()                         */
     811                 : /*                                                                      */
     812                 : /*      Extract attribute values from all attribute records in a        */
     813                 : /*      record set.                                                     */
     814                 : /************************************************************************/
     815                 : 
     816                 : int NTFFileReader::ProcessAttRecGroup( NTFRecord **papoRecords,
     817                 :                                        char ***ppapszTypes,
     818           19828 :                                        char ***ppapszValues )
     819                 : 
     820                 : {
     821           19828 :     *ppapszTypes = NULL;
     822           19828 :     *ppapszValues = NULL;
     823                 :     
     824           81996 :     for( int iRec = 0; papoRecords[iRec] != NULL; iRec++ )
     825                 :     {
     826           62168 :         char    **papszTypes1 = NULL, **papszValues1 = NULL;
     827                 :         
     828           62168 :         if( papoRecords[iRec]->GetType() != NRT_ATTREC )
     829           42340 :             continue;
     830                 : 
     831           19828 :         if( !ProcessAttRec( papoRecords[iRec], NULL,
     832                 :                             &papszTypes1, &papszValues1 ) )
     833               0 :             return FALSE;
     834                 : 
     835           19828 :         if( *ppapszTypes == NULL )
     836                 :         {
     837           19828 :             *ppapszTypes = papszTypes1;
     838           19828 :             *ppapszValues = papszValues1;
     839                 :         }
     840                 :         else
     841                 :         {
     842               0 :             for( int i=0; papszTypes1[i] != NULL; i++ )
     843                 :             {
     844               0 :                 *ppapszTypes = CSLAddString( *ppapszTypes, papszTypes1[i] );
     845               0 :                 *ppapszValues = CSLAddString( *ppapszValues, papszValues1[i] );
     846                 :             }
     847               0 :             CSLDestroy( papszTypes1 );
     848               0 :             CSLDestroy( papszValues1 );
     849                 :         }
     850                 :     }
     851                 : 
     852           19828 :     return TRUE;
     853                 : }
     854                 : 
     855                 : /************************************************************************/
     856                 : /*                           ProcessAttRec()                            */
     857                 : /************************************************************************/
     858                 : 
     859                 : int NTFFileReader::ProcessAttRec( NTFRecord * poRecord, 
     860                 :                                   int *pnAttId,
     861                 :                                   char *** ppapszTypes, 
     862           19828 :                                   char *** ppapszValues )
     863                 : 
     864                 : {
     865                 :     int            iOffset;
     866                 :     const char     *pszData;
     867                 : 
     868           19828 :     if( poRecord->GetType() != NRT_ATTREC )
     869               0 :         return FALSE;
     870                 : 
     871                 : /* -------------------------------------------------------------------- */
     872                 : /*      Extract the attribute id.                                       */
     873                 : /* -------------------------------------------------------------------- */
     874           19828 :     if( pnAttId != NULL )
     875               0 :         *pnAttId = atoi(poRecord->GetField(3,8));
     876                 : 
     877                 : /* ==================================================================== */
     878                 : /*      Loop handling attribute till we get a '0' indicating the end    */
     879                 : /*      of the record.                                                  */
     880                 : /* ==================================================================== */
     881           19828 :     *ppapszTypes = NULL;
     882           19828 :     *ppapszValues = NULL;
     883                 : 
     884           19828 :     iOffset = 8;
     885           19828 :     pszData = poRecord->GetData();
     886                 : 
     887           82936 :     while( pszData[iOffset] != '0' && pszData[iOffset] != '\0' )
     888                 :     {
     889                 :         NTFAttDesc *psAttDesc;
     890                 :         int         nEnd;
     891                 :         int         nFWidth;
     892                 : 
     893                 : /* -------------------------------------------------------------------- */
     894                 : /*      Extract the two letter code name for the attribute, and use     */
     895                 : /*      it to find the correct ATTDESC info.                            */
     896                 : /* -------------------------------------------------------------------- */
     897           43280 :         psAttDesc = GetAttDesc(pszData + iOffset );
     898           43280 :         if( psAttDesc == NULL )
     899                 :         {
     900                 :             CPLDebug( "NTF", "Couldn't translate attrec type `%2.2s'.", 
     901               0 :                       pszData + iOffset );
     902               0 :             return FALSE;
     903                 :         }
     904                 : 
     905                 :         *ppapszTypes =
     906                 :             CSLAddString( *ppapszTypes, 
     907           43280 :                           poRecord->GetField(iOffset+1,iOffset+2) );
     908                 : 
     909                 : /* -------------------------------------------------------------------- */
     910                 : /*      Establish the width of the value.  Zero width fields are        */
     911                 : /*      terminated by a backslash.                                      */
     912                 : /* -------------------------------------------------------------------- */
     913           43280 :         nFWidth = atoi(psAttDesc->fwidth);
     914           43280 :         if( nFWidth == 0 )
     915                 :         {
     916            5401 :             const char * pszData = poRecord->GetData();
     917                 : 
     918            5401 :             for( nEnd = iOffset + 2; 
     919                 :                  pszData[nEnd] != '\\' && pszData[nEnd] != '\0';
     920                 :                  nEnd++ ) {}
     921                 :         }
     922                 :         else
     923                 :         {
     924           37879 :             nEnd = iOffset + 3 + nFWidth - 1;
     925                 :         }
     926                 : 
     927                 : /* -------------------------------------------------------------------- */
     928                 : /*      Extract the value.  If it is formatted as fixed point real      */
     929                 : /*      we reprocess it to insert the decimal point.                    */
     930                 : /* -------------------------------------------------------------------- */
     931           43280 :         const char * pszRawValue = poRecord->GetField(iOffset+3,nEnd);
     932           43280 :         *ppapszValues = CSLAddString( *ppapszValues, pszRawValue );
     933                 : 
     934                 : /* -------------------------------------------------------------------- */
     935                 : /*      Establish new offset position.                                  */
     936                 : /* -------------------------------------------------------------------- */
     937           43280 :         if( nFWidth == 0 )
     938                 :         {
     939            5401 :             iOffset = nEnd;
     940            5401 :             if( pszData[iOffset] == '\\' )
     941            5394 :                 iOffset++;
     942                 :         }
     943                 :         else
     944           37879 :             iOffset += 2 + atoi(psAttDesc->fwidth);
     945                 :     }
     946                 : 
     947           19828 :     return TRUE;
     948                 : }
     949                 : 
     950                 : /************************************************************************/
     951                 : /*                             GetAttDesc()                             */
     952                 : /************************************************************************/
     953                 : 
     954           84731 : NTFAttDesc * NTFFileReader::GetAttDesc( const char * pszType )
     955                 : 
     956                 : {
     957          465136 :     for( int i = 0; i < nAttCount; i++ )
     958                 :     {
     959          465136 :         if( EQUALN(pszType, pasAttDesc[i].val_type, 2) )
     960           84731 :             return pasAttDesc + i;
     961                 :     }
     962                 : 
     963               0 :     return NULL;
     964                 : }
     965                 : 
     966                 : /************************************************************************/
     967                 : /*                          ProcessAttValue()                           */
     968                 : /*                                                                      */
     969                 : /*      Take an attribute type/value pair and transform into a          */
     970                 : /*      meaningful attribute name, and value.  The source can be an     */
     971                 : /*      ATTREC or the VAL_TYPE/VALUE pair of a POINTREC or LINEREC.     */
     972                 : /*      The name is transformed from the two character short form to    */
     973                 : /*      the long user name.  The value will be transformed from         */
     974                 : /*      fixed point (with the decimal implicit) to fixed point with     */
     975                 : /*      an explicit decimal point if it has a "R" format.               */
     976                 : /************************************************************************/
     977                 : 
     978                 : int NTFFileReader::ProcessAttValue( const char *pszValType, 
     979                 :                                     const char *pszRawValue,
     980                 :                                     char **ppszAttName, 
     981                 :                                     char **ppszAttValue,
     982           41451 :                                     char **ppszCodeDesc )
     983                 : 
     984                 : {
     985                 : /* -------------------------------------------------------------------- */
     986                 : /*      Find the ATTDESC for this attribute, and assign return name value.*/
     987                 : /* -------------------------------------------------------------------- */
     988           41451 :     NTFAttDesc      *psAttDesc = GetAttDesc(pszValType);
     989                 : 
     990           41451 :     if( psAttDesc == NULL )
     991               0 :         return FALSE;
     992                 : 
     993           41451 :     if( ppszAttName != NULL )
     994           41451 :         *ppszAttName = psAttDesc->att_name;
     995                 : 
     996                 : /* -------------------------------------------------------------------- */
     997                 : /*      Extract the value.  If it is formatted as fixed point real      */
     998                 : /*      we reprocess it to insert the decimal point.                    */
     999                 : /* -------------------------------------------------------------------- */
    1000           41451 :     if( psAttDesc->finter[0] == 'R' )
    1001                 :     {
    1002                 :         static char      szRealString[30];
    1003                 :         const char *pszDecimalPortion;
    1004                 :         int       nWidth, nPrecision;
    1005                 : 
    1006              96 :         for( pszDecimalPortion = psAttDesc->finter; 
    1007                 :              *pszDecimalPortion != ',' && *pszDecimalPortion != '\0';
    1008                 :              pszDecimalPortion++ ) {}
    1009                 : 
    1010              96 :         nWidth = strlen(pszRawValue);
    1011              96 :         nPrecision = atoi(pszDecimalPortion+1);
    1012                 : 
    1013              96 :         strncpy( szRealString, pszRawValue, nWidth - nPrecision );
    1014              96 :         szRealString[nWidth-nPrecision] = '.';
    1015                 :         strcpy( szRealString+nWidth-nPrecision+1, 
    1016              96 :                 pszRawValue+nWidth-nPrecision );
    1017                 :         
    1018              96 :         *ppszAttValue = szRealString;
    1019                 :     }
    1020                 : 
    1021                 : /* -------------------------------------------------------------------- */
    1022                 : /*      If it is an integer, we just reformat to get rid of leading     */
    1023                 : /*      zeros.                                                          */
    1024                 : /* -------------------------------------------------------------------- */
    1025           41355 :     else if( psAttDesc->finter[0] == 'I' )
    1026                 :     {
    1027                 :         static char    szIntString[30];
    1028                 : 
    1029           14267 :         sprintf( szIntString, "%d", atoi(pszRawValue) );
    1030                 : 
    1031           14267 :         *ppszAttValue = szIntString;
    1032                 :     }
    1033                 : 
    1034                 : /* -------------------------------------------------------------------- */
    1035                 : /*      Otherwise we take the value directly.                           */
    1036                 : /* -------------------------------------------------------------------- */
    1037                 :     else
    1038                 :     {
    1039           27088 :         *ppszAttValue = (char *) pszRawValue;
    1040                 :     }
    1041                 : 
    1042                 : /* -------------------------------------------------------------------- */
    1043                 : /*      Handle processing code values into code descriptions, if        */
    1044                 : /*      applicable.                                                     */
    1045                 : /* -------------------------------------------------------------------- */
    1046           41451 :     if( ppszCodeDesc == NULL )
    1047                 :     {
    1048                 :     }
    1049           41451 :     else if( psAttDesc->poCodeList != NULL )
    1050                 :     {
    1051               0 :         *ppszCodeDesc = (char *)psAttDesc->poCodeList->Lookup( *ppszAttValue );
    1052                 :     }
    1053                 :     else
    1054                 :     {
    1055           41451 :         *ppszCodeDesc = NULL;
    1056                 :     }
    1057                 : 
    1058           41451 :     return TRUE;
    1059                 : }
    1060                 : 
    1061                 : /************************************************************************/
    1062                 : /*                        ApplyAttributeValues()                        */
    1063                 : /*                                                                      */
    1064                 : /*      Apply a series of attribute values to a feature from generic    */
    1065                 : /*      attribute records.                                              */
    1066                 : /************************************************************************/
    1067                 : 
    1068                 : void NTFFileReader::ApplyAttributeValues( OGRFeature * poFeature,
    1069           19828 :                                           NTFRecord ** papoGroup, ... )
    1070                 : 
    1071                 : {
    1072           19828 :     char        **papszTypes = NULL, **papszValues = NULL;
    1073                 : 
    1074                 : /* -------------------------------------------------------------------- */
    1075                 : /*      Extract attribute values from record group.                     */
    1076                 : /* -------------------------------------------------------------------- */
    1077           19828 :     if( !ProcessAttRecGroup( papoGroup, &papszTypes, &papszValues ) )
    1078               0 :         return;
    1079                 :     
    1080                 : /* -------------------------------------------------------------------- */
    1081                 : /*      Handle attribute pairs                                          */
    1082                 : /* -------------------------------------------------------------------- */
    1083                 :     va_list     hVaArgs;
    1084                 :     const char  *pszAttName;
    1085                 :     
    1086           19828 :     va_start(hVaArgs, papoGroup);
    1087                 : 
    1088          394223 :     while( (pszAttName = va_arg(hVaArgs, const char *)) != NULL )
    1089                 :     {
    1090          354567 :         int     iField = va_arg(hVaArgs, int);
    1091                 : 
    1092                 :         ApplyAttributeValue( poFeature, iField, pszAttName,
    1093          354567 :                              papszTypes, papszValues );
    1094                 :     }
    1095                 : 
    1096                 : /* -------------------------------------------------------------------- */
    1097                 : /*      Cleanup.                                                        */
    1098                 : /* -------------------------------------------------------------------- */
    1099           19828 :     CSLDestroy( papszTypes );
    1100           19828 :     CSLDestroy( papszValues );
    1101                 : }
    1102                 :                                           
    1103                 : 
    1104                 : /************************************************************************/
    1105                 : /*                        ApplyAttributeValue()                         */
    1106                 : /*                                                                      */
    1107                 : /*      Apply the indicated attribute value to an OGRFeature field      */
    1108                 : /*      if it exists in the attribute value list given.                 */
    1109                 : /************************************************************************/
    1110                 : 
    1111                 : int NTFFileReader::ApplyAttributeValue( OGRFeature * poFeature, int iField,
    1112                 :                                         const char * pszAttName,
    1113                 :                                         char ** papszTypes,
    1114          354567 :                                         char ** papszValues )
    1115                 : 
    1116                 : {
    1117                 : /* -------------------------------------------------------------------- */
    1118                 : /*      Find the requested attribute in the name/value pair             */
    1119                 : /*      provided.  If not found that's fine, just return with           */
    1120                 : /*      notification.                                                   */
    1121                 : /* -------------------------------------------------------------------- */
    1122                 :     int         iValue;
    1123                 :     
    1124          354567 :     iValue = CSLFindString( papszTypes, pszAttName );
    1125          354567 :     if( iValue < 0 )
    1126          313116 :         return FALSE;
    1127                 : 
    1128                 : /* -------------------------------------------------------------------- */
    1129                 : /*      Process the attribute value ... this really only has a          */
    1130                 : /*      useful effect for real numbers.                                 */
    1131                 : /* -------------------------------------------------------------------- */
    1132                 :     char        *pszAttLongName, *pszAttValue, *pszCodeDesc;
    1133                 : 
    1134                 :     ProcessAttValue( pszAttName, papszValues[iValue],
    1135           41451 :                      &pszAttLongName, &pszAttValue, &pszCodeDesc );
    1136                 : 
    1137                 : /* -------------------------------------------------------------------- */
    1138                 : /*      Apply the value to the field using the simple set string        */
    1139                 : /*      method.  Leave it to the OGRFeature::SetField() method to       */
    1140                 : /*      take care of translation to other types.                        */
    1141                 : /* -------------------------------------------------------------------- */
    1142           41451 :     poFeature->SetField( iField, pszAttValue );
    1143                 : 
    1144                 : /* -------------------------------------------------------------------- */
    1145                 : /*      Apply the code description if we found one.                     */
    1146                 : /* -------------------------------------------------------------------- */
    1147           41451 :     if( pszCodeDesc != NULL )
    1148                 :     {
    1149                 :         char    szDescFieldName[256];
    1150                 : 
    1151                 :         sprintf( szDescFieldName, "%s_DESC", 
    1152               0 :                  poFeature->GetDefnRef()->GetFieldDefn(iField)->GetNameRef() );
    1153               0 :         poFeature->SetField( szDescFieldName, pszCodeDesc );
    1154                 :     }
    1155                 : 
    1156           41451 :     return TRUE;
    1157                 : }
    1158                 : 
    1159                 : /************************************************************************/
    1160                 : /*                             SaveRecord()                             */
    1161                 : /************************************************************************/
    1162                 : 
    1163          133933 : void NTFFileReader::SaveRecord( NTFRecord * poRecord )
    1164                 : 
    1165                 : {
    1166          133933 :     CPLAssert( poSavedRecord == NULL );
    1167          133933 :     poSavedRecord = poRecord;
    1168          133933 : }
    1169                 : 
    1170                 : /************************************************************************/
    1171                 : /*                             ReadRecord()                             */
    1172                 : /************************************************************************/
    1173                 : 
    1174          454872 : NTFRecord *NTFFileReader::ReadRecord()
    1175                 : 
    1176                 : {
    1177          454872 :     if( poSavedRecord != NULL )
    1178                 :     {
    1179                 :         NTFRecord       *poReturn;
    1180                 : 
    1181          133922 :         poReturn = poSavedRecord;
    1182                 : 
    1183          133922 :         poSavedRecord = NULL;
    1184                 : 
    1185          133922 :         return poReturn;
    1186                 :     }
    1187                 :     else
    1188                 :     {
    1189                 :         NTFRecord       *poRecord;
    1190                 : 
    1191          320950 :         CPLErrorReset();
    1192          320950 :         if( fp != NULL )
    1193          320950 :             nPreSavedPos = VSIFTell( fp );
    1194          320950 :         poRecord = new NTFRecord( fp );
    1195          320950 :         if( fp != NULL )
    1196          320950 :             nPostSavedPos = VSIFTell( fp );
    1197                 : 
    1198                 :         /* ensure termination if we fail to read a record */
    1199          320950 :         if( CPLGetLastErrorType() == CE_Failure )
    1200                 :         {
    1201               0 :             delete poRecord;
    1202               0 :             poRecord = NULL;
    1203                 :         }
    1204                 : 
    1205          320950 :         return poRecord;
    1206                 :     }
    1207                 : }
    1208                 : 
    1209                 : /************************************************************************/
    1210                 : /*                              GetFPPos()                              */
    1211                 : /*                                                                      */
    1212                 : /*      Return the current file pointer position.                       */
    1213                 : /************************************************************************/
    1214                 : 
    1215           31216 : void NTFFileReader::GetFPPos( long *pnPos, long *pnFID )
    1216                 : 
    1217                 : {
    1218           31216 :     if( poSavedRecord != NULL )
    1219           31216 :         *pnPos = nPreSavedPos;
    1220                 :     else
    1221               0 :         *pnPos = nPostSavedPos;
    1222                 : 
    1223           31216 :     if( pnFID != NULL )
    1224           31216 :         *pnFID = nSavedFeatureId;
    1225           31216 : }
    1226                 : 
    1227                 : /************************************************************************/
    1228                 : /*                              SetFPPos()                              */
    1229                 : /************************************************************************/
    1230                 : 
    1231           31224 : int NTFFileReader::SetFPPos( long nNewPos, long nNewFID )
    1232                 : 
    1233                 : {
    1234           31224 :     if( nNewFID == nSavedFeatureId )
    1235           31223 :         return TRUE;
    1236                 : 
    1237               1 :     if( poSavedRecord != NULL )
    1238                 :     {
    1239               1 :         delete poSavedRecord;
    1240               1 :         poSavedRecord = NULL;
    1241                 :     }
    1242                 : 
    1243               1 :     if( fp != NULL && VSIFSeek( fp, nNewPos, SEEK_SET ) == 0 )
    1244                 :     {
    1245               1 :         nPreSavedPos = nPostSavedPos = nNewPos;
    1246               1 :         nSavedFeatureId = nNewFID;
    1247               1 :         return TRUE;
    1248                 :     }
    1249                 :     else
    1250               0 :         return FALSE;
    1251                 : }
    1252                 : 
    1253                 : /************************************************************************/
    1254                 : /*                               Reset()                                */
    1255                 : /*                                                                      */
    1256                 : /*      Reset reading to the first feature record.                      */
    1257                 : /************************************************************************/
    1258                 : 
    1259              11 : void NTFFileReader::Reset()
    1260                 : 
    1261                 : {
    1262              11 :     SetFPPos( nStartPos, nBaseFeatureId );
    1263              11 :     ClearCGroup();
    1264              11 : }
    1265                 : 
    1266                 : /************************************************************************/
    1267                 : /*                            ClearCGroup()                             */
    1268                 : /*                                                                      */
    1269                 : /*      Clear the currently loaded record group.                        */
    1270                 : /************************************************************************/
    1271                 : 
    1272          133948 : void NTFFileReader::ClearCGroup()
    1273                 : 
    1274                 : {
    1275          454887 :     for( int i = 0; apoCGroup[i] != NULL; i++ )
    1276          320939 :         delete apoCGroup[i];
    1277                 : 
    1278          133948 :     apoCGroup[0] = NULL;
    1279          133948 :     apoCGroup[1] = NULL;
    1280          133948 : }
    1281                 : 
    1282                 : /************************************************************************/
    1283                 : /*                      DefaultNTFRecordGrouper()                       */
    1284                 : /*                                                                      */
    1285                 : /*      Default rules for figuring out if a new candidate record        */
    1286                 : /*      belongs to a group of records that together form a feature      */
    1287                 : /*      (a record group).                                               */
    1288                 : /************************************************************************/
    1289                 : 
    1290                 : int DefaultNTFRecordGrouper( NTFFileReader *, NTFRecord ** papoGroup,
    1291          454856 :                              NTFRecord * poCandidate )
    1292                 : 
    1293                 : {
    1294                 : /* -------------------------------------------------------------------- */
    1295                 : /*      Is this group going to be a CPOLY set?  We can recognise        */
    1296                 : /*      this because we get repeating POLY/CHAIN sets without an        */
    1297                 : /*      intermediate attribute record.  This is a rather special case!  */
    1298                 : /* -------------------------------------------------------------------- */
    1299          454856 :     if( papoGroup[0] != NULL && papoGroup[1] != NULL
    1300                 :         && papoGroup[0]->GetType() == NRT_POLYGON
    1301                 :         && papoGroup[1]->GetType() == NRT_CHAIN )
    1302                 :     {
    1303                 :         // We keep going till we get the seed geometry.
    1304               0 :         int     iRec, bGotCPOLY=FALSE;
    1305                 : 
    1306               0 :         for( iRec = 0; papoGroup[iRec] != NULL; iRec++ ) 
    1307                 :         {
    1308               0 :             if( papoGroup[iRec]->GetType() == NRT_CPOLY )
    1309               0 :                 bGotCPOLY = TRUE;
    1310                 :         }
    1311                 : 
    1312               0 :         if( bGotCPOLY 
    1313                 :             && poCandidate->GetType() != NRT_GEOMETRY
    1314                 :             && poCandidate->GetType() != NRT_ATTREC )
    1315               0 :             return FALSE;
    1316                 : 
    1317                 :         /*
    1318                 :          * this logic assumes we always get a point geometry with a CPOLY
    1319                 :          * but that isn't always true, for instance with BL2000 data.  The
    1320                 :          * preceed check will handle this case.
    1321                 :          */
    1322               0 :         if( papoGroup[iRec-1]->GetType() != NRT_GEOMETRY )
    1323               0 :             return TRUE;
    1324                 :         else
    1325               0 :             return FALSE;
    1326                 :     }
    1327                 :     
    1328                 : /* -------------------------------------------------------------------- */
    1329                 : /*      Is this a "feature" defining record?  If so break out if it     */
    1330                 : /*      isn't the first record in the group.                            */
    1331                 : /* -------------------------------------------------------------------- */
    1332          454856 :     if( papoGroup[0] != NULL 
    1333                 :         && (poCandidate->GetType() == NRT_NAMEREC
    1334                 :             || poCandidate->GetType() == NRT_NODEREC
    1335                 :             || poCandidate->GetType() == NRT_LINEREC
    1336                 :             || poCandidate->GetType() == NRT_POINTREC
    1337                 :             || poCandidate->GetType() == NRT_POLYGON
    1338                 :             || poCandidate->GetType() == NRT_CPOLY
    1339                 :             || poCandidate->GetType() == NRT_COLLECT
    1340                 :             || poCandidate->GetType() == NRT_TEXTREC
    1341                 :             || poCandidate->GetType() == NRT_COMMENT) )
    1342                 :     {
    1343          133917 :         return FALSE;
    1344                 :     }
    1345                 : 
    1346                 : /* -------------------------------------------------------------------- */
    1347                 : /*      Do we already have a record of this type?  If so, it likely     */
    1348                 : /*      doesn't belong in the group.  Attribute records do repeat in    */
    1349                 : /*      some products.                                                  */
    1350                 : /* -------------------------------------------------------------------- */
    1351          320939 :     if (poCandidate->GetType() != NRT_ATTREC )
    1352                 :     {
    1353                 :         int     iRec;
    1354          347779 :         for( iRec = 0; papoGroup[iRec] != NULL; iRec++ )
    1355                 :         {
    1356          114979 :             if( poCandidate->GetType() == papoGroup[iRec]->GetType() )
    1357               0 :                 break;
    1358                 :         }
    1359                 :            
    1360          232800 :         if( papoGroup[iRec] != NULL )
    1361               0 :             return FALSE;
    1362                 :     }
    1363                 : 
    1364          320939 :     return TRUE;
    1365                 : }
    1366                 : 
    1367                 : /************************************************************************/
    1368                 : /*                          ReadRecordGroup()                           */
    1369                 : /*                                                                      */
    1370                 : /*      Read a group of records that form a single feature.             */
    1371                 : /************************************************************************/
    1372                 : 
    1373          133933 : NTFRecord **NTFFileReader::ReadRecordGroup()
    1374                 : 
    1375                 : {
    1376                 :    NTFRecord     *poRecord;
    1377          133933 :    int            nRecordCount = 0;
    1378                 : 
    1379          133933 :    ClearCGroup();
    1380                 :    
    1381                 : /* -------------------------------------------------------------------- */
    1382                 : /*      Loop, reading records till we think we have a grouping.         */
    1383                 : /* -------------------------------------------------------------------- */
    1384          588805 :    while( (poRecord = ReadRecord()) != NULL && poRecord->GetType() != NRT_VTR )
    1385                 :    {
    1386          454856 :        CPLAssert( nRecordCount < MAX_REC_GROUP);
    1387          454856 :        if( nRecordCount >= MAX_REC_GROUP )
    1388                 :        {
    1389                 :            CPLError( CE_Failure, CPLE_AppDefined, 
    1390                 :                      "Maximum record group size (%d) exceeded.\n", 
    1391               0 :                      MAX_REC_GROUP );
    1392               0 :            break;
    1393                 :        }
    1394                 : 
    1395          454856 :        if( !pfnRecordGrouper( this, apoCGroup, poRecord ) )
    1396          133917 :            break;
    1397                 :        
    1398          320939 :        apoCGroup[nRecordCount++] = poRecord;
    1399          320939 :        apoCGroup[nRecordCount] = NULL;
    1400                 :    }
    1401                 :    
    1402                 : /* -------------------------------------------------------------------- */
    1403                 : /*      Push the last record back on the input queue.                   */
    1404                 : /* -------------------------------------------------------------------- */
    1405          133933 :    if( poRecord != NULL )
    1406          133933 :        SaveRecord( poRecord );
    1407                 : 
    1408                 : /* -------------------------------------------------------------------- */
    1409                 : /*      Return the list, or NULL if we didn't get any records.          */
    1410                 : /* -------------------------------------------------------------------- */
    1411          133933 :    if( nRecordCount == 0 )
    1412               8 :        return NULL;
    1413                 :    else
    1414          133925 :        return apoCGroup;
    1415                 : }
    1416                 : 
    1417                 : /************************************************************************/
    1418                 : /*                          GetFeatureClass()                           */
    1419                 : /************************************************************************/
    1420                 : 
    1421                 : int NTFFileReader::GetFeatureClass( int iFCIndex,
    1422                 :                                     char ** ppszFCId,
    1423             274 :                                     char ** ppszFCName )
    1424                 : 
    1425                 : {
    1426             274 :     if( iFCIndex < 0 || iFCIndex >= nFCCount )
    1427                 :     {
    1428               0 :         *ppszFCId = NULL;
    1429               0 :         *ppszFCName = NULL;
    1430               0 :         return FALSE;
    1431                 :     }
    1432                 :     else
    1433                 :     {
    1434             274 :         *ppszFCId   = papszFCNum[iFCIndex];
    1435             274 :         *ppszFCName = papszFCName[iFCIndex];
    1436             274 :         return TRUE;
    1437                 :     }
    1438                 : }
    1439                 : 
    1440                 : /************************************************************************/
    1441                 : /*                           ReadOGRFeature()                           */
    1442                 : /************************************************************************/
    1443                 : 
    1444           31224 : OGRFeature * NTFFileReader::ReadOGRFeature( OGRNTFLayer * poTargetLayer )
    1445                 : 
    1446                 : {
    1447           31224 :     OGRNTFLayer *poLayer = NULL;
    1448                 :     NTFRecord   **papoGroup;
    1449           31224 :     OGRFeature  *poFeature = NULL;
    1450                 : 
    1451                 : /* -------------------------------------------------------------------- */
    1452                 : /*      If this is a raster file, use a custom method to read the       */
    1453                 : /*      feature.                                                        */
    1454                 : /* -------------------------------------------------------------------- */
    1455           31224 :     if( IsRasterProduct() )
    1456               0 :         return poRasterLayer->GetNextFeature();
    1457                 : 
    1458                 : /* -------------------------------------------------------------------- */
    1459                 : /*      Loop looking for a group we can translate, and that if          */
    1460                 : /*      needed matches our layer request.                               */
    1461                 : /* -------------------------------------------------------------------- */
    1462          102709 :     while( TRUE )
    1463                 :     {
    1464          133933 :         if( GetProductId() == NPC_UNKNOWN && nNTFLevel > 2 )
    1465               0 :             papoGroup = GetNextIndexedRecordGroup( apoCGroup + 1 );
    1466                 :         else
    1467          133933 :             papoGroup = ReadRecordGroup();
    1468                 : 
    1469          133933 :         if( papoGroup == NULL )
    1470               8 :             break;
    1471                 :         
    1472          133925 :         poLayer = apoTypeTranslation[papoGroup[0]->GetType()];
    1473          133925 :         if( poLayer == NULL )
    1474             234 :             continue;
    1475                 : 
    1476          133691 :         if( poTargetLayer != NULL && poTargetLayer != poLayer )
    1477                 :         {
    1478          102475 :             CacheLineGeometryInGroup( papoGroup );
    1479          102475 :             nSavedFeatureId++;
    1480          102475 :             continue;
    1481                 :         }
    1482                 : 
    1483           31216 :         poFeature = poLayer->FeatureTranslate( this, papoGroup );
    1484           31216 :         if( poFeature == NULL )
    1485                 :         {
    1486                 :             // should this be a real error?
    1487                 :             CPLDebug( "NTF",
    1488                 :                       "FeatureTranslate() failed for a type %d record group\n"
    1489                 :                       "in a %s type file.\n",
    1490                 :                       papoGroup[0]->GetType(),
    1491               0 :                       GetProduct() );
    1492                 :         }
    1493                 :         else
    1494           31216 :             break;
    1495                 :     }
    1496                 : 
    1497                 : /* -------------------------------------------------------------------- */
    1498                 : /*      If we got a feature, set the TILE_REF on it.                    */
    1499                 : /* -------------------------------------------------------------------- */
    1500           31224 :     if( poFeature != NULL )
    1501                 :     {
    1502                 :         int             iTileRefField;
    1503                 : 
    1504           31216 :         iTileRefField = poLayer->GetLayerDefn()->GetFieldCount()-1;
    1505                 :     
    1506           31216 :         CPLAssert( EQUAL(poLayer->GetLayerDefn()->GetFieldDefn(iTileRefField)->
    1507                 :                          GetNameRef(), "TILE_REF") );
    1508                 : 
    1509           31216 :         poFeature->SetField( iTileRefField, GetTileName() );
    1510           31216 :         poFeature->SetFID( nSavedFeatureId );
    1511                 : 
    1512           31216 :         nSavedFeatureId++;
    1513                 :     }
    1514                 : 
    1515                 : /* -------------------------------------------------------------------- */
    1516                 : /*      If we got to the end we can establish our feature count for     */
    1517                 : /*      the file.                                                       */
    1518                 : /* -------------------------------------------------------------------- */
    1519                 :     else
    1520                 :     {
    1521               8 :         CPLAssert( nFeatureCount == -1
    1522                 :                    || nFeatureCount == nSavedFeatureId - nBaseFeatureId );
    1523               8 :         nFeatureCount = nSavedFeatureId - nBaseFeatureId;
    1524                 :     }
    1525                 : 
    1526           31224 :     return( poFeature );
    1527                 : }
    1528                 : 
    1529                 : /************************************************************************/
    1530                 : /*                            TestForLayer()                            */
    1531                 : /*                                                                      */
    1532                 : /*      Return indicator of whether this file contains any features     */
    1533                 : /*      of the indicated layer type.                                    */
    1534                 : /************************************************************************/
    1535                 : 
    1536               0 : int NTFFileReader::TestForLayer( OGRNTFLayer * poLayer )
    1537                 : 
    1538                 : {
    1539               0 :     for( int i = 0; i < 100; i++ )
    1540                 :     {
    1541               0 :         if( apoTypeTranslation[i] == poLayer )
    1542               0 :             return TRUE;
    1543                 :     }
    1544                 : 
    1545               0 :     return FALSE;
    1546                 : }
    1547                 : 
    1548                 : /************************************************************************/
    1549                 : /*                            FreshenIndex()                            */
    1550                 : /*                                                                      */
    1551                 : /*      Rebuild the index if it is needed, and currently missing.       */
    1552                 : /************************************************************************/
    1553                 : 
    1554               0 : void NTFFileReader::FreshenIndex()
    1555                 : 
    1556                 : {
    1557               0 :     if( !bIndexBuilt && bIndexNeeded )
    1558               0 :         IndexFile();
    1559               0 : }
    1560                 : 
    1561                 : /************************************************************************/
    1562                 : /*                             IndexFile()                              */
    1563                 : /*                                                                      */
    1564                 : /*      Read all records beyond the section header and build an         */
    1565                 : /*      internal index of them.                                         */
    1566                 : /************************************************************************/
    1567                 : 
    1568               0 : void NTFFileReader::IndexFile()
    1569                 : 
    1570                 : {
    1571                 :     NTFRecord   *poRecord;
    1572                 :     
    1573               0 :     Reset();
    1574                 : 
    1575               0 :     DestroyIndex();
    1576                 : 
    1577               0 :     bIndexNeeded = TRUE;
    1578               0 :     bIndexBuilt = TRUE;
    1579               0 :     bCacheLines = FALSE;
    1580                 : 
    1581                 : /* -------------------------------------------------------------------- */
    1582                 : /*      Process all records after the section header, and before 99     */
    1583                 : /*      to put them in the index.                                       */
    1584                 : /* -------------------------------------------------------------------- */
    1585               0 :     while( (poRecord = ReadRecord()) != NULL && poRecord->GetType() != 99 )
    1586                 :     {
    1587               0 :         int     iType = poRecord->GetType();
    1588               0 :         int     iId = atoi(poRecord->GetField( 3, 8 ));
    1589                 : 
    1590               0 :         if( iType < 0 || iType >= 100 )
    1591                 :         {
    1592                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    1593                 :                       "Illegal type %d record, skipping.", 
    1594               0 :                       iType );
    1595               0 :             delete poRecord;
    1596               0 :             continue;
    1597                 :         }
    1598                 : 
    1599                 : /* -------------------------------------------------------------------- */
    1600                 : /*      Grow type specific subindex if needed.                          */
    1601                 : /* -------------------------------------------------------------------- */
    1602               0 :         if( anIndexSize[iType] <= iId )
    1603                 :         {
    1604               0 :             int nNewSize = MAX(iId+1,anIndexSize[iType] * 2 + 10);
    1605                 : 
    1606                 :             apapoRecordIndex[iType] = (NTFRecord **)
    1607                 :                 CPLRealloc(apapoRecordIndex[iType],
    1608               0 :                            sizeof(void *) * nNewSize);
    1609                 : 
    1610               0 :             for( int i = anIndexSize[iType]; i < nNewSize; i++ )
    1611               0 :                 (apapoRecordIndex[iType])[i] = NULL;
    1612                 : 
    1613               0 :             anIndexSize[iType] = nNewSize;
    1614                 :         }
    1615                 : 
    1616                 : /* -------------------------------------------------------------------- */
    1617                 : /*      Put record into type specific subindex based on it's id as      */
    1618                 : /*      the key.                                                        */
    1619                 : /* -------------------------------------------------------------------- */
    1620               0 :         if( apapoRecordIndex[iType][iId] != NULL )
    1621                 :         {
    1622                 :             CPLDebug( "OGR_NTF", 
    1623                 :                       "Duplicate record with index %d and type %d\n"
    1624                 :                       "in NTFFileReader::IndexFile().",
    1625               0 :                       iId, iType );
    1626               0 :             delete apapoRecordIndex[iType][iId];
    1627                 :         }
    1628               0 :         (apapoRecordIndex[iType])[iId] = poRecord;
    1629                 :     }
    1630                 : 
    1631               0 :     if( poRecord != NULL )
    1632               0 :         delete poRecord;
    1633               0 : }
    1634                 : 
    1635                 : /************************************************************************/
    1636                 : /*                            DestroyIndex()                            */
    1637                 : /************************************************************************/
    1638                 : 
    1639               2 : void NTFFileReader::DestroyIndex()
    1640                 : 
    1641                 : {
    1642             202 :     for( int i = 0; i < 100; i++ )
    1643                 :     {
    1644             200 :         for( int iId = 0; iId < anIndexSize[i]; iId++ )
    1645                 :         {
    1646               0 :             if( (apapoRecordIndex[i])[iId] != NULL )
    1647               0 :                 delete (apapoRecordIndex[i])[iId];
    1648                 :         }
    1649                 : 
    1650             200 :         CPLFree( apapoRecordIndex[i] );
    1651             200 :         apapoRecordIndex[i] = NULL;
    1652             200 :         anIndexSize[i] = 0;
    1653                 :     }
    1654                 : 
    1655               2 :     bIndexBuilt = FALSE;
    1656               2 : }
    1657                 : 
    1658                 : /************************************************************************/
    1659                 : /*                          GetIndexedRecord()                          */
    1660                 : /************************************************************************/
    1661                 : 
    1662               0 : NTFRecord * NTFFileReader::GetIndexedRecord( int iType, int iId )
    1663                 : 
    1664                 : {
    1665               0 :     if( (iType < 0 || iType > 99)
    1666                 :         || (iId < 0 || iId >= anIndexSize[iType]) 
    1667                 :         || (apapoRecordIndex[iType])[iId] == NULL )
    1668                 :     {
    1669                 :         /* If NRT_GEOMETRY3D is an acceptable alternative to 2D */
    1670               0 :         if( iType == NRT_GEOMETRY )
    1671               0 :             return GetIndexedRecord( NRT_GEOMETRY3D, iId );
    1672                 :         else
    1673               0 :             return NULL;
    1674                 :     }
    1675                 : 
    1676               0 :     return (apapoRecordIndex[iType])[iId];
    1677                 : }
    1678                 : 
    1679                 : /************************************************************************/
    1680                 : /*                          AddToIndexGroup()                           */
    1681                 : /************************************************************************/
    1682                 : 
    1683               0 : static void AddToIndexGroup( NTFRecord **papoGroup, NTFRecord * poRecord )
    1684                 : 
    1685                 : {
    1686                 :     int         i;
    1687                 :     
    1688               0 :     for( i = 1; papoGroup[i] != NULL; i++ ) {}
    1689                 : 
    1690               0 :     papoGroup[i] = poRecord;
    1691               0 :     papoGroup[i+1] = NULL;
    1692               0 : }
    1693                 : 
    1694                 : 
    1695                 : /************************************************************************/
    1696                 : /*                     GetNextIndexedRecordGroup()                      */
    1697                 : /************************************************************************/
    1698                 : 
    1699                 : NTFRecord **NTFFileReader::GetNextIndexedRecordGroup( NTFRecord **
    1700               0 :                                                       papoPrevGroup )
    1701                 : 
    1702                 : {
    1703                 :     int         nPrevType, nPrevId;
    1704                 : 
    1705                 : /* -------------------------------------------------------------------- */
    1706                 : /*      What was the identify of our previous anchor record?            */
    1707                 : /* -------------------------------------------------------------------- */
    1708               0 :     if( papoPrevGroup == NULL || papoPrevGroup[0] == NULL )
    1709                 :     {
    1710               0 :         nPrevType = NRT_POINTREC;
    1711               0 :         nPrevId = 0;
    1712               0 :         FreshenIndex();
    1713                 :     }
    1714                 :     else
    1715                 :     {
    1716               0 :         nPrevType = papoPrevGroup[0]->GetType();
    1717               0 :         nPrevId = atoi(papoPrevGroup[0]->GetField(3,8));
    1718                 :     }
    1719                 : 
    1720                 : /* -------------------------------------------------------------------- */
    1721                 : /*      Find the next anchor record.                                    */
    1722                 : /* -------------------------------------------------------------------- */
    1723               0 :     NTFRecord   *poAnchor = NULL;
    1724                 :     
    1725               0 :     while( nPrevType != 99 && poAnchor == NULL )
    1726                 :     {
    1727               0 :         nPrevId++;
    1728               0 :         if( nPrevId >= anIndexSize[nPrevType] )
    1729                 :         {
    1730               0 :             do
    1731                 :             {
    1732               0 :                 nPrevType++;
    1733                 :             }
    1734                 :             while( nPrevType != NRT_VTR
    1735                 :                    && nPrevType != NRT_NODEREC
    1736                 :                    && nPrevType != NRT_TEXTREC
    1737                 :                    && nPrevType != NRT_NAMEREC
    1738                 :                    && nPrevType != NRT_COLLECT
    1739                 :                    && nPrevType != NRT_POLYGON
    1740                 :                    && nPrevType != NRT_CPOLY
    1741                 :                    && nPrevType != NRT_POINTREC
    1742                 :                    && nPrevType != NRT_LINEREC );
    1743                 :             
    1744               0 :             nPrevId = 0;
    1745                 :         }
    1746                 :         else
    1747                 :         {
    1748               0 :             poAnchor = (apapoRecordIndex[nPrevType])[nPrevId];
    1749                 :         }
    1750                 :     }
    1751                 : 
    1752               0 :     if( poAnchor == NULL )
    1753                 :     {
    1754               0 :         return NULL;
    1755                 :     }
    1756                 : 
    1757                 : /* -------------------------------------------------------------------- */
    1758                 : /*      Build record group depending on type of anchor and what it      */
    1759                 : /*      refers to.                                                      */
    1760                 : /* -------------------------------------------------------------------- */
    1761               0 :     apoCGroup[0] = NULL;
    1762               0 :     apoCGroup[1] = poAnchor;
    1763               0 :     apoCGroup[2] = NULL;
    1764                 : 
    1765                 : /* -------------------------------------------------------------------- */
    1766                 : /*      Handle POINTREC/LINEREC                                         */
    1767                 : /* -------------------------------------------------------------------- */
    1768               0 :     if( poAnchor->GetType() == NRT_POINTREC
    1769                 :          || poAnchor->GetType() == NRT_LINEREC )
    1770                 :     {
    1771               0 :         int             nAttCount = 0;
    1772                 :         
    1773                 :         AddToIndexGroup( apoCGroup,
    1774                 :                          GetIndexedRecord( NRT_GEOMETRY,
    1775               0 :                                            atoi(poAnchor->GetField(9,14)) ) );
    1776                 : 
    1777               0 :         if( poAnchor->GetLength() >= 16 )
    1778               0 :             nAttCount = atoi(poAnchor->GetField(15,16));
    1779                 : 
    1780               0 :         for( int iAtt = 0; iAtt < nAttCount; iAtt++ )
    1781                 :         {
    1782                 :             AddToIndexGroup(
    1783                 :                 apoCGroup,
    1784                 :                 GetIndexedRecord( NRT_ATTREC,
    1785                 :                                   atoi(poAnchor->GetField(17+6*iAtt,
    1786               0 :                                                           22+6*iAtt)) ) );
    1787                 :         }
    1788                 :     }
    1789                 : 
    1790                 : /* -------------------------------------------------------------------- */
    1791                 : /*      Handle TEXTREC                                                  */
    1792                 : /* -------------------------------------------------------------------- */
    1793               0 :     else if( poAnchor->GetType() == NRT_TEXTREC )
    1794                 :     {
    1795               0 :         int             nAttCount = 0;
    1796               0 :         int             nSelCount = 0;
    1797                 : 
    1798                 :         // Add all the text position records.
    1799               0 :         nSelCount = atoi(poAnchor->GetField(9,10));
    1800                 :         
    1801               0 :         for( int iSel = 0; iSel < nSelCount; iSel++ )
    1802                 :         {
    1803               0 :             int iStart = 11 + 12*iSel + 6;
    1804                 :             
    1805                 :             AddToIndexGroup(
    1806                 :                 apoCGroup,
    1807                 :                 GetIndexedRecord( NRT_TEXTPOS,
    1808               0 :                                   atoi(poAnchor->GetField(iStart,iStart+5)) ));
    1809                 :         }
    1810                 : 
    1811                 :         // Add all geometry and TEXR records pointed to by text position
    1812                 :         // records.
    1813               0 :         for( int iRec = 1; apoCGroup[iRec] != NULL; iRec++ )
    1814                 :         {
    1815                 :             int         nNumTEXR;
    1816               0 :             NTFRecord  *poRecord = apoCGroup[iRec];
    1817                 :             
    1818               0 :             if( poRecord->GetType() != NRT_TEXTPOS )
    1819               0 :                 continue;
    1820                 : 
    1821               0 :             nNumTEXR = atoi(poRecord->GetField(9,10));
    1822               0 :             for( int iTEXR = 0; iTEXR < nNumTEXR; iTEXR++ )
    1823                 :             {
    1824                 :                 AddToIndexGroup(
    1825                 :                     apoCGroup,
    1826                 :                     GetIndexedRecord( NRT_TEXTREP,
    1827                 :                                       atoi(poRecord->GetField(11+iTEXR*12,
    1828               0 :                                                               16+iTEXR*12))));
    1829                 :                 AddToIndexGroup(
    1830                 :                     apoCGroup,
    1831                 :                     GetIndexedRecord( NRT_GEOMETRY,
    1832                 :                                       atoi(poRecord->GetField(17+iTEXR*12,
    1833               0 :                                                               22+iTEXR*12))));
    1834                 :             }
    1835                 :         }
    1836                 :         
    1837                 :         // Add all the attribute records.
    1838               0 :         if( poAnchor->GetLength() >= 10 + nSelCount*12 + 2 )
    1839                 :             nAttCount = atoi(poAnchor->GetField(11+nSelCount*12,
    1840               0 :                                                 12+nSelCount*12));
    1841                 : 
    1842               0 :         for( int iAtt = 0; iAtt < nAttCount; iAtt++ )
    1843                 :         {
    1844               0 :             int iStart = 13 + nSelCount*12 + 6 * iAtt;
    1845                 :             
    1846                 :             AddToIndexGroup(
    1847                 :                 apoCGroup,
    1848                 :                 GetIndexedRecord( NRT_ATTREC,
    1849               0 :                                   atoi(poAnchor->GetField(iStart,iStart+5)) ));
    1850                 :         }
    1851                 : 
    1852                 :     }
    1853                 : 
    1854                 : /* -------------------------------------------------------------------- */
    1855                 : /*      Handle NODEREC.                                                 */
    1856                 : /* -------------------------------------------------------------------- */
    1857               0 :     else if( poAnchor->GetType() == NRT_NODEREC )
    1858                 :     {
    1859                 :         AddToIndexGroup( apoCGroup,
    1860                 :                          GetIndexedRecord( NRT_GEOMETRY,
    1861               0 :                                            atoi(poAnchor->GetField(9,14)) ) );
    1862                 :     }
    1863                 : 
    1864                 : /* -------------------------------------------------------------------- */
    1865                 : /*      Handle COLLECT.                                                 */
    1866                 : /* -------------------------------------------------------------------- */
    1867               0 :     else if( poAnchor->GetType() == NRT_COLLECT )
    1868                 :     {
    1869               0 :         int     nParts = atoi(poAnchor->GetField(9,12));
    1870               0 :         int     nAttOffset = 13 + nParts * 8;
    1871               0 :         int     nAttCount = 0;
    1872                 :         
    1873               0 :         if( poAnchor->GetLength() > nAttOffset + 2 )
    1874               0 :             nAttCount = atoi(poAnchor->GetField(nAttOffset,nAttOffset+1));
    1875                 : 
    1876               0 :         for( int iAtt = 0; iAtt < nAttCount; iAtt++ )
    1877                 :         {
    1878               0 :             int iStart = nAttOffset + 2 + iAtt * 6;
    1879                 :             
    1880                 :             AddToIndexGroup(
    1881                 :                 apoCGroup,
    1882                 :                 GetIndexedRecord( NRT_ATTREC,
    1883               0 :                                   atoi(poAnchor->GetField(iStart,iStart+5)) ));
    1884                 :         }
    1885                 :     }
    1886                 : 
    1887                 : /* -------------------------------------------------------------------- */
    1888                 : /*      Handle POLYGON                                                  */
    1889                 : /* -------------------------------------------------------------------- */
    1890               0 :     else if( poAnchor->GetType() == NRT_POLYGON )
    1891                 :     {
    1892                 :         AddToIndexGroup( apoCGroup,
    1893                 :                          GetIndexedRecord( NRT_CHAIN,
    1894               0 :                                            atoi(poAnchor->GetField(9,14)) ) );
    1895                 : 
    1896               0 :         if( poAnchor->GetLength() >= 20 )
    1897                 :             AddToIndexGroup( apoCGroup,
    1898                 :                         GetIndexedRecord( NRT_GEOMETRY,
    1899               0 :                                           atoi(poAnchor->GetField(15,20)) ) );
    1900                 : 
    1901                 :         // Attributes
    1902                 :         
    1903               0 :         int     nAttCount = 0;
    1904                 :         
    1905               0 :         if( poAnchor->GetLength() >= 22 )
    1906               0 :             nAttCount = atoi(poAnchor->GetField(21,22));
    1907                 : 
    1908               0 :         for( int iAtt = 0; iAtt < nAttCount; iAtt++ )
    1909                 :         {
    1910                 :             AddToIndexGroup(
    1911                 :                 apoCGroup,
    1912                 :                 GetIndexedRecord( NRT_ATTREC,
    1913                 :                                   atoi(poAnchor->GetField(23+6*iAtt,
    1914               0 :                                                           28+6*iAtt)) ) );
    1915                 :         }
    1916                 :     }
    1917                 : /* -------------------------------------------------------------------- */
    1918                 : /*      Handle CPOLY                                                    */
    1919                 : /* -------------------------------------------------------------------- */
    1920               0 :     else if( poAnchor->GetType() == NRT_CPOLY )
    1921                 :     {
    1922               0 :         int     nPolyCount = atoi(poAnchor->GetField(9,12));
    1923               0 :         int     nPostPoly = nPolyCount*7 + 12;
    1924                 : 
    1925               0 :         if( poAnchor->GetLength() >= nPostPoly + 6 )
    1926                 :         {
    1927               0 :             int  nGeomId = atoi(poAnchor->GetField(nPostPoly+1,nPostPoly+6));
    1928                 : 
    1929                 :             AddToIndexGroup( apoCGroup, 
    1930               0 :                              GetIndexedRecord( NRT_GEOMETRY, nGeomId) );
    1931                 :         }
    1932                 : 
    1933               0 :         if( poAnchor->GetLength() >= nPostPoly + 8 )
    1934                 :         {
    1935               0 :             int nAttCount = atoi(poAnchor->GetField(nPostPoly+7,nPostPoly+8));
    1936                 :             
    1937               0 :             for( int iAtt = 0; iAtt < nAttCount; iAtt++ )
    1938                 :             {
    1939                 :                 int nAttId = atoi(poAnchor->GetField(nPostPoly+9+iAtt*6,
    1940               0 :                                                      nPostPoly+14+iAtt*6));
    1941                 :                 AddToIndexGroup( apoCGroup, 
    1942               0 :                                  GetIndexedRecord( NRT_ATTREC, nAttId) );
    1943                 :             }
    1944                 :         }
    1945                 :     }
    1946                 : 
    1947               0 :     return apoCGroup + 1;
    1948                 : }
    1949                 : 
    1950                 : /************************************************************************/
    1951                 : /*                          OverrideTileName()                          */
    1952                 : /************************************************************************/
    1953                 : 
    1954               0 : void NTFFileReader::OverrideTileName( const char *pszNewName )
    1955                 : 
    1956                 : {
    1957               0 :     CPLFree( pszTileName );
    1958               0 :     pszTileName = CPLStrdup( pszNewName );
    1959               0 : }
    1960                 : 
    1961                 : /************************************************************************/
    1962                 : /*                          CacheAddByGeomId()                          */
    1963                 : /*                                                                      */
    1964                 : /*      Add a geometry to the geometry cache given it's GEOMID as       */
    1965                 : /*      the index.                                                      */
    1966                 : /************************************************************************/
    1967                 : 
    1968            8883 : void NTFFileReader::CacheAddByGeomId( int nGeomId, OGRGeometry *poGeometry )
    1969                 : 
    1970                 : {
    1971            8883 :     if( !bCacheLines )
    1972            8883 :         return;
    1973                 : 
    1974               0 :     CPLAssert( nGeomId >= 0 );
    1975                 : 
    1976                 : /* -------------------------------------------------------------------- */
    1977                 : /*      Grow the cache if it isn't large enough to hold the newly       */
    1978                 : /*      requested geometry id.                                          */
    1979                 : /* -------------------------------------------------------------------- */
    1980               0 :     if( nGeomId >= nLineCacheSize )
    1981                 :     {
    1982               0 :         int     nNewSize = nGeomId + 100;
    1983                 : 
    1984                 :         papoLineCache = (OGRGeometry **) 
    1985               0 :             CPLRealloc( papoLineCache, sizeof(void*) * nNewSize );
    1986                 :         memset( papoLineCache + nLineCacheSize, 0, 
    1987               0 :                 sizeof(void*) * (nNewSize - nLineCacheSize) );
    1988               0 :         nLineCacheSize = nNewSize;
    1989                 :     }
    1990                 : 
    1991                 : /* -------------------------------------------------------------------- */
    1992                 : /*      Make a cloned copy of the geometry for the cache.               */
    1993                 : /* -------------------------------------------------------------------- */
    1994               0 :     if( papoLineCache[nGeomId] != NULL )
    1995               0 :         return;
    1996                 : 
    1997               0 :     papoLineCache[nGeomId] = poGeometry->clone();
    1998                 : }
    1999                 : 
    2000                 : /************************************************************************/
    2001                 : /*                          CacheGetByGeomId()                          */
    2002                 : /************************************************************************/
    2003                 : 
    2004               0 : OGRGeometry *NTFFileReader::CacheGetByGeomId( int nGeomId )
    2005                 : 
    2006                 : {
    2007               0 :     if( nGeomId < 0 || nGeomId >= nLineCacheSize )
    2008               0 :         return NULL;
    2009                 :     else
    2010               0 :         return papoLineCache[nGeomId];
    2011                 : }
    2012                 : 
    2013                 : /************************************************************************/
    2014                 : /*                             CacheClean()                             */
    2015                 : /************************************************************************/
    2016                 : 
    2017              26 : void NTFFileReader::CacheClean()
    2018                 : 
    2019                 : {
    2020              26 :     for( int i = 0; i < nLineCacheSize; i++ )
    2021                 :     {
    2022               0 :         if( papoLineCache[i] != NULL )
    2023               0 :             delete papoLineCache[i];
    2024                 :     }
    2025              26 :     if( papoLineCache != NULL )
    2026               0 :         CPLFree( papoLineCache );
    2027                 : 
    2028              26 :     nLineCacheSize = 0;
    2029              26 :     papoLineCache = NULL;
    2030              26 : }
    2031                 : 
    2032                 : /************************************************************************/
    2033                 : /*                      CacheLineGeometryInGroup()                      */
    2034                 : /*                                                                      */
    2035                 : /*      Run any line geometries in this group through the               */
    2036                 : /*      ProcessGeometry() call just to ensure the line geometry will    */
    2037                 : /*      be cached.                                                      */
    2038                 : /************************************************************************/
    2039                 : 
    2040          102475 : void NTFFileReader::CacheLineGeometryInGroup( NTFRecord **papoGroup )
    2041                 : 
    2042                 : {
    2043          102475 :     if( !bCacheLines )
    2044          102475 :         return;
    2045                 : 
    2046               0 :     for( int iRec = 0; papoGroup[iRec] != NULL; iRec++ )
    2047                 :     {
    2048               0 :         if( papoGroup[iRec]->GetType() == NRT_GEOMETRY
    2049                 :             || papoGroup[iRec]->GetType() == NRT_GEOMETRY3D )
    2050                 :         {
    2051               0 :             OGRGeometry *poGeom = ProcessGeometry( papoGroup[iRec], NULL );
    2052               0 :             if( poGeom != NULL )
    2053               0 :                 delete poGeom;
    2054                 :         }
    2055                 :     }
    2056                 : }
    2057                 : 
    2058                 : /************************************************************************/
    2059                 : /*                        FormPolygonFromCache()                        */
    2060                 : /*                                                                      */
    2061                 : /*      This method will attempt to find the line geometries            */
    2062                 : /*      referenced by the GEOM_ID_OF_LINK ids of a feature in the       */
    2063                 : /*      line cache (if available), and if so, assemble them into a      */
    2064                 : /*      polygon.                                                        */
    2065                 : /************************************************************************/
    2066                 : 
    2067               0 : int NTFFileReader::FormPolygonFromCache( OGRFeature * poFeature )
    2068                 : 
    2069                 : {
    2070               0 :     if( !bCacheLines )
    2071               0 :         return FALSE;
    2072                 : 
    2073               0 :     OGRGeometryCollection oLines;
    2074                 :     const int *panLinks;
    2075                 :     int        nLinkCount, i;
    2076                 : 
    2077                 : /* -------------------------------------------------------------------- */
    2078                 : /*      Collect all the linked lines.                                   */
    2079                 : /* -------------------------------------------------------------------- */
    2080                 :     panLinks = poFeature->GetFieldAsIntegerList( "GEOM_ID_OF_LINK", 
    2081               0 :                                                  &nLinkCount );
    2082                 : 
    2083               0 :     if( panLinks == NULL )
    2084               0 :         return FALSE;
    2085                 : 
    2086               0 :     for( i = 0; i < nLinkCount; i++ )
    2087                 :     {
    2088               0 :         OGRGeometry *poLine = CacheGetByGeomId( panLinks[i] );
    2089               0 :         if( poLine == NULL )
    2090                 :         {
    2091               0 :             oLines.removeGeometry( -1, FALSE );
    2092               0 :             return FALSE;
    2093                 :         }
    2094                 : 
    2095               0 :         oLines.addGeometryDirectly( poLine );
    2096                 :     }
    2097                 : 
    2098                 : /* -------------------------------------------------------------------- */
    2099                 : /*      Assemble into a polygon geometry.                               */
    2100                 : /* -------------------------------------------------------------------- */
    2101                 :     OGRPolygon *poPoly;
    2102                 : 
    2103                 :     poPoly = (OGRPolygon *) 
    2104                 :         OGRBuildPolygonFromEdges( (OGRGeometryH) &oLines, FALSE, FALSE, 0.1, 
    2105               0 :                                   NULL );
    2106                 : 
    2107               0 :     poFeature->SetGeometryDirectly( poPoly );
    2108                 : 
    2109               0 :     oLines.removeGeometry( -1, FALSE );
    2110                 :     
    2111               0 :     return poPoly != NULL;
    2112                 : }

Generated by: LTP GCOV extension version 1.5