LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/ntf - ogrntfdatasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 49 192 25.5 %
Date: 2024-11-25 13:07:18 Functions: 4 15 26.7 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  UK NTF Reader
       4             :  * Purpose:  Implements OGRNTFDataSource class
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1999, Frank Warmerdam
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "ntf.h"
      14             : #include "cpl_conv.h"
      15             : #include "cpl_string.h"
      16             : 
      17             : /************************************************************************/
      18             : /*                          OGRNTFDataSource()                          */
      19             : /************************************************************************/
      20             : 
      21         708 : OGRNTFDataSource::OGRNTFDataSource()
      22             :     : nLayers(0), papoLayers(nullptr), poFCLayer(nullptr), iCurrentFC(0),
      23             :       iCurrentReader(-1), nCurrentPos(0), nCurrentFID(0), nNTFFileCount(0),
      24             :       papoNTFFileReader(nullptr), nFCCount(0), papszFCNum(nullptr),
      25             :       papszFCName(nullptr),
      26             :       poSpatialRef(new OGRSpatialReference(
      27             :           "PROJCS[\"OSGB 1936 / British National Grid\",GEOGCS[\"OSGB 1936\","
      28             :           "DATUM[\"OSGB_1936\",SPHEROID[\"Airy 1830\",6377563.396,299.3249646,"
      29             :           "AUTHORITY[\"EPSG\",\"7001\"]],AUTHORITY[\"EPSG\",\"6277\"]],"
      30             :           "PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],"
      31             :           "UNIT[\"degree\",0.0174532925199433],AUTHORITY[\"EPSG\",\"4277\"]],"
      32             :           "PROJECTION[\"Transverse_Mercator\"],"
      33             :           "PARAMETER[\"latitude_of_origin\",49],"
      34             :           "PARAMETER[\"central_meridian\",-2],"
      35             :           "PARAMETER[\"scale_factor\",0.999601272],"
      36             :           "PARAMETER[\"false_easting\",400000],"
      37             :           "PARAMETER[\"false_northing\",-100000],"
      38             :           "UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],"
      39         708 :           "AUTHORITY[\"EPSG\",\"27700\"]]")),
      40       72216 :       papszOptions(nullptr)
      41             : {
      42         708 :     poSpatialRef->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
      43             : 
      44             :     /* -------------------------------------------------------------------- */
      45             :     /*      Allow initialization of options from the environment.           */
      46             :     /* -------------------------------------------------------------------- */
      47         708 :     if (getenv("OGR_NTF_OPTIONS") != nullptr)
      48             :     {
      49           0 :         papszOptions = CSLTokenizeStringComplex(getenv("OGR_NTF_OPTIONS"), ",",
      50             :                                                 FALSE, FALSE);
      51             :     }
      52         708 : }
      53             : 
      54             : /************************************************************************/
      55             : /*                         ~OGRNTFDataSource()                          */
      56             : /************************************************************************/
      57             : 
      58       72216 : OGRNTFDataSource::~OGRNTFDataSource()
      59             : 
      60             : {
      61         708 :     for (int i = 0; i < nNTFFileCount; i++)
      62           0 :         delete papoNTFFileReader[i];
      63             : 
      64         708 :     CPLFree(papoNTFFileReader);
      65             : 
      66         708 :     for (int i = 0; i < nLayers; i++)
      67           0 :         delete papoLayers[i];
      68             : 
      69         708 :     if (poFCLayer != nullptr)
      70           0 :         delete poFCLayer;
      71             : 
      72         708 :     CPLFree(papoLayers);
      73             : 
      74         708 :     CSLDestroy(papszOptions);
      75             : 
      76         708 :     CSLDestroy(papszFCNum);
      77         708 :     CSLDestroy(papszFCName);
      78             : 
      79         708 :     if (poSpatialRef)
      80         708 :         poSpatialRef->Release();
      81        1416 : }
      82             : 
      83             : /************************************************************************/
      84             : /*                           TestCapability()                           */
      85             : /************************************************************************/
      86             : 
      87           0 : int OGRNTFDataSource::TestCapability(const char *pszCap)
      88             : 
      89             : {
      90           0 :     if (EQUAL(pszCap, ODsCZGeometries))
      91           0 :         return true;
      92             : 
      93           0 :     return false;
      94             : }
      95             : 
      96             : /************************************************************************/
      97             : /*                           GetNamedLayer()                            */
      98             : /************************************************************************/
      99             : 
     100           0 : OGRNTFLayer *OGRNTFDataSource::GetNamedLayer(const char *pszNameIn)
     101             : 
     102             : {
     103           0 :     for (int i = 0; i < nLayers; i++)
     104             :     {
     105           0 :         if (EQUAL(papoLayers[i]->GetLayerDefn()->GetName(), pszNameIn))
     106           0 :             return static_cast<OGRNTFLayer *>(papoLayers[i]);
     107             :     }
     108             : 
     109           0 :     return nullptr;
     110             : }
     111             : 
     112             : /************************************************************************/
     113             : /*                              AddLayer()                              */
     114             : /************************************************************************/
     115             : 
     116           0 : void OGRNTFDataSource::AddLayer(OGRLayer *poNewLayer)
     117             : 
     118             : {
     119           0 :     papoLayers = static_cast<OGRLayer **>(
     120           0 :         CPLRealloc(papoLayers, sizeof(void *) * ++nLayers));
     121             : 
     122           0 :     papoLayers[nLayers - 1] = poNewLayer;
     123           0 : }
     124             : 
     125             : /************************************************************************/
     126             : /*                              GetLayer()                              */
     127             : /************************************************************************/
     128             : 
     129           0 : OGRLayer *OGRNTFDataSource::GetLayer(int iLayer)
     130             : 
     131             : {
     132           0 :     if (iLayer < 0 || iLayer > nLayers)
     133           0 :         return nullptr;
     134           0 :     else if (iLayer == nLayers)
     135           0 :         return poFCLayer;
     136             :     else
     137           0 :         return papoLayers[iLayer];
     138             : }
     139             : 
     140             : /************************************************************************/
     141             : /*                           GetLayerCount()                            */
     142             : /************************************************************************/
     143             : 
     144           0 : int OGRNTFDataSource::GetLayerCount()
     145             : 
     146             : {
     147           0 :     if (poFCLayer == nullptr)
     148           0 :         return nLayers;
     149             :     else
     150           0 :         return nLayers + 1;
     151             : }
     152             : 
     153             : /************************************************************************/
     154             : /*                                Open()                                */
     155             : /************************************************************************/
     156             : 
     157         708 : int OGRNTFDataSource::Open(const char *pszFilename, int bTestOpen,
     158             :                            char **papszLimitedFileList)
     159             : 
     160             : {
     161             :     VSIStatBufL stat;
     162         708 :     char **papszFileList = nullptr;
     163             : 
     164             :     /* -------------------------------------------------------------------- */
     165             :     /*      Is the given path a directory or a regular file?                */
     166             :     /* -------------------------------------------------------------------- */
     167        1416 :     if (VSIStatL(pszFilename, &stat) != 0 ||
     168         708 :         (!VSI_ISDIR(stat.st_mode) && !VSI_ISREG(stat.st_mode)))
     169             :     {
     170           0 :         if (!bTestOpen)
     171           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     172             :                      "%s is neither a file or directory, NTF access failed.\n",
     173             :                      pszFilename);
     174             : 
     175           0 :         return FALSE;
     176             :     }
     177             : 
     178             :     /* -------------------------------------------------------------------- */
     179             :     /*      Build a list of filenames we figure are NTF files.              */
     180             :     /* -------------------------------------------------------------------- */
     181         708 :     if (VSI_ISREG(stat.st_mode))
     182             :     {
     183          52 :         papszFileList = CSLAddString(nullptr, pszFilename);
     184             :     }
     185             :     else
     186             :     {
     187         656 :         char **candidateFileList = VSIReadDir(pszFilename);
     188             : 
     189       27772 :         for (int i = 0;
     190       27772 :              candidateFileList != nullptr && candidateFileList[i] != nullptr;
     191             :              i++)
     192             :         {
     193       27116 :             if (papszLimitedFileList != nullptr &&
     194           0 :                 CSLFindString(papszLimitedFileList, candidateFileList[i]) == -1)
     195             :             {
     196           0 :                 continue;
     197             :             }
     198             : 
     199       27116 :             if (strlen(candidateFileList[i]) > 4 &&
     200       25952 :                 STARTS_WITH_CI(candidateFileList[i] +
     201             :                                    strlen(candidateFileList[i]) - 4,
     202             :                                ".ntf"))
     203             :             {
     204             :                 char fullFilename[2048];
     205             : 
     206           0 :                 snprintf(fullFilename, sizeof(fullFilename), "%s%c%s",
     207             :                          pszFilename,
     208             : #ifdef _WIN32
     209             :                          '\\',
     210             : #else
     211             :                          '/',
     212             : #endif
     213           0 :                          candidateFileList[i]);
     214             : 
     215           0 :                 papszFileList = CSLAddString(papszFileList, fullFilename);
     216             :             }
     217             :         }
     218             : 
     219         656 :         CSLDestroy(candidateFileList);
     220             : 
     221         656 :         if (CSLCount(papszFileList) == 0)
     222             :         {
     223         656 :             if (!bTestOpen)
     224           0 :                 CPLError(CE_Failure, CPLE_OpenFailed,
     225             :                          "No candidate NTF files (.ntf) found in\n"
     226             :                          "directory: %s",
     227             :                          pszFilename);
     228         656 :             CSLDestroy(papszFileList);
     229         656 :             return FALSE;
     230             :         }
     231             :     }
     232             : 
     233             :     /* -------------------------------------------------------------------- */
     234             :     /*      Loop over all these files trying to open them.  In testopen     */
     235             :     /*      mode we first read the first 80 characters, to verify that      */
     236             :     /*      it looks like an NTF file.  Note that we don't keep the file    */
     237             :     /*      open ... we don't want to occupy a lot of file handles when      */
     238             :     /*      handling a whole directory.                                     */
     239             :     /* -------------------------------------------------------------------- */
     240          52 :     papoNTFFileReader = static_cast<NTFFileReader **>(
     241          52 :         CPLCalloc(sizeof(void *), CSLCount(papszFileList)));
     242             : 
     243         104 :     for (int i = 0; papszFileList != nullptr && papszFileList[i] != nullptr;
     244             :          i++)
     245             :     {
     246          52 :         if (bTestOpen)
     247             :         {
     248          52 :             VSILFILE *fp = VSIFOpenL(papszFileList[i], "rb");
     249          52 :             if (fp == nullptr)
     250          52 :                 continue;
     251             : 
     252          49 :             char szHeader[80] = {};
     253          49 :             if (VSIFReadL(szHeader, 80, 1, fp) < 1)
     254             :             {
     255          49 :                 VSIFCloseL(fp);
     256          49 :                 continue;
     257             :             }
     258             : 
     259           0 :             VSIFCloseL(fp);
     260             : 
     261           0 :             if (!STARTS_WITH_CI(szHeader, "01"))
     262           0 :                 continue;
     263             : 
     264           0 :             int j = 0;  // Used after for.
     265           0 :             for (; j < 80; j++)
     266             :             {
     267           0 :                 if (szHeader[j] == 10 || szHeader[j] == 13)
     268             :                     break;
     269             :             }
     270             : 
     271           0 :             if (j == 80 || (j > 0 && szHeader[j - 1] != '%'))
     272           0 :                 continue;
     273             :         }
     274             : 
     275           0 :         NTFFileReader *poFR = new NTFFileReader(this);
     276             : 
     277           0 :         if (!poFR->Open(papszFileList[i]))
     278             :         {
     279           0 :             delete poFR;
     280           0 :             CSLDestroy(papszFileList);
     281             : 
     282           0 :             return FALSE;
     283             :         }
     284             : 
     285           0 :         poFR->SetBaseFID(nNTFFileCount * 1000000 + 1);
     286           0 :         poFR->Close();
     287             : 
     288           0 :         EnsureTileNameUnique(poFR);
     289             : 
     290           0 :         papoNTFFileReader[nNTFFileCount++] = poFR;
     291             :     }
     292             : 
     293          52 :     CSLDestroy(papszFileList);
     294             : 
     295          52 :     if (nNTFFileCount == 0)
     296          52 :         return FALSE;
     297             : 
     298             :     /* -------------------------------------------------------------------- */
     299             :     /*      Establish generic layers.                                       */
     300             :     /* -------------------------------------------------------------------- */
     301           0 :     EstablishGenericLayers();
     302             : 
     303             :     /* -------------------------------------------------------------------- */
     304             :     /*      Loop over all the files, collecting a unique feature class      */
     305             :     /*      listing.                                                        */
     306             :     /* -------------------------------------------------------------------- */
     307           0 :     for (int iSrcFile = 0; iSrcFile < nNTFFileCount; iSrcFile++)
     308             :     {
     309           0 :         NTFFileReader *poSrcReader = papoNTFFileReader[iSrcFile];
     310             : 
     311           0 :         for (int iSrcFC = 0; iSrcFC < poSrcReader->GetFCCount(); iSrcFC++)
     312             :         {
     313           0 :             char *pszSrcFCName = nullptr;
     314           0 :             char *pszSrcFCNum = nullptr;
     315             : 
     316           0 :             poSrcReader->GetFeatureClass(iSrcFC, &pszSrcFCNum, &pszSrcFCName);
     317             : 
     318           0 :             int iDstFC = 0;
     319           0 :             for (; iDstFC < nFCCount; iDstFC++)
     320             :             {
     321           0 :                 if (EQUAL(pszSrcFCNum, papszFCNum[iDstFC]))
     322           0 :                     break;
     323             :             }
     324             : 
     325           0 :             if (iDstFC >= nFCCount)
     326             :             {
     327           0 :                 nFCCount++;
     328           0 :                 papszFCNum = CSLAddString(papszFCNum, pszSrcFCNum);
     329           0 :                 papszFCName = CSLAddString(papszFCName, pszSrcFCName);
     330             :             }
     331             :         }
     332             :     }
     333             : 
     334             :     /* -------------------------------------------------------------------- */
     335             :     /*      Create a new layer specifically for feature classes.            */
     336             :     /* -------------------------------------------------------------------- */
     337           0 :     if (nFCCount > 0)
     338           0 :         poFCLayer = new OGRNTFFeatureClassLayer(this);
     339             :     else
     340           0 :         poFCLayer = nullptr;
     341             : 
     342           0 :     return TRUE;
     343             : }
     344             : 
     345             : /************************************************************************/
     346             : /*                            ResetReading()                            */
     347             : /*                                                                      */
     348             : /*      Cleanup, and start over.                                        */
     349             : /************************************************************************/
     350             : 
     351           0 : void OGRNTFDataSource::ResetReading()
     352             : 
     353             : {
     354           0 :     for (int i = 0; i < nNTFFileCount; i++)
     355           0 :         papoNTFFileReader[i]->Close();
     356             : 
     357           0 :     iCurrentReader = -1;
     358           0 :     nCurrentPos = (vsi_l_offset)-1;
     359           0 :     nCurrentFID = 1;
     360           0 :     iCurrentFC = 0;
     361           0 : }
     362             : 
     363             : /************************************************************************/
     364             : /*                           GetNextFeature()                           */
     365             : /************************************************************************/
     366             : 
     367           0 : OGRFeature *OGRNTFDataSource::GetNextFeature(OGRLayer **ppoBelongingLayer,
     368             :                                              double *pdfProgressPct,
     369             :                                              GDALProgressFunc /* pfnProgress */,
     370             :                                              void * /* pProgressData */)
     371             : 
     372             : {
     373           0 :     if (pdfProgressPct != nullptr)
     374           0 :         *pdfProgressPct = 0.0;
     375           0 :     if (ppoBelongingLayer != nullptr)
     376           0 :         *ppoBelongingLayer = nullptr;
     377             : 
     378           0 :     OGRFeature *poFeature = nullptr;
     379             : 
     380             :     /* -------------------------------------------------------------------- */
     381             :     /*      If we have already read all the conventional features, we       */
     382             :     /*      should try and return feature class features.                   */
     383             :     /* -------------------------------------------------------------------- */
     384           0 :     if (iCurrentReader == nNTFFileCount)
     385             :     {
     386           0 :         if (iCurrentFC < nFCCount)
     387           0 :             return poFCLayer->GetFeature(iCurrentFC++);
     388             :         else
     389           0 :             return nullptr;
     390             :     }
     391             : 
     392             :     /* -------------------------------------------------------------------- */
     393             :     /*      Do we need to open a file?                                      */
     394             :     /* -------------------------------------------------------------------- */
     395           0 :     if (iCurrentReader == -1)
     396             :     {
     397           0 :         iCurrentReader++;
     398           0 :         nCurrentPos = (vsi_l_offset)-1;
     399             :     }
     400             : 
     401           0 :     if (papoNTFFileReader[iCurrentReader]->GetFP() == nullptr)
     402             :     {
     403           0 :         papoNTFFileReader[iCurrentReader]->Open();
     404             :     }
     405             : 
     406             :     /* -------------------------------------------------------------------- */
     407             :     /*      Ensure we are reading on from the same point we were reading    */
     408             :     /*      from for the last feature, even if some other access            */
     409             :     /*      mechanism has moved the file pointer.                           */
     410             :     /* -------------------------------------------------------------------- */
     411           0 :     if (nCurrentPos != (vsi_l_offset)-1)
     412           0 :         papoNTFFileReader[iCurrentReader]->SetFPPos(nCurrentPos, nCurrentFID);
     413             : 
     414             :     /* -------------------------------------------------------------------- */
     415             :     /*      Read a feature.  If we get NULL the file must be all            */
     416             :     /*      consumed, advance to the next file.                             */
     417             :     /* -------------------------------------------------------------------- */
     418           0 :     poFeature = papoNTFFileReader[iCurrentReader]->ReadOGRFeature();
     419           0 :     if (poFeature == nullptr)
     420             :     {
     421           0 :         papoNTFFileReader[iCurrentReader]->Close();
     422           0 :         if (GetOption("CACHING") != nullptr &&
     423           0 :             EQUAL(GetOption("CACHING"), "OFF"))
     424           0 :             papoNTFFileReader[iCurrentReader]->DestroyIndex();
     425             : 
     426           0 :         iCurrentReader++;
     427           0 :         nCurrentPos = (vsi_l_offset)-1;
     428           0 :         nCurrentFID = 1;
     429             : 
     430           0 :         poFeature = GetNextFeature(nullptr, nullptr, nullptr, nullptr);
     431             :     }
     432             :     else
     433             :     {
     434           0 :         papoNTFFileReader[iCurrentReader]->GetFPPos(&nCurrentPos, &nCurrentFID);
     435             :     }
     436             : 
     437           0 :     return poFeature;
     438             : }
     439             : 
     440             : /************************************************************************/
     441             : /*                          GetFeatureClass()                           */
     442             : /************************************************************************/
     443             : 
     444           0 : int OGRNTFDataSource::GetFeatureClass(int iFCIndex, char **ppszFCId,
     445             :                                       char **ppszFCName)
     446             : 
     447             : {
     448           0 :     if (iFCIndex < 0 || iFCIndex >= nFCCount)
     449             :     {
     450           0 :         *ppszFCId = nullptr;
     451           0 :         *ppszFCName = nullptr;
     452           0 :         return FALSE;
     453             :     }
     454             :     else
     455             :     {
     456           0 :         *ppszFCId = papszFCNum[iFCIndex];
     457           0 :         *ppszFCName = papszFCName[iFCIndex];
     458           0 :         return TRUE;
     459             :     }
     460             : }
     461             : 
     462             : /************************************************************************/
     463             : /*                             SetOptions()                             */
     464             : /************************************************************************/
     465             : 
     466           0 : void OGRNTFDataSource::SetOptionList(char **papszNewOptions)
     467             : 
     468             : {
     469           0 :     CSLDestroy(papszOptions);
     470           0 :     papszOptions = CSLDuplicate(papszNewOptions);
     471           0 : }
     472             : 
     473             : /************************************************************************/
     474             : /*                             GetOption()                              */
     475             : /************************************************************************/
     476             : 
     477           0 : const char *OGRNTFDataSource::GetOption(const char *pszOption)
     478             : 
     479             : {
     480           0 :     return CSLFetchNameValue(papszOptions, pszOption);
     481             : }
     482             : 
     483             : /************************************************************************/
     484             : /*                        EnsureTileNameUnique()                        */
     485             : /*                                                                      */
     486             : /*      This method is called with an NTFFileReader to ensure that      */
     487             : /*      its tilename is unique relative to all the readers already      */
     488             : /*      assigned to this data source.  If not, a unique name is         */
     489             : /*      selected for it and assigned.  This method should not be        */
     490             : /*      called with readers that are already attached to the data      */
     491             : /*      source.                                                         */
     492             : /************************************************************************/
     493             : 
     494           0 : void OGRNTFDataSource::EnsureTileNameUnique(NTFFileReader *poNewReader)
     495             : 
     496             : {
     497           0 :     int iSequenceNumber = -1;
     498           0 :     bool bIsUnique = false;
     499           0 :     char szCandidateName[12] = {};
     500             : 
     501           0 :     do
     502             :     {
     503           0 :         bIsUnique = TRUE;
     504           0 :         if (iSequenceNumber++ == -1)
     505           0 :             strncpy(szCandidateName, poNewReader->GetTileName(),
     506             :                     sizeof(szCandidateName) - 1);
     507             :         else
     508           0 :             snprintf(szCandidateName, sizeof(szCandidateName), "%010d",
     509             :                      iSequenceNumber);
     510             : 
     511           0 :         for (int iReader = 0; iReader < nNTFFileCount && bIsUnique; iReader++)
     512             :         {
     513           0 :             const char *pszTileName = GetFileReader(iReader)->GetTileName();
     514           0 :             if (pszTileName != nullptr &&
     515           0 :                 strcmp(szCandidateName, pszTileName) == 0)
     516             :             {
     517           0 :                 bIsUnique = FALSE;
     518             :             }
     519             :         }
     520           0 :     } while (!bIsUnique);
     521             : 
     522           0 :     if (iSequenceNumber > 0)
     523             :     {
     524           0 :         poNewReader->OverrideTileName(szCandidateName);
     525           0 :         CPLError(CE_Warning, CPLE_AppDefined,
     526             :                  "Forcing TILE_REF to `%s' on file %s\n"
     527             :                  "to avoid conflict with other tiles in this data source.",
     528             :                  szCandidateName, poNewReader->GetFilename());
     529             :     }
     530           0 : }

Generated by: LCOV version 1.14