LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/ili - ogrili1datasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 126 142 88.7 %
Date: 2024-11-21 22:18:42 Functions: 10 10 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  Interlis 1 Translator
       4             :  * Purpose:  Implements OGRILI1DataSource class.
       5             :  * Author:   Pirmin Kalberer, Sourcepole AG
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2004, Pirmin Kalberer, Sourcepole AG
       9             :  * Copyright (c) 2007-2008, 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             : 
      17             : #include "ili1reader.h"
      18             : #include "ogr_ili1.h"
      19             : 
      20             : #include <string>
      21             : 
      22             : /************************************************************************/
      23             : /*                         OGRILI1DataSource()                         */
      24             : /************************************************************************/
      25             : 
      26         130 : OGRILI1DataSource::OGRILI1DataSource()
      27         130 :     : poImdReader(new ImdReader(1)), poReader(nullptr), fpTransfer(nullptr),
      28         130 :       pszTopic(nullptr), nLayers(0), papoLayers(nullptr)
      29             : {
      30         130 : }
      31             : 
      32             : /************************************************************************/
      33             : /*                        ~OGRILI1DataSource()                         */
      34             : /************************************************************************/
      35             : 
      36         260 : OGRILI1DataSource::~OGRILI1DataSource()
      37             : 
      38             : {
      39         167 :     for (int i = 0; i < nLayers; i++)
      40             :     {
      41          37 :         delete papoLayers[i];
      42             :     }
      43         130 :     CPLFree(papoLayers);
      44             : 
      45         130 :     CPLFree(pszTopic);
      46         130 :     DestroyILI1Reader(poReader);
      47         130 :     delete poImdReader;
      48         130 :     if (fpTransfer)
      49             :     {
      50          21 :         VSIFPrintfL(fpTransfer, "ETAB\n");
      51          21 :         VSIFPrintfL(fpTransfer, "ETOP\n");
      52          21 :         VSIFPrintfL(fpTransfer, "EMOD\n");
      53          21 :         VSIFPrintfL(fpTransfer, "ENDE\n");
      54          21 :         VSIFCloseL(fpTransfer);
      55             :     }
      56         260 : }
      57             : 
      58             : /************************************************************************/
      59             : /*                                Open()                                */
      60             : /************************************************************************/
      61             : 
      62         108 : int OGRILI1DataSource::Open(const char *pszNewName, char **papszOpenOptionsIn,
      63             :                             int bTestOpen)
      64             : 
      65             : {
      66         108 :     if (strlen(pszNewName) == 0)
      67             :     {
      68           0 :         return FALSE;
      69             :     }
      70             : 
      71         216 :     std::string osBasename;
      72         216 :     std::string osModelFilename;
      73         108 :     if (CSLFetchNameValue(papszOpenOptionsIn, "MODEL") != nullptr)
      74             :     {
      75           0 :         osBasename = pszNewName;
      76           0 :         osModelFilename = CSLFetchNameValue(papszOpenOptionsIn, "MODEL");
      77             :     }
      78             :     else
      79             :     {
      80         108 :         char **filenames = CSLTokenizeString2(pszNewName, ",", 0);
      81         108 :         int nCount = CSLCount(filenames);
      82         108 :         if (nCount == 0)
      83             :         {
      84           0 :             CSLDestroy(filenames);
      85           0 :             return FALSE;
      86             :         }
      87         108 :         osBasename = filenames[0];
      88             : 
      89         108 :         if (nCount > 1)
      90          73 :             osModelFilename = filenames[1];
      91             : 
      92         108 :         CSLDestroy(filenames);
      93             :     }
      94             : 
      95             :     /* -------------------------------------------------------------------- */
      96             :     /*      Open the source file.                                           */
      97             :     /* -------------------------------------------------------------------- */
      98         108 :     VSILFILE *fp = VSIFOpenL(osBasename.c_str(), "r");
      99         108 :     if (fp == nullptr)
     100             :     {
     101          57 :         if (!bTestOpen)
     102           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
     103             :                      "Failed to open ILI1 file `%s'.", pszNewName);
     104             : 
     105          57 :         return FALSE;
     106             :     }
     107             : 
     108             :     /* -------------------------------------------------------------------- */
     109             :     /*      If we aren't sure it is ILI1, load a header chunk and check      */
     110             :     /*      for signs it is ILI1                                             */
     111             :     /* -------------------------------------------------------------------- */
     112             :     char szHeader[1000];
     113             : 
     114          51 :     if (bTestOpen)
     115             :     {
     116          51 :         int nLen = (int)VSIFReadL(szHeader, 1, sizeof(szHeader), fp);
     117          51 :         if (nLen == sizeof(szHeader))
     118           5 :             szHeader[sizeof(szHeader) - 1] = '\0';
     119             :         else
     120          46 :             szHeader[nLen] = '\0';
     121             : 
     122          51 :         if (strstr(szHeader, "SCNT") == nullptr)
     123             :         {
     124           3 :             VSIFCloseL(fp);
     125           3 :             return FALSE;
     126             :         }
     127             :     }
     128             : 
     129             :     /* -------------------------------------------------------------------- */
     130             :     /*      We assume now that it is ILI1.  Close and instantiate a          */
     131             :     /*      ILI1Reader on it.                                                */
     132             :     /* -------------------------------------------------------------------- */
     133          48 :     VSIFCloseL(fp);
     134             : 
     135          48 :     poReader = CreateILI1Reader();
     136          48 :     if (poReader == nullptr)
     137             :     {
     138           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     139             :                  "File %s appears to be ILI1 but the ILI1 reader cannot\n"
     140             :                  "be instantiated, likely because Xerces support was not\n"
     141             :                  "configured in.",
     142             :                  pszNewName);
     143           0 :         return FALSE;
     144             :     }
     145             : 
     146          48 :     poReader->OpenFile(osBasename.c_str());
     147             : 
     148          48 :     if (osModelFilename.length() > 0)
     149          16 :         poReader->ReadModel(poImdReader, osModelFilename.c_str(), this);
     150             : 
     151          48 :     int bResetConfigOption = FALSE;
     152          48 :     if (EQUAL(CPLGetConfigOption("OGR_ARC_STEPSIZE", ""), ""))
     153             :     {
     154          48 :         bResetConfigOption = TRUE;
     155          48 :         CPLSetThreadLocalConfigOption("OGR_ARC_STEPSIZE", "0.96");
     156             :     }
     157             : 
     158             :     // Parse model and read data - without surface join and area polygonizing.
     159          48 :     poReader->ReadFeatures();
     160             : 
     161          48 :     if (bResetConfigOption)
     162          48 :         CPLSetThreadLocalConfigOption("OGR_ARC_STEPSIZE", nullptr);
     163             : 
     164          48 :     return TRUE;
     165             : }
     166             : 
     167             : /************************************************************************/
     168             : /*                               Create()                               */
     169             : /************************************************************************/
     170             : 
     171          22 : int OGRILI1DataSource::Create(const char *pszFilename,
     172             :                               char ** /* papszOptions */)
     173             : {
     174          22 :     char **filenames = CSLTokenizeString2(pszFilename, ",", 0);
     175             : 
     176          44 :     std::string osBasename = filenames[0];
     177             : 
     178          44 :     std::string osModelFilename;
     179          22 :     if (CSLCount(filenames) > 1)
     180           3 :         osModelFilename = filenames[1];
     181             : 
     182          22 :     CSLDestroy(filenames);
     183             : 
     184             :     /* -------------------------------------------------------------------- */
     185             :     /*      Create the empty file.                                          */
     186             :     /* -------------------------------------------------------------------- */
     187          22 :     fpTransfer = VSIFOpenL(osBasename.c_str(), "w+b");
     188             : 
     189          22 :     if (fpTransfer == nullptr)
     190             :     {
     191           1 :         CPLError(CE_Failure, CPLE_OpenFailed, "Failed to create %s:\n%s",
     192           1 :                  osBasename.c_str(), VSIStrerror(errno));
     193             : 
     194           1 :         return FALSE;
     195             :     }
     196             : 
     197             :     /* -------------------------------------------------------------------- */
     198             :     /*      Parse model                                                     */
     199             :     /* -------------------------------------------------------------------- */
     200          21 :     if (osModelFilename.length() == 0)
     201             :     {
     202          18 :         CPLError(CE_Warning, CPLE_AppDefined,
     203             :                  "Creating Interlis transfer file without model definition.");
     204             :     }
     205             :     else
     206             :     {
     207           3 :         poImdReader->ReadModel(osModelFilename.c_str());
     208             :     }
     209             : 
     210          21 :     pszTopic = CPLStrdup(poImdReader->mainTopicName.c_str());
     211             : 
     212             :     /* -------------------------------------------------------------------- */
     213             :     /*      Write headers                                                   */
     214             :     /* -------------------------------------------------------------------- */
     215          21 :     VSIFPrintfL(fpTransfer, "SCNT\n");
     216          21 :     VSIFPrintfL(fpTransfer, "OGR/GDAL %s, INTERLIS Driver\n",
     217             :                 GDALVersionInfo("RELEASE_NAME"));
     218          21 :     VSIFPrintfL(fpTransfer, "////\n");
     219          21 :     VSIFPrintfL(fpTransfer, "MTID INTERLIS1\n");
     220          21 :     const char *modelname = poImdReader->mainModelName.c_str();
     221          21 :     VSIFPrintfL(fpTransfer, "MODL %s\n", modelname);
     222             : 
     223          21 :     return TRUE;
     224             : }
     225             : 
     226          37 : static char *ExtractTopic(const char *pszLayerName)
     227             : {
     228          37 :     const char *table = strchr(pszLayerName, '_');
     229          37 :     while (table && table[1] != '_')
     230           0 :         table = strchr(table + 1, '_');
     231          40 :     return (table) ? CPLScanString(pszLayerName,
     232           3 :                                    static_cast<int>(table - pszLayerName),
     233             :                                    FALSE, FALSE)
     234          37 :                    : nullptr;
     235             : }
     236             : 
     237             : /************************************************************************/
     238             : /*                           ICreateLayer()                             */
     239             : /************************************************************************/
     240             : 
     241             : OGRLayer *
     242          37 : OGRILI1DataSource::ICreateLayer(const char *pszLayerName,
     243             :                                 const OGRGeomFieldDefn *poGeomFieldDefn,
     244             :                                 CSLConstList /*papszOptions*/)
     245             : {
     246          37 :     const auto eType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
     247             : 
     248             :     FeatureDefnInfo featureDefnInfo =
     249          37 :         poImdReader->GetFeatureDefnInfo(pszLayerName);
     250          37 :     const char *table = pszLayerName;
     251          37 :     char *topic = ExtractTopic(pszLayerName);
     252          37 :     if (nLayers)
     253          16 :         VSIFPrintfL(fpTransfer, "ETAB\n");
     254          37 :     if (topic)
     255             :     {
     256           3 :         table = pszLayerName + strlen(topic) + 2;  // after "__"
     257           3 :         if (pszTopic == nullptr || !EQUAL(topic, pszTopic))
     258             :         {
     259           1 :             if (pszTopic)
     260             :             {
     261           1 :                 VSIFPrintfL(fpTransfer, "ETOP\n");
     262           1 :                 CPLFree(pszTopic);
     263             :             }
     264           1 :             pszTopic = topic;
     265           1 :             VSIFPrintfL(fpTransfer, "TOPI %s\n", pszTopic);
     266             :         }
     267             :         else
     268             :         {
     269           2 :             CPLFree(topic);
     270             :         }
     271             :     }
     272             :     else
     273             :     {
     274          34 :         if (pszTopic == nullptr)
     275           0 :             pszTopic = CPLStrdup("Unknown");
     276          34 :         VSIFPrintfL(fpTransfer, "TOPI %s\n", pszTopic);
     277             :     }
     278          37 :     VSIFPrintfL(fpTransfer, "TABL %s\n", table);
     279             : 
     280          37 :     OGRFeatureDefn *poFeatureDefn = new OGRFeatureDefn(table);
     281          37 :     poFeatureDefn->SetGeomType(eType);
     282             :     OGRILI1Layer *poLayer =
     283          37 :         new OGRILI1Layer(poFeatureDefn, featureDefnInfo.poGeomFieldInfos, this);
     284             : 
     285          37 :     nLayers++;
     286          37 :     papoLayers = static_cast<OGRILI1Layer **>(
     287          37 :         CPLRealloc(papoLayers, sizeof(OGRILI1Layer *) * nLayers));
     288          37 :     papoLayers[nLayers - 1] = poLayer;
     289             : 
     290          74 :     return poLayer;
     291             : }
     292             : 
     293             : /************************************************************************/
     294             : /*                           TestCapability()                           */
     295             : /************************************************************************/
     296             : 
     297          49 : int OGRILI1DataSource::TestCapability(const char *pszCap)
     298             : 
     299             : {
     300          49 :     if (EQUAL(pszCap, ODsCCreateLayer))
     301          32 :         return TRUE;
     302          17 :     else if (EQUAL(pszCap, ODsCCurveGeometries))
     303           1 :         return TRUE;
     304          16 :     else if (EQUAL(pszCap, ODsCZGeometries))
     305           0 :         return TRUE;
     306             : 
     307          16 :     return FALSE;
     308             : }
     309             : 
     310             : /************************************************************************/
     311             : /*                              GetLayer()                              */
     312             : /************************************************************************/
     313             : 
     314          23 : OGRLayer *OGRILI1DataSource::GetLayer(int iLayer)
     315             : {
     316          23 :     if (!poReader)
     317             :     {
     318           0 :         if (iLayer < 0 || iLayer >= nLayers)
     319           0 :             return nullptr;
     320           0 :         return papoLayers[iLayer];
     321             :     }
     322          23 :     return poReader->GetLayer(iLayer);
     323             : }
     324             : 
     325             : /************************************************************************/
     326             : /*                              GetLayerByName()                              */
     327             : /************************************************************************/
     328             : 
     329          44 : OGRILI1Layer *OGRILI1DataSource::GetLayerByName(const char *pszLayerName)
     330             : {
     331          44 :     if (!poReader)
     332             :     {
     333           0 :         return cpl::down_cast<OGRILI1Layer *>(
     334           0 :             GDALDataset::GetLayerByName(pszLayerName));
     335             :     }
     336             : 
     337          44 :     return cpl::down_cast<OGRILI1Layer *>(
     338          88 :         poReader->GetLayerByName(pszLayerName));
     339             : }

Generated by: LCOV version 1.14