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

Generated by: LCOV version 1.14