LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/ntf - ntffilereader.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 782 424 54.2 %
Date: 2013-03-30 Functions: 41 28 68.3 %

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

Generated by: LCOV version 1.7