LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/nas - ogrnasdatasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 84 120 70.0 %
Date: 2024-11-21 22:18:42 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OGR
       4             :  * Purpose:  Implements OGRNASDataSource class.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.com>
       9             :  * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_conv.h"
      15             : #include "cpl_string.h"
      16             : #include "ogr_nas.h"
      17             : 
      18             : static const char *const apszURNNames[] = {
      19             :     "DE_DHDN_3GK2_*", "EPSG:31466", "DE_DHDN_3GK3_*", "EPSG:31467",
      20             :     "ETRS89_UTM32",   "EPSG:25832", "ETRS89_UTM33",   "EPSG:25833",
      21             :     nullptr,          nullptr};
      22             : 
      23             : /************************************************************************/
      24             : /*                         OGRNASDataSource()                           */
      25             : /************************************************************************/
      26             : 
      27           5 : OGRNASDataSource::OGRNASDataSource()
      28           5 :     : papoLayers(nullptr), nLayers(0), poReader(nullptr)
      29             : {
      30           5 : }
      31             : 
      32             : /************************************************************************/
      33             : /*                        ~OGRNASDataSource()                         */
      34             : /************************************************************************/
      35             : 
      36          10 : OGRNASDataSource::~OGRNASDataSource()
      37             : 
      38             : {
      39          10 :     for (int i = 0; i < nLayers; i++)
      40           5 :         delete papoLayers[i];
      41             : 
      42           5 :     CPLFree(papoLayers);
      43             : 
      44           5 :     if (poReader)
      45           5 :         delete poReader;
      46          10 : }
      47             : 
      48             : /************************************************************************/
      49             : /*                                Open()                                */
      50             : /************************************************************************/
      51             : 
      52           5 : int OGRNASDataSource::Open(const char *pszNewName)
      53             : 
      54             : {
      55           5 :     poReader = CreateNASReader();
      56           5 :     if (poReader == nullptr)
      57             :     {
      58           0 :         CPLError(CE_Failure, CPLE_AppDefined,
      59             :                  "File %s appears to be NAS but the NAS reader cannot\n"
      60             :                  "be instantiated, likely because Xerces support was not\n"
      61             :                  "configured in.",
      62             :                  pszNewName);
      63           0 :         return FALSE;
      64             :     }
      65             : 
      66           5 :     poReader->SetSourceFile(pszNewName);
      67             : 
      68           5 :     bool bHaveSchema = false;
      69           5 :     bool bHaveTemplate = false;
      70             :     const char *pszGFSFilename;
      71             :     VSIStatBufL sGFSStatBuf;
      72             : 
      73             :     // Is some NAS Feature Schema (.gfs) TEMPLATE required?
      74           5 :     const char *pszNASTemplateName = CPLGetConfigOption("NAS_GFS_TEMPLATE", "");
      75           5 :     if (!EQUAL(pszNASTemplateName, ""))
      76             :     {
      77             :         // Load the TEMPLATE.
      78           0 :         if (!poReader->LoadClasses(pszNASTemplateName))
      79             :         {
      80           0 :             CPLError(CE_Failure, CPLE_AppDefined,
      81             :                      "NAS schema %s could not be loaded\n", pszNASTemplateName);
      82           0 :             return FALSE;
      83             :         }
      84             : 
      85           0 :         bHaveTemplate = true;
      86             : 
      87           0 :         CPLDebug("NAS", "Schema loaded.");
      88             :     }
      89             :     else
      90             :     {
      91             :         /* --------------------------------------------------------------------
      92             :          */
      93             :         /*      Can we find a NAS Feature Schema (.gfs) for the input file? */
      94             :         /* --------------------------------------------------------------------
      95             :          */
      96           5 :         pszGFSFilename = CPLResetExtension(pszNewName, "gfs");
      97           5 :         if (VSIStatL(pszGFSFilename, &sGFSStatBuf) == 0)
      98             :         {
      99             :             VSIStatBufL sNASStatBuf;
     100           0 :             if (VSIStatL(pszNewName, &sNASStatBuf) == 0 &&
     101           0 :                 sNASStatBuf.st_mtime > sGFSStatBuf.st_mtime)
     102             :             {
     103           0 :                 CPLDebug("NAS",
     104             :                          "Found %s but ignoring because it appears "
     105             :                          "be older than the associated NAS file.",
     106             :                          pszGFSFilename);
     107             :             }
     108             :             else
     109             :             {
     110           0 :                 bHaveSchema = poReader->LoadClasses(pszGFSFilename);
     111             :             }
     112             :         }
     113             : 
     114           5 :         if (!bHaveSchema)
     115             :         {
     116           5 :             CPLError(CE_Failure, CPLE_AppDefined,
     117             :                      "No schema information loaded");
     118             :         }
     119             :     }
     120             : 
     121             :     /* -------------------------------------------------------------------- */
     122             :     /*      Force a first pass to establish the schema.  The loaded schema  */
     123             :     /*      if any will be cleaned from any unavailable classes.            */
     124             :     /* -------------------------------------------------------------------- */
     125           5 :     CPLErrorReset();
     126           7 :     if (!bHaveSchema && !poReader->PrescanForSchema(TRUE) &&
     127           2 :         CPLGetLastErrorType() == CE_Failure)
     128             :     {
     129             :         // Assume an error has been reported.
     130           1 :         return FALSE;
     131             :     }
     132             : 
     133             :     /* -------------------------------------------------------------------- */
     134             :     /*      Save the schema file if possible.  Do not make a fuss if we     */
     135             :     /*      cannot.  It could be read-only directory or something.          */
     136             :     /* -------------------------------------------------------------------- */
     137           4 :     if (!bHaveTemplate && !bHaveSchema && poReader->GetClassCount() > 0 &&
     138           3 :         !STARTS_WITH_CI(pszNewName, "/vsitar/") &&
     139           3 :         !STARTS_WITH_CI(pszNewName, "/vsizip/") &&
     140           3 :         !STARTS_WITH_CI(pszNewName, "/vsigzip/vsi") &&
     141           3 :         !STARTS_WITH_CI(pszNewName, "/vsigzip//vsi") &&
     142          11 :         !STARTS_WITH_CI(pszNewName, "/vsicurl/") &&
     143           3 :         !STARTS_WITH_CI(pszNewName, "/vsicurl_streaming/"))
     144             :     {
     145           3 :         VSILFILE *fp = nullptr;
     146             : 
     147           3 :         pszGFSFilename = CPLResetExtension(pszNewName, "gfs");
     148           6 :         if (VSIStatL(pszGFSFilename, &sGFSStatBuf) != 0 &&
     149           3 :             (fp = VSIFOpenL(pszGFSFilename, "wt")) != nullptr)
     150             :         {
     151           3 :             VSIFCloseL(fp);
     152           3 :             poReader->SaveClasses(pszGFSFilename);
     153             :         }
     154             :         else
     155             :         {
     156           0 :             CPLDebug("NAS",
     157             :                      "Not saving %s. File already exists or can't be created.",
     158             :                      pszGFSFilename);
     159             :         }
     160             :     }
     161             : 
     162             :     /* -------------------------------------------------------------------- */
     163             :     /*      Translate the GMLFeatureClasses into layers.                    */
     164             :     /* -------------------------------------------------------------------- */
     165           8 :     papoLayers = (OGRLayer **)CPLCalloc(sizeof(OGRNASLayer *),
     166           4 :                                         poReader->GetClassCount() + 1);
     167           4 :     nLayers = 0;
     168             : 
     169           9 :     while (nLayers < poReader->GetClassCount())
     170             :     {
     171           5 :         papoLayers[nLayers] = TranslateNASSchema(poReader->GetClass(nLayers));
     172           5 :         nLayers++;
     173             :     }
     174             : 
     175           4 :     return TRUE;
     176             : }
     177             : 
     178             : /************************************************************************/
     179             : /*                         TranslateNASSchema()                         */
     180             : /************************************************************************/
     181             : 
     182           5 : OGRNASLayer *OGRNASDataSource::TranslateNASSchema(GMLFeatureClass *poClass)
     183             : 
     184             : {
     185             :     /* -------------------------------------------------------------------- */
     186             :     /*      Translate SRS.                                                  */
     187             :     /* -------------------------------------------------------------------- */
     188           5 :     const char *pszSRSName = poClass->GetSRSName();
     189           5 :     OGRSpatialReference *poSRS = nullptr;
     190           5 :     if (pszSRSName)
     191             :     {
     192           0 :         const char *pszHandle = strrchr(pszSRSName, ':');
     193           0 :         if (pszHandle != nullptr)
     194             :         {
     195           0 :             pszHandle += 1;
     196             : 
     197           0 :             poSRS = new OGRSpatialReference();
     198           0 :             poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     199             : 
     200           0 :             for (int i = 0; apszURNNames[i * 2 + 0] != nullptr; i++)
     201             :             {
     202           0 :                 const char *pszTarget = apszURNNames[i * 2 + 0];
     203           0 :                 const int nTLen = static_cast<int>(strlen(pszTarget));
     204             : 
     205             :                 // Are we just looking for a prefix match?
     206           0 :                 if (pszTarget[nTLen - 1] == '*')
     207             :                 {
     208           0 :                     if (EQUALN(pszTarget, pszHandle, nTLen - 1))
     209           0 :                         pszSRSName = apszURNNames[i * 2 + 1];
     210             :                 }
     211             :                 else
     212             :                 {
     213           0 :                     if (EQUAL(pszTarget, pszHandle))
     214           0 :                         pszSRSName = apszURNNames[i * 2 + 1];
     215             :                 }
     216             :             }
     217             : 
     218           0 :             if (poSRS->SetFromUserInput(
     219             :                     pszSRSName,
     220             :                     OGRSpatialReference::
     221           0 :                         SET_FROM_USER_INPUT_LIMITATIONS_get()) != OGRERR_NONE)
     222             :             {
     223           0 :                 CPLDebug("NAS", "Failed to translate srsName='%s'", pszSRSName);
     224           0 :                 delete poSRS;
     225           0 :                 poSRS = nullptr;
     226             :             }
     227             :         }
     228             :     }
     229             : 
     230             :     /* -------------------------------------------------------------------- */
     231             :     /*      Create an empty layer.                                          */
     232             :     /* -------------------------------------------------------------------- */
     233           5 :     OGRNASLayer *poLayer = new OGRNASLayer(poClass->GetName(), this);
     234             : 
     235             :     /* -------------------------------------------------------------------- */
     236             :     /*      Added attributes (properties).                                  */
     237             :     /* -------------------------------------------------------------------- */
     238          81 :     for (int iField = 0; iField < poClass->GetPropertyCount(); iField++)
     239             :     {
     240          76 :         GMLPropertyDefn *poProperty = poClass->GetProperty(iField);
     241             :         OGRFieldType eFType;
     242             : 
     243          76 :         if (poProperty->GetType() == GMLPT_Untyped)
     244           4 :             eFType = OFTString;
     245          72 :         else if (poProperty->GetType() == GMLPT_String)
     246          47 :             eFType = OFTString;
     247          25 :         else if (poProperty->GetType() == GMLPT_Integer)
     248          12 :             eFType = OFTInteger;
     249          13 :         else if (poProperty->GetType() == GMLPT_Real)
     250           2 :             eFType = OFTReal;
     251          11 :         else if (poProperty->GetType() == GMLPT_StringList)
     252           7 :             eFType = OFTStringList;
     253           4 :         else if (poProperty->GetType() == GMLPT_IntegerList)
     254           0 :             eFType = OFTIntegerList;
     255           4 :         else if (poProperty->GetType() == GMLPT_RealList)
     256           0 :             eFType = OFTRealList;
     257             :         else
     258           4 :             eFType = OFTString;
     259             : 
     260         152 :         OGRFieldDefn oField(poProperty->GetName(), eFType);
     261          76 :         if (STARTS_WITH_CI(oField.GetNameRef(), "ogr:"))
     262           0 :             oField.SetName(poProperty->GetName() + 4);
     263          76 :         if (poProperty->GetWidth() > 0)
     264          42 :             oField.SetWidth(poProperty->GetWidth());
     265             : 
     266          76 :         poLayer->GetLayerDefn()->AddFieldDefn(&oField);
     267             :     }
     268             : 
     269           7 :     for (int iField = 0; iField < poClass->GetGeometryPropertyCount(); iField++)
     270             :     {
     271             :         GMLGeometryPropertyDefn *poProperty =
     272           2 :             poClass->GetGeometryProperty(iField);
     273             :         OGRGeomFieldDefn oField(poProperty->GetName(),
     274           4 :                                 (OGRwkbGeometryType)poProperty->GetType());
     275           4 :         if (poClass->GetGeometryPropertyCount() == 1 &&
     276           2 :             poClass->GetFeatureCount() == 0)
     277             :         {
     278           0 :             oField.SetType(wkbUnknown);
     279             :         }
     280             : 
     281           2 :         oField.SetSpatialRef(poSRS);
     282           2 :         oField.SetNullable(poProperty->IsNullable());
     283           2 :         poLayer->GetLayerDefn()->AddGeomFieldDefn(&oField);
     284             :     }
     285             : 
     286           5 :     if (poSRS)
     287           0 :         poSRS->Dereference();
     288             : 
     289           5 :     return poLayer;
     290             : }
     291             : 
     292             : /************************************************************************/
     293             : /*                              GetLayer()                              */
     294             : /************************************************************************/
     295             : 
     296           4 : OGRLayer *OGRNASDataSource::GetLayer(int iLayer)
     297             : 
     298             : {
     299           4 :     if (iLayer < 0 || iLayer >= nLayers)
     300           0 :         return nullptr;
     301             : 
     302           4 :     return papoLayers[iLayer];
     303             : }

Generated by: LCOV version 1.14