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: 2025-01-18 12:42:00 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             : 
      71             :     // Is some NAS Feature Schema (.gfs) TEMPLATE required?
      72           5 :     const char *pszNASTemplateName = CPLGetConfigOption("NAS_GFS_TEMPLATE", "");
      73           5 :     if (!EQUAL(pszNASTemplateName, ""))
      74             :     {
      75             :         // Load the TEMPLATE.
      76           0 :         if (!poReader->LoadClasses(pszNASTemplateName))
      77             :         {
      78           0 :             CPLError(CE_Failure, CPLE_AppDefined,
      79             :                      "NAS schema %s could not be loaded\n", pszNASTemplateName);
      80           0 :             return FALSE;
      81             :         }
      82             : 
      83           0 :         bHaveTemplate = true;
      84             : 
      85           0 :         CPLDebug("NAS", "Schema loaded.");
      86             :     }
      87             :     else
      88             :     {
      89             :         /* --------------------------------------------------------------------
      90             :          */
      91             :         /*      Can we find a NAS Feature Schema (.gfs) for the input file? */
      92             :         /* --------------------------------------------------------------------
      93             :          */
      94             :         const std::string osGFSFilename =
      95          10 :             CPLResetExtensionSafe(pszNewName, "gfs");
      96             :         VSIStatBufL sGFSStatBuf;
      97           5 :         if (VSIStatL(osGFSFilename.c_str(), &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             :                          osGFSFilename.c_str());
     107             :             }
     108             :             else
     109             :             {
     110           0 :                 bHaveSchema = poReader->LoadClasses(osGFSFilename.c_str());
     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             :         const std::string osGFSFilename =
     148           6 :             CPLResetExtensionSafe(pszNewName, "gfs");
     149             :         VSIStatBufL sGFSStatBuf;
     150           6 :         if (VSIStatL(osGFSFilename.c_str(), &sGFSStatBuf) != 0 &&
     151           3 :             (fp = VSIFOpenL(osGFSFilename.c_str(), "wt")) != nullptr)
     152             :         {
     153           3 :             VSIFCloseL(fp);
     154           3 :             poReader->SaveClasses(osGFSFilename.c_str());
     155             :         }
     156             :         else
     157             :         {
     158           0 :             CPLDebug("NAS",
     159             :                      "Not saving %s. File already exists or can't be created.",
     160             :                      osGFSFilename.c_str());
     161             :         }
     162             :     }
     163             : 
     164             :     /* -------------------------------------------------------------------- */
     165             :     /*      Translate the GMLFeatureClasses into layers.                    */
     166             :     /* -------------------------------------------------------------------- */
     167           8 :     papoLayers = (OGRLayer **)CPLCalloc(sizeof(OGRNASLayer *),
     168           4 :                                         poReader->GetClassCount() + 1);
     169           4 :     nLayers = 0;
     170             : 
     171           9 :     while (nLayers < poReader->GetClassCount())
     172             :     {
     173           5 :         papoLayers[nLayers] = TranslateNASSchema(poReader->GetClass(nLayers));
     174           5 :         nLayers++;
     175             :     }
     176             : 
     177           4 :     return TRUE;
     178             : }
     179             : 
     180             : /************************************************************************/
     181             : /*                         TranslateNASSchema()                         */
     182             : /************************************************************************/
     183             : 
     184           5 : OGRNASLayer *OGRNASDataSource::TranslateNASSchema(GMLFeatureClass *poClass)
     185             : 
     186             : {
     187             :     /* -------------------------------------------------------------------- */
     188             :     /*      Translate SRS.                                                  */
     189             :     /* -------------------------------------------------------------------- */
     190           5 :     const char *pszSRSName = poClass->GetSRSName();
     191           5 :     OGRSpatialReference *poSRS = nullptr;
     192           5 :     if (pszSRSName)
     193             :     {
     194           0 :         const char *pszHandle = strrchr(pszSRSName, ':');
     195           0 :         if (pszHandle != nullptr)
     196             :         {
     197           0 :             pszHandle += 1;
     198             : 
     199           0 :             poSRS = new OGRSpatialReference();
     200           0 :             poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     201             : 
     202           0 :             for (int i = 0; apszURNNames[i * 2 + 0] != nullptr; i++)
     203             :             {
     204           0 :                 const char *pszTarget = apszURNNames[i * 2 + 0];
     205           0 :                 const int nTLen = static_cast<int>(strlen(pszTarget));
     206             : 
     207             :                 // Are we just looking for a prefix match?
     208           0 :                 if (pszTarget[nTLen - 1] == '*')
     209             :                 {
     210           0 :                     if (EQUALN(pszTarget, pszHandle, nTLen - 1))
     211           0 :                         pszSRSName = apszURNNames[i * 2 + 1];
     212             :                 }
     213             :                 else
     214             :                 {
     215           0 :                     if (EQUAL(pszTarget, pszHandle))
     216           0 :                         pszSRSName = apszURNNames[i * 2 + 1];
     217             :                 }
     218             :             }
     219             : 
     220           0 :             if (poSRS->SetFromUserInput(
     221             :                     pszSRSName,
     222             :                     OGRSpatialReference::
     223           0 :                         SET_FROM_USER_INPUT_LIMITATIONS_get()) != OGRERR_NONE)
     224             :             {
     225           0 :                 CPLDebug("NAS", "Failed to translate srsName='%s'", pszSRSName);
     226           0 :                 delete poSRS;
     227           0 :                 poSRS = nullptr;
     228             :             }
     229             :         }
     230             :     }
     231             : 
     232             :     /* -------------------------------------------------------------------- */
     233             :     /*      Create an empty layer.                                          */
     234             :     /* -------------------------------------------------------------------- */
     235           5 :     OGRNASLayer *poLayer = new OGRNASLayer(poClass->GetName(), this);
     236             : 
     237             :     /* -------------------------------------------------------------------- */
     238             :     /*      Added attributes (properties).                                  */
     239             :     /* -------------------------------------------------------------------- */
     240          81 :     for (int iField = 0; iField < poClass->GetPropertyCount(); iField++)
     241             :     {
     242          76 :         GMLPropertyDefn *poProperty = poClass->GetProperty(iField);
     243             :         OGRFieldType eFType;
     244             : 
     245          76 :         if (poProperty->GetType() == GMLPT_Untyped)
     246           4 :             eFType = OFTString;
     247          72 :         else if (poProperty->GetType() == GMLPT_String)
     248          47 :             eFType = OFTString;
     249          25 :         else if (poProperty->GetType() == GMLPT_Integer)
     250          12 :             eFType = OFTInteger;
     251          13 :         else if (poProperty->GetType() == GMLPT_Real)
     252           2 :             eFType = OFTReal;
     253          11 :         else if (poProperty->GetType() == GMLPT_StringList)
     254           7 :             eFType = OFTStringList;
     255           4 :         else if (poProperty->GetType() == GMLPT_IntegerList)
     256           0 :             eFType = OFTIntegerList;
     257           4 :         else if (poProperty->GetType() == GMLPT_RealList)
     258           0 :             eFType = OFTRealList;
     259             :         else
     260           4 :             eFType = OFTString;
     261             : 
     262         152 :         OGRFieldDefn oField(poProperty->GetName(), eFType);
     263          76 :         if (STARTS_WITH_CI(oField.GetNameRef(), "ogr:"))
     264           0 :             oField.SetName(poProperty->GetName() + 4);
     265          76 :         if (poProperty->GetWidth() > 0)
     266          42 :             oField.SetWidth(poProperty->GetWidth());
     267             : 
     268          76 :         poLayer->GetLayerDefn()->AddFieldDefn(&oField);
     269             :     }
     270             : 
     271           7 :     for (int iField = 0; iField < poClass->GetGeometryPropertyCount(); iField++)
     272             :     {
     273             :         GMLGeometryPropertyDefn *poProperty =
     274           2 :             poClass->GetGeometryProperty(iField);
     275             :         OGRGeomFieldDefn oField(poProperty->GetName(),
     276           4 :                                 (OGRwkbGeometryType)poProperty->GetType());
     277           4 :         if (poClass->GetGeometryPropertyCount() == 1 &&
     278           2 :             poClass->GetFeatureCount() == 0)
     279             :         {
     280           0 :             oField.SetType(wkbUnknown);
     281             :         }
     282             : 
     283           2 :         oField.SetSpatialRef(poSRS);
     284           2 :         oField.SetNullable(poProperty->IsNullable());
     285           2 :         poLayer->GetLayerDefn()->AddGeomFieldDefn(&oField);
     286             :     }
     287             : 
     288           5 :     if (poSRS)
     289           0 :         poSRS->Dereference();
     290             : 
     291           5 :     return poLayer;
     292             : }
     293             : 
     294             : /************************************************************************/
     295             : /*                              GetLayer()                              */
     296             : /************************************************************************/
     297             : 
     298           4 : OGRLayer *OGRNASDataSource::GetLayer(int iLayer)
     299             : 
     300             : {
     301           4 :     if (iLayer < 0 || iLayer >= nLayers)
     302           0 :         return nullptr;
     303             : 
     304           4 :     return papoLayers[iLayer];
     305             : }

Generated by: LCOV version 1.14