LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/ntf - ntf_generic.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 9 372 2.4 %
Date: 2024-05-04 12:52:34 Functions: 2 15 13.3 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  NTF Translator
       4             :  * Purpose:  Handle NTF products that aren't recognised generically.
       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 <stdarg.h>
      30             : #include "ntf.h"
      31             : #include "cpl_string.h"
      32             : 
      33             : /************************************************************************/
      34             : /* ==================================================================== */
      35             : /*                          NTFGenericClass                             */
      36             : /*                                                                      */
      37             : /*      The NTFGenericClass class exists to hold aggregated             */
      38             : /*      information for each type of record encountered in a set of     */
      39             : /*      NTF files, primarily the list of attributes actually            */
      40             : /*      encountered.                                                    */
      41             : /* ==================================================================== */
      42             : /************************************************************************/
      43             : 
      44             : /************************************************************************/
      45             : /*                           NTFGenericClass                            */
      46             : /************************************************************************/
      47             : 
      48       66100 : NTFGenericClass::NTFGenericClass()
      49             :     : nFeatureCount(0), b3D(FALSE), nAttrCount(0), papszAttrNames(nullptr),
      50             :       papszAttrFormats(nullptr), panAttrMaxWidth(nullptr),
      51       66100 :       pabAttrMultiple(nullptr)
      52             : {
      53       66100 : }
      54             : 
      55             : /************************************************************************/
      56             : /*                           ~NTFGenericClass                           */
      57             : /************************************************************************/
      58             : 
      59      132200 : NTFGenericClass::~NTFGenericClass()
      60             : 
      61             : {
      62       66100 :     CSLDestroy(papszAttrNames);
      63       66100 :     CSLDestroy(papszAttrFormats);
      64       66100 :     CPLFree(panAttrMaxWidth);
      65       66100 :     CPLFree(pabAttrMultiple);
      66       66100 : }
      67             : 
      68             : /************************************************************************/
      69             : /*                            CheckAddAttr()                            */
      70             : /*                                                                      */
      71             : /*      Check if an attribute already exists.  If not add it with       */
      72             : /*      its format.  Note we don't check for format conflicts at        */
      73             : /*      this time.                                                      */
      74             : /************************************************************************/
      75             : 
      76           0 : void NTFGenericClass::CheckAddAttr(const char *pszName, const char *pszFormat,
      77             :                                    int nWidth)
      78             : 
      79             : {
      80           0 :     if (EQUAL(pszName, "TX"))
      81           0 :         pszName = "TEXT";
      82           0 :     if (EQUAL(pszName, "FC"))
      83           0 :         pszName = "FEAT_CODE";
      84             : 
      85           0 :     const int iAttrOffset = CSLFindString(papszAttrNames, pszName);
      86             : 
      87           0 :     if (iAttrOffset == -1)
      88             :     {
      89           0 :         nAttrCount++;
      90             : 
      91           0 :         papszAttrNames = CSLAddString(papszAttrNames, pszName);
      92           0 :         papszAttrFormats = CSLAddString(papszAttrFormats, pszFormat);
      93             : 
      94           0 :         panAttrMaxWidth = static_cast<int *>(
      95           0 :             CPLRealloc(panAttrMaxWidth, sizeof(int) * nAttrCount));
      96             : 
      97           0 :         panAttrMaxWidth[nAttrCount - 1] = nWidth;
      98             : 
      99           0 :         pabAttrMultiple = static_cast<int *>(
     100           0 :             CPLRealloc(pabAttrMultiple, sizeof(int) * nAttrCount));
     101             : 
     102           0 :         pabAttrMultiple[nAttrCount - 1] = FALSE;
     103             :     }
     104             :     else
     105             :     {
     106           0 :         if (panAttrMaxWidth[iAttrOffset] < nWidth)
     107           0 :             panAttrMaxWidth[iAttrOffset] = nWidth;
     108             :     }
     109           0 : }
     110             : 
     111             : /************************************************************************/
     112             : /*                            SetMultiple()                             */
     113             : /*                                                                      */
     114             : /*      Mark this attribute as appearing multiple times on some         */
     115             : /*      features.                                                       */
     116             : /************************************************************************/
     117             : 
     118           0 : void NTFGenericClass::SetMultiple(const char *pszName)
     119             : 
     120             : {
     121           0 :     if (EQUAL(pszName, "TX"))
     122           0 :         pszName = "TEXT";
     123           0 :     if (EQUAL(pszName, "FC"))
     124           0 :         pszName = "FEAT_CODE";
     125             : 
     126           0 :     const int iAttrOffset = CSLFindString(papszAttrNames, pszName);
     127           0 :     if (iAttrOffset == -1)
     128           0 :         return;
     129             : 
     130           0 :     pabAttrMultiple[iAttrOffset] = TRUE;
     131             : }
     132             : 
     133             : /************************************************************************/
     134             : /*                           WorkupGeneric()                            */
     135             : /*                                                                      */
     136             : /*      Scan a whole file, in order to build up a list of attributes    */
     137             : /*      for the generic types.                                          */
     138             : /************************************************************************/
     139             : 
     140           0 : void OGRNTFDataSource::WorkupGeneric(NTFFileReader *poReader)
     141             : 
     142             : {
     143           0 :     NTFRecord **papoGroup = nullptr;
     144             : 
     145           0 :     if (poReader->GetNTFLevel() > 2)
     146             :     {
     147           0 :         poReader->IndexFile();
     148           0 :         if (CPLGetLastErrorType() == CE_Failure)
     149           0 :             return;
     150             :     }
     151             :     else
     152           0 :         poReader->Reset();
     153             : 
     154             :     /* ==================================================================== */
     155             :     /*      Read all record groups in the file.                             */
     156             :     /* ==================================================================== */
     157             :     while (true)
     158             :     {
     159             :         /* --------------------------------------------------------------------
     160             :          */
     161             :         /*      Read a record group */
     162             :         /* --------------------------------------------------------------------
     163             :          */
     164           0 :         if (poReader->GetNTFLevel() > 2)
     165           0 :             papoGroup = poReader->GetNextIndexedRecordGroup(papoGroup);
     166             :         else
     167           0 :             papoGroup = poReader->ReadRecordGroup();
     168             : 
     169           0 :         if (papoGroup == nullptr || papoGroup[0]->GetType() < 0 ||
     170           0 :             papoGroup[0]->GetType() >= 99)
     171           0 :             break;
     172             : 
     173             :         /* --------------------------------------------------------------------
     174             :          */
     175             :         /*      Get the class corresponding to the anchor record. */
     176             :         /* --------------------------------------------------------------------
     177             :          */
     178           0 :         NTFGenericClass *poClass = GetGClass(papoGroup[0]->GetType());
     179           0 :         char **papszFullAttList = nullptr;
     180             : 
     181           0 :         poClass->nFeatureCount++;
     182             : 
     183             :         /* --------------------------------------------------------------------
     184             :          */
     185             :         /*      Loop over constituent records collecting attributes. */
     186             :         /* --------------------------------------------------------------------
     187             :          */
     188           0 :         for (int iRec = 0; papoGroup[iRec] != nullptr; iRec++)
     189             :         {
     190           0 :             NTFRecord *poRecord = papoGroup[iRec];
     191             : 
     192           0 :             switch (poRecord->GetType())
     193             :             {
     194           0 :                 case NRT_ATTREC:
     195             :                 {
     196             :                     char **papszTypes, **papszValues;
     197             : 
     198           0 :                     poReader->ProcessAttRec(poRecord, nullptr, &papszTypes,
     199             :                                             &papszValues);
     200             : 
     201           0 :                     for (int iAtt = 0;
     202           0 :                          papszTypes != nullptr && papszTypes[iAtt] != nullptr;
     203             :                          iAtt++)
     204             :                     {
     205             :                         NTFAttDesc *poAttDesc =
     206           0 :                             poReader->GetAttDesc(papszTypes[iAtt]);
     207           0 :                         if (poAttDesc != nullptr &&
     208           0 :                             papszValues[iAtt] != nullptr)
     209             :                         {
     210           0 :                             poClass->CheckAddAttr(
     211           0 :                                 poAttDesc->val_type, poAttDesc->finter,
     212           0 :                                 static_cast<int>(strlen(papszValues[iAtt])));
     213             :                         }
     214             : 
     215           0 :                         if (CSLFindString(papszFullAttList, papszTypes[iAtt]) ==
     216             :                             -1)
     217           0 :                             papszFullAttList = CSLAddString(papszFullAttList,
     218           0 :                                                             papszTypes[iAtt]);
     219           0 :                         else if (poAttDesc != nullptr)
     220           0 :                             poClass->SetMultiple(poAttDesc->val_type);
     221             :                     }
     222             : 
     223           0 :                     CSLDestroy(papszTypes);
     224           0 :                     CSLDestroy(papszValues);
     225             :                 }
     226           0 :                 break;
     227             : 
     228           0 :                 case NRT_TEXTREP:
     229             :                 case NRT_NAMEPOSTN:
     230           0 :                     poClass->CheckAddAttr("FONT", "I4", 4);
     231           0 :                     poClass->CheckAddAttr("TEXT_HT", "R3,1", 3);
     232           0 :                     poClass->CheckAddAttr("TEXT_HT_GROUND", "R9,3", 9);
     233           0 :                     poClass->CheckAddAttr("TEXT_HT", "R3,1", 3);
     234           0 :                     poClass->CheckAddAttr("DIG_POSTN", "I1", 1);
     235           0 :                     poClass->CheckAddAttr("ORIENT", "R4,1", 4);
     236           0 :                     break;
     237             : 
     238           0 :                 case NRT_NAMEREC:
     239           0 :                     poClass->CheckAddAttr("TEXT", "A*",
     240             :                                           atoi(poRecord->GetField(13, 14)));
     241           0 :                     break;
     242             : 
     243           0 :                 case NRT_GEOMETRY:
     244             :                 case NRT_GEOMETRY3D:
     245           0 :                     if (atoi(poRecord->GetField(3, 8)) != 0)
     246           0 :                         poClass->CheckAddAttr("GEOM_ID", "I6", 6);
     247           0 :                     if (poRecord->GetType() == NRT_GEOMETRY3D)
     248           0 :                         poClass->b3D = TRUE;
     249           0 :                     break;
     250             : 
     251           0 :                 case NRT_POINTREC:
     252             :                 case NRT_LINEREC:
     253           0 :                     if (poReader->GetNTFLevel() < 3)
     254             :                     {
     255             :                         NTFAttDesc *poAttDesc =
     256           0 :                             poReader->GetAttDesc(poRecord->GetField(9, 10));
     257           0 :                         if (poAttDesc != nullptr)
     258           0 :                             poClass->CheckAddAttr(poAttDesc->val_type,
     259           0 :                                                   poAttDesc->finter, 6);
     260             : 
     261           0 :                         if (!EQUAL(poRecord->GetField(17, 20), "    "))
     262           0 :                             poClass->CheckAddAttr("FEAT_CODE", "A4", 4);
     263             :                     }
     264           0 :                     break;
     265             : 
     266           0 :                 default:
     267           0 :                     break;
     268             :             }
     269             :         }
     270             : 
     271           0 :         CSLDestroy(papszFullAttList);
     272           0 :     }
     273             : 
     274           0 :     if (GetOption("CACHING") != nullptr && EQUAL(GetOption("CACHING"), "OFF"))
     275           0 :         poReader->DestroyIndex();
     276             : 
     277           0 :     poReader->Reset();
     278             : }
     279             : 
     280             : /************************************************************************/
     281             : /*                        AddGenericAttributes()                        */
     282             : /************************************************************************/
     283             : 
     284           0 : static void AddGenericAttributes(NTFFileReader *poReader, NTFRecord **papoGroup,
     285             :                                  OGRFeature *poFeature)
     286             : 
     287             : {
     288           0 :     char **papszTypes = nullptr;
     289           0 :     char **papszValues = nullptr;
     290             : 
     291           0 :     if (!poReader->ProcessAttRecGroup(papoGroup, &papszTypes, &papszValues))
     292           0 :         return;
     293             : 
     294           0 :     for (int iAtt = 0; papszTypes != nullptr && papszTypes[iAtt] != nullptr;
     295             :          iAtt++)
     296             :     {
     297           0 :         int iField = 0;
     298             : 
     299           0 :         if (EQUAL(papszTypes[iAtt], "TX"))
     300           0 :             iField = poFeature->GetFieldIndex("TEXT");
     301           0 :         else if (EQUAL(papszTypes[iAtt], "FC"))
     302           0 :             iField = poFeature->GetFieldIndex("FEAT_CODE");
     303             :         else
     304           0 :             iField = poFeature->GetFieldIndex(papszTypes[iAtt]);
     305             : 
     306           0 :         if (iField == -1)
     307           0 :             continue;
     308             : 
     309           0 :         poReader->ApplyAttributeValue(poFeature, iField, papszTypes[iAtt],
     310             :                                       papszTypes, papszValues);
     311             : 
     312             :         /* --------------------------------------------------------------------
     313             :          */
     314             :         /*      Do we have a corresponding list field we should be */
     315             :         /*      accumulating this into? */
     316             :         /* --------------------------------------------------------------------
     317             :          */
     318           0 :         char szListName[128] = {};
     319             : 
     320           0 :         snprintf(szListName, sizeof(szListName), "%s_LIST",
     321             :                  poFeature->GetFieldDefnRef(iField)->GetNameRef());
     322           0 :         const int iListField = poFeature->GetFieldIndex(szListName);
     323             : 
     324             :         /* --------------------------------------------------------------------
     325             :          */
     326             :         /*      Yes, so perform processing similar to ApplyAttributeValue(), */
     327             :         /*      and append to list value. */
     328             :         /* --------------------------------------------------------------------
     329             :          */
     330           0 :         if (iListField != -1)
     331             :         {
     332           0 :             const char *pszAttLongName = nullptr;
     333           0 :             const char *pszAttValue = nullptr;
     334           0 :             const char *pszCodeDesc = nullptr;
     335             : 
     336           0 :             poReader->ProcessAttValue(papszTypes[iAtt], papszValues[iAtt],
     337             :                                       &pszAttLongName, &pszAttValue,
     338             :                                       &pszCodeDesc);
     339             : 
     340           0 :             if (poFeature->IsFieldSetAndNotNull(iListField))
     341             :             {
     342           0 :                 poFeature->SetField(
     343             :                     iListField,
     344             :                     CPLSPrintf("%s,%s", poFeature->GetFieldAsString(iListField),
     345             :                                pszAttValue));
     346             :             }
     347             :             else
     348             :             {
     349           0 :                 poFeature->SetField(iListField, pszAttValue);
     350             :             }
     351             :         }
     352             :     }
     353             : 
     354           0 :     CSLDestroy(papszTypes);
     355           0 :     CSLDestroy(papszValues);
     356             : }
     357             : 
     358             : /************************************************************************/
     359             : /*                        TranslateGenericNode()                        */
     360             : /************************************************************************/
     361             : 
     362           0 : static OGRFeature *TranslateGenericNode(NTFFileReader *poReader,
     363             :                                         OGRNTFLayer *poLayer,
     364             :                                         NTFRecord **papoGroup)
     365             : 
     366             : {
     367           0 :     if (CSLCount((char **)papoGroup) < 2 ||
     368           0 :         papoGroup[0]->GetType() != NRT_NODEREC ||
     369           0 :         (papoGroup[1]->GetType() != NRT_GEOMETRY &&
     370           0 :          papoGroup[1]->GetType() != NRT_GEOMETRY3D))
     371             :     {
     372           0 :         return nullptr;
     373             :     }
     374             : 
     375           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
     376             : 
     377             :     // NODE_ID
     378           0 :     poFeature->SetField("NODE_ID", atoi(papoGroup[0]->GetField(3, 8)));
     379             : 
     380             :     // Geometry
     381           0 :     poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[1]));
     382           0 :     poFeature->SetField("GEOM_ID", papoGroup[1]->GetField(3, 8));
     383             : 
     384             :     // NUM_LINKS
     385           0 :     int nLinkCount = 0;
     386           0 :     if (papoGroup[0]->GetLength() > 18)
     387             :     {
     388           0 :         nLinkCount = atoi(papoGroup[0]->GetField(15, 18));
     389           0 :         if (nLinkCount > 0)
     390             :         {
     391           0 :             std::vector<int> anLinks(nLinkCount);
     392             : 
     393             :             // GEOM_ID_OF_LINK
     394           0 :             for (int iLink = 0; iLink < nLinkCount; iLink++)
     395           0 :                 anLinks[iLink] = atoi(
     396           0 :                     papoGroup[0]->GetField(20 + iLink * 12, 25 + iLink * 12));
     397             : 
     398           0 :             poFeature->SetField("GEOM_ID_OF_LINK", nLinkCount, anLinks.data());
     399             : 
     400             :             // DIR
     401           0 :             for (int iLink = 0; iLink < nLinkCount; iLink++)
     402           0 :                 anLinks[iLink] = atoi(
     403           0 :                     papoGroup[0]->GetField(19 + iLink * 12, 19 + iLink * 12));
     404             : 
     405           0 :             poFeature->SetField("DIR", nLinkCount, anLinks.data());
     406             :         }
     407             :     }
     408             : 
     409           0 :     poFeature->SetField("NUM_LINKS", nLinkCount);
     410             : 
     411             :     // should we add LEVEL and/or ORIENT?
     412             : 
     413           0 :     return poFeature;
     414             : }
     415             : 
     416             : /************************************************************************/
     417             : /*                     TranslateGenericCollection()                     */
     418             : /************************************************************************/
     419             : 
     420           0 : static OGRFeature *TranslateGenericCollection(NTFFileReader *poReader,
     421             :                                               OGRNTFLayer *poLayer,
     422             :                                               NTFRecord **papoGroup)
     423             : 
     424             : {
     425           0 :     if (CSLCount((char **)papoGroup) < 1 ||
     426           0 :         papoGroup[0]->GetType() != NRT_COLLECT)
     427           0 :         return nullptr;
     428             : 
     429           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
     430             : 
     431             :     // COLL_ID
     432           0 :     poFeature->SetField("COLL_ID", atoi(papoGroup[0]->GetField(3, 8)));
     433             : 
     434             :     // NUM_PARTS
     435           0 :     int nPartCount = 0;
     436             : 
     437           0 :     if (papoGroup[0]->GetLength() >= 20)
     438             :     {
     439           0 :         nPartCount = atoi(papoGroup[0]->GetField(9, 12));
     440           0 :         if (nPartCount > 0 &&
     441           0 :             nPartCount - 1 <= (papoGroup[0]->GetLength() - 20) / 8)
     442             :         {
     443           0 :             std::vector<int> anParts(nPartCount);
     444             : 
     445             :             // TYPE
     446           0 :             for (int iPart = 0; iPart < nPartCount; iPart++)
     447           0 :                 anParts[iPart] = atoi(
     448           0 :                     papoGroup[0]->GetField(13 + iPart * 8, 14 + iPart * 8));
     449             : 
     450           0 :             poFeature->SetField("TYPE", nPartCount, anParts.data());
     451             : 
     452             :             // ID
     453           0 :             for (int iPart = 0; iPart < nPartCount; iPart++)
     454           0 :                 anParts[iPart] = atoi(
     455           0 :                     papoGroup[0]->GetField(15 + iPart * 8, 20 + iPart * 8));
     456             : 
     457           0 :             poFeature->SetField("ID", nPartCount, anParts.data());
     458             :         }
     459             :         else
     460             :         {
     461           0 :             nPartCount = 0;
     462             :         }
     463             :     }
     464             : 
     465           0 :     poFeature->SetField("NUM_PARTS", nPartCount);
     466             : 
     467             :     // ATTREC Attributes
     468           0 :     AddGenericAttributes(poReader, papoGroup, poFeature);
     469             : 
     470           0 :     return poFeature;
     471             : }
     472             : 
     473             : /************************************************************************/
     474             : /*                        TranslateGenericText()                        */
     475             : /************************************************************************/
     476             : 
     477           0 : static OGRFeature *TranslateGenericText(NTFFileReader *poReader,
     478             :                                         OGRNTFLayer *poLayer,
     479             :                                         NTFRecord **papoGroup)
     480             : 
     481             : {
     482           0 :     if (CSLCount((char **)papoGroup) < 2 ||
     483           0 :         papoGroup[0]->GetType() != NRT_TEXTREC)
     484           0 :         return nullptr;
     485             : 
     486           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
     487             : 
     488             :     // TEXT_ID
     489           0 :     poFeature->SetField("TEXT_ID", atoi(papoGroup[0]->GetField(3, 8)));
     490             : 
     491             :     // Geometry
     492           0 :     for (int iRec = 0; papoGroup[iRec] != nullptr; iRec++)
     493             :     {
     494           0 :         if (papoGroup[iRec]->GetType() == NRT_GEOMETRY ||
     495           0 :             papoGroup[iRec]->GetType() == NRT_GEOMETRY3D)
     496             :         {
     497           0 :             poFeature->SetGeometryDirectly(
     498           0 :                 poReader->ProcessGeometry(papoGroup[iRec]));
     499           0 :             poFeature->SetField("GEOM_ID", papoGroup[iRec]->GetField(3, 8));
     500           0 :             break;
     501             :         }
     502             :     }
     503             : 
     504             :     // ATTREC Attributes
     505           0 :     AddGenericAttributes(poReader, papoGroup, poFeature);
     506             : 
     507             :     // TEXTREP information
     508           0 :     for (int iRec = 0; papoGroup[iRec] != nullptr; iRec++)
     509             :     {
     510           0 :         NTFRecord *poRecord = papoGroup[iRec];
     511             : 
     512           0 :         if (poRecord->GetType() == NRT_TEXTREP)
     513             :         {
     514           0 :             poFeature->SetField("FONT", atoi(poRecord->GetField(9, 12)));
     515           0 :             poFeature->SetField("TEXT_HT",
     516           0 :                                 atoi(poRecord->GetField(13, 15)) * 0.1);
     517           0 :             poFeature->SetField("TEXT_HT_GROUND",
     518           0 :                                 atoi(poRecord->GetField(13, 15)) * 0.1 *
     519           0 :                                     poReader->GetPaperToGround());
     520           0 :             poFeature->SetField("DIG_POSTN", atoi(poRecord->GetField(16, 16)));
     521           0 :             poFeature->SetField("ORIENT",
     522           0 :                                 atoi(poRecord->GetField(17, 20)) * 0.1);
     523           0 :             break;
     524             :         }
     525             :     }
     526             : 
     527           0 :     return poFeature;
     528             : }
     529             : 
     530             : /************************************************************************/
     531             : /*                        TranslateGenericName()                        */
     532             : /************************************************************************/
     533             : 
     534           0 : static OGRFeature *TranslateGenericName(NTFFileReader *poReader,
     535             :                                         OGRNTFLayer *poLayer,
     536             :                                         NTFRecord **papoGroup)
     537             : 
     538             : {
     539           0 :     if (CSLCount((char **)papoGroup) < 2 ||
     540           0 :         papoGroup[0]->GetType() != NRT_NAMEREC)
     541           0 :         return nullptr;
     542             : 
     543           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
     544             : 
     545             :     // NAME_ID
     546           0 :     poFeature->SetField("NAME_ID", atoi(papoGroup[0]->GetField(3, 8)));
     547             : 
     548             :     // TEXT_CODE
     549           0 :     poFeature->SetField("TEXT_CODE", papoGroup[0]->GetField(8, 12));
     550             : 
     551             :     // TEXT
     552           0 :     int nNumChar = atoi(papoGroup[0]->GetField(13, 14));
     553             : 
     554           0 :     if (nNumChar > 0 && papoGroup[0]->GetLength() >= 15 + nNumChar - 1)
     555           0 :         poFeature->SetField("TEXT",
     556             :                             papoGroup[0]->GetField(15, 15 + nNumChar - 1));
     557             : 
     558             :     // Geometry
     559           0 :     for (int iRec = 0; papoGroup[iRec] != nullptr; iRec++)
     560             :     {
     561           0 :         if (papoGroup[iRec]->GetType() == NRT_GEOMETRY ||
     562           0 :             papoGroup[iRec]->GetType() == NRT_GEOMETRY3D)
     563             :         {
     564           0 :             poFeature->SetGeometryDirectly(
     565           0 :                 poReader->ProcessGeometry(papoGroup[iRec]));
     566           0 :             poFeature->SetField("GEOM_ID", papoGroup[iRec]->GetField(3, 8));
     567           0 :             break;
     568             :         }
     569             :     }
     570             : 
     571             :     // ATTREC Attributes
     572           0 :     AddGenericAttributes(poReader, papoGroup, poFeature);
     573             : 
     574             :     // NAMEPOSTN information
     575           0 :     for (int iRec = 0; papoGroup[iRec] != nullptr; iRec++)
     576             :     {
     577           0 :         NTFRecord *poRecord = papoGroup[iRec];
     578             : 
     579           0 :         if (poRecord->GetType() == NRT_NAMEPOSTN)
     580             :         {
     581           0 :             poFeature->SetField("FONT", atoi(poRecord->GetField(3, 6)));
     582           0 :             poFeature->SetField("TEXT_HT",
     583           0 :                                 atoi(poRecord->GetField(7, 9)) * 0.1);
     584           0 :             poFeature->SetField("TEXT_HT_GROUND",
     585           0 :                                 atoi(poRecord->GetField(7, 9)) * 0.1 *
     586           0 :                                     poReader->GetPaperToGround());
     587           0 :             poFeature->SetField("DIG_POSTN", atoi(poRecord->GetField(10, 10)));
     588           0 :             poFeature->SetField("ORIENT",
     589           0 :                                 atoi(poRecord->GetField(11, 14)) * 0.1);
     590           0 :             break;
     591             :         }
     592             :     }
     593             : 
     594           0 :     return poFeature;
     595             : }
     596             : 
     597             : /************************************************************************/
     598             : /*                       TranslateGenericPoint()                        */
     599             : /************************************************************************/
     600             : 
     601           0 : static OGRFeature *TranslateGenericPoint(NTFFileReader *poReader,
     602             :                                          OGRNTFLayer *poLayer,
     603             :                                          NTFRecord **papoGroup)
     604             : 
     605             : {
     606           0 :     if (CSLCount((char **)papoGroup) < 2 ||
     607           0 :         papoGroup[0]->GetType() != NRT_POINTREC ||
     608           0 :         (papoGroup[1]->GetType() != NRT_GEOMETRY &&
     609           0 :          papoGroup[1]->GetType() != NRT_GEOMETRY3D))
     610             :     {
     611           0 :         return nullptr;
     612             :     }
     613             : 
     614           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
     615             : 
     616             :     // POINT_ID
     617           0 :     poFeature->SetField("POINT_ID", atoi(papoGroup[0]->GetField(3, 8)));
     618             : 
     619             :     // Geometry
     620           0 :     poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[1]));
     621           0 :     poFeature->SetField("GEOM_ID", papoGroup[1]->GetField(3, 8));
     622             : 
     623             :     // ATTREC Attributes
     624           0 :     AddGenericAttributes(poReader, papoGroup, poFeature);
     625             : 
     626             :     // Handle singular attribute in pre-level 3 POINTREC.
     627           0 :     if (poReader->GetNTFLevel() < 3)
     628             :     {
     629             :         char szValType[3];
     630             : 
     631           0 :         snprintf(szValType, sizeof(szValType), "%s",
     632             :                  papoGroup[0]->GetField(9, 10));
     633           0 :         if (!EQUAL(szValType, "  "))
     634             :         {
     635           0 :             const char *pszProcessedValue = nullptr;
     636             : 
     637           0 :             if (poReader->ProcessAttValue(szValType,
     638             :                                           papoGroup[0]->GetField(11, 16),
     639           0 :                                           nullptr, &pszProcessedValue, nullptr))
     640           0 :                 poFeature->SetField(szValType, pszProcessedValue);
     641             :         }
     642             : 
     643           0 :         if (!EQUAL(papoGroup[0]->GetField(17, 20), "    "))
     644             :         {
     645           0 :             poFeature->SetField("FEAT_CODE", papoGroup[0]->GetField(17, 20));
     646             :         }
     647             :     }
     648             : 
     649           0 :     return poFeature;
     650             : }
     651             : 
     652             : /************************************************************************/
     653             : /*                        TranslateGenericLine()                        */
     654             : /************************************************************************/
     655             : 
     656           0 : static OGRFeature *TranslateGenericLine(NTFFileReader *poReader,
     657             :                                         OGRNTFLayer *poLayer,
     658             :                                         NTFRecord **papoGroup)
     659             : 
     660             : {
     661           0 :     if (CSLCount((char **)papoGroup) < 2 ||
     662           0 :         papoGroup[0]->GetType() != NRT_LINEREC ||
     663           0 :         (papoGroup[1]->GetType() != NRT_GEOMETRY &&
     664           0 :          papoGroup[1]->GetType() != NRT_GEOMETRY3D))
     665           0 :         return nullptr;
     666             : 
     667           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
     668             : 
     669             :     // LINE_ID
     670           0 :     poFeature->SetField("LINE_ID", atoi(papoGroup[0]->GetField(3, 8)));
     671             : 
     672             :     // Geometry
     673           0 :     poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[1]));
     674           0 :     poFeature->SetField("GEOM_ID", papoGroup[1]->GetField(3, 8));
     675             : 
     676             :     // ATTREC Attributes
     677           0 :     AddGenericAttributes(poReader, papoGroup, poFeature);
     678             : 
     679             :     // Handle singular attribute in pre-level 3 LINEREC.
     680           0 :     if (poReader->GetNTFLevel() < 3)
     681             :     {
     682           0 :         char szValType[3] = {};
     683             : 
     684           0 :         snprintf(szValType, sizeof(szValType), "%s",
     685             :                  papoGroup[0]->GetField(9, 10));
     686           0 :         if (!EQUAL(szValType, "  "))
     687             :         {
     688           0 :             const char *pszProcessedValue = nullptr;
     689             : 
     690           0 :             if (poReader->ProcessAttValue(szValType,
     691             :                                           papoGroup[0]->GetField(11, 16),
     692           0 :                                           nullptr, &pszProcessedValue, nullptr))
     693           0 :                 poFeature->SetField(szValType, pszProcessedValue);
     694             :         }
     695             : 
     696           0 :         if (!EQUAL(papoGroup[0]->GetField(17, 20), "    "))
     697             :         {
     698           0 :             poFeature->SetField("FEAT_CODE", papoGroup[0]->GetField(17, 20));
     699             :         }
     700             :     }
     701             : 
     702           0 :     return poFeature;
     703             : }
     704             : 
     705             : /************************************************************************/
     706             : /*                        TranslateGenericPoly()                        */
     707             : /************************************************************************/
     708             : 
     709           0 : static OGRFeature *TranslateGenericPoly(NTFFileReader *poReader,
     710             :                                         OGRNTFLayer *poLayer,
     711             :                                         NTFRecord **papoGroup)
     712             : 
     713             : {
     714             :     /* ==================================================================== */
     715             :     /*      Traditional POLYGON record groups.                              */
     716             :     /* ==================================================================== */
     717           0 :     if (CSLCount((char **)papoGroup) >= 2 &&
     718           0 :         papoGroup[0]->GetType() == NRT_POLYGON &&
     719           0 :         papoGroup[1]->GetType() == NRT_CHAIN)
     720             :     {
     721           0 :         OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
     722             : 
     723             :         // POLY_ID
     724           0 :         poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
     725             : 
     726             :         // NUM_PARTS
     727           0 :         int nNumLinks = atoi(papoGroup[1]->GetField(9, 12));
     728             : 
     729           0 :         if (nNumLinks < 0 || nNumLinks > MAX_LINK)
     730             :         {
     731           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     732             :                      "MAX_LINK exceeded in ntf_generic.cpp.");
     733           0 :             return poFeature;
     734             :         }
     735             : 
     736           0 :         poFeature->SetField("NUM_PARTS", nNumLinks);
     737             : 
     738             :         // DIR
     739             :         int i, anList[MAX_LINK];
     740             : 
     741           0 :         for (i = 0; i < nNumLinks; i++)
     742           0 :             anList[i] = atoi(papoGroup[1]->GetField(19 + i * 7, 19 + i * 7));
     743             : 
     744           0 :         poFeature->SetField("DIR", nNumLinks, anList);
     745             : 
     746             :         // GEOM_ID_OF_LINK
     747           0 :         for (i = 0; i < nNumLinks; i++)
     748           0 :             anList[i] = atoi(papoGroup[1]->GetField(13 + i * 7, 18 + i * 7));
     749             : 
     750           0 :         poFeature->SetField("GEOM_ID_OF_LINK", nNumLinks, anList);
     751             : 
     752             :         // RingStart
     753           0 :         int nRingList = 0;
     754           0 :         poFeature->SetField("RingStart", 1, &nRingList);
     755             : 
     756             :         // ATTREC Attributes
     757           0 :         AddGenericAttributes(poReader, papoGroup, poFeature);
     758             : 
     759             :         // Read point geometry
     760           0 :         if (papoGroup[2] != nullptr &&
     761           0 :             (papoGroup[2]->GetType() == NRT_GEOMETRY ||
     762           0 :              papoGroup[2]->GetType() == NRT_GEOMETRY3D))
     763             :         {
     764           0 :             poFeature->SetGeometryDirectly(
     765           0 :                 poReader->ProcessGeometry(papoGroup[2]));
     766           0 :             poFeature->SetField("GEOM_ID", papoGroup[2]->GetField(3, 8));
     767             :         }
     768             : 
     769           0 :         return poFeature;
     770             :     }
     771             : 
     772           0 :     return nullptr;
     773             : }
     774             : 
     775             : /************************************************************************/
     776             : /*                       TranslateGenericCPoly()                        */
     777             : /************************************************************************/
     778             : 
     779           0 : static OGRFeature *TranslateGenericCPoly(NTFFileReader *poReader,
     780             :                                          OGRNTFLayer *poLayer,
     781             :                                          NTFRecord **papoGroup)
     782             : 
     783             : {
     784             :     /* -------------------------------------------------------------------- */
     785             :     /*      First we do validation of the grouping.                         */
     786             :     /* -------------------------------------------------------------------- */
     787           0 :     if (papoGroup[0]->GetType() != NRT_CPOLY)
     788           0 :         return nullptr;
     789             : 
     790           0 :     if (papoGroup[1] == nullptr || (papoGroup[1]->GetType() != NRT_GEOMETRY &&
     791           0 :                                     papoGroup[1]->GetType() != NRT_GEOMETRY3D))
     792           0 :         return nullptr;
     793             : 
     794           0 :     if (papoGroup[2] != nullptr && papoGroup[2]->GetType() != NRT_ATTREC)
     795           0 :         return nullptr;
     796             : 
     797             :     /* -------------------------------------------------------------------- */
     798             :     /*      collect information for whole complex polygon.                  */
     799             :     /* -------------------------------------------------------------------- */
     800           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
     801             : 
     802             :     // CPOLY_ID
     803           0 :     poFeature->SetField("CPOLY_ID", atoi(papoGroup[0]->GetField(3, 8)));
     804             : 
     805             :     // ATTREC Attributes
     806           0 :     AddGenericAttributes(poReader, papoGroup, poFeature);
     807             : 
     808             :     // Read point geometry
     809           0 :     if (papoGroup[1] != nullptr && (papoGroup[1]->GetType() == NRT_GEOMETRY ||
     810           0 :                                     papoGroup[1]->GetType() == NRT_GEOMETRY3D))
     811             :     {
     812           0 :         poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[1]));
     813           0 :         poFeature->SetField("GEOM_ID", atoi(papoGroup[1]->GetField(3, 8)));
     814             :     }
     815             : 
     816             :     /* -------------------------------------------------------------------- */
     817             :     /*      Collect the chains for each of the rings, and just aggregate    */
     818             :     /*      these into the master list without any concept of where the     */
     819             :     /*      boundaries are.  The boundary information will be emitted      */
     820             :     /*      in the RingStart field.                                         */
     821             :     /* -------------------------------------------------------------------- */
     822           0 :     int nNumLink = 0;
     823             :     int anPolyId[MAX_LINK * 2];
     824             : 
     825           0 :     nNumLink = atoi(papoGroup[0]->GetField(9, 12));
     826           0 :     if (nNumLink < 0 || nNumLink > MAX_LINK)
     827             :     {
     828           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     829             :                  "MAX_LINK exceeded in ntf_generic.cpp.");
     830           0 :         return poFeature;
     831             :     }
     832             : 
     833           0 :     for (int iLink = 0; iLink < nNumLink; iLink++)
     834             :     {
     835           0 :         anPolyId[iLink] =
     836           0 :             atoi(papoGroup[0]->GetField(13 + iLink * 7, 18 + iLink * 7));
     837             :     }
     838             : 
     839             :     // NUM_PARTS
     840           0 :     poFeature->SetField("NUM_PARTS", nNumLink);
     841             : 
     842             :     // POLY_ID
     843           0 :     poFeature->SetField("POLY_ID", nNumLink, anPolyId);
     844             : 
     845           0 :     return poFeature;
     846             : }
     847             : 
     848             : /************************************************************************/
     849             : /*                       EstablishGenericLayers()                       */
     850             : /************************************************************************/
     851             : 
     852           0 : void OGRNTFDataSource::EstablishGenericLayers()
     853             : 
     854             : {
     855             :     /* -------------------------------------------------------------------- */
     856             :     /*      Pick an initial NTFFileReader to build the layers against.      */
     857             :     /* -------------------------------------------------------------------- */
     858           0 :     for (int iFile = 0; iFile < nNTFFileCount; iFile++)
     859             :     {
     860           0 :         int bHasZ = FALSE;
     861             : 
     862           0 :         NTFFileReader *poPReader = papoNTFFileReader[iFile];
     863           0 :         if (poPReader->GetProductId() != NPC_UNKNOWN)
     864           0 :             continue;
     865             : 
     866             :         /* --------------------------------------------------------------------
     867             :          */
     868             :         /*      If any of the generic classes are 3D, then assume all our */
     869             :         /*      geometry should be marked as 3D. */
     870             :         /* --------------------------------------------------------------------
     871             :          */
     872           0 :         for (int iType = 0; iType < 99; iType++)
     873             :         {
     874           0 :             NTFGenericClass *poClass = aoGenericClass + iType;
     875             : 
     876           0 :             if (poClass->nFeatureCount > 0 && poClass->b3D)
     877           0 :                 bHasZ = TRUE;
     878             :         }
     879             : 
     880             :         /* --------------------------------------------------------------------
     881             :          */
     882             :         /*      Create layers for all recognised layer types with features. */
     883             :         /* --------------------------------------------------------------------
     884             :          */
     885           0 :         for (int iType = 0; iType < 99; iType++)
     886             :         {
     887           0 :             NTFGenericClass *poClass = aoGenericClass + iType;
     888             : 
     889           0 :             if (poClass->nFeatureCount == 0)
     890           0 :                 continue;
     891             : 
     892           0 :             if (iType == NRT_POINTREC)
     893             :             {
     894           0 :                 poPReader->EstablishLayer(
     895             :                     "GENERIC_POINT", OGR_GT_SetModifier(wkbPoint, bHasZ, FALSE),
     896             :                     TranslateGenericPoint, NRT_POINTREC, poClass, "POINT_ID",
     897             :                     OFTInteger, 6, 0, NULL);
     898             :             }
     899           0 :             else if (iType == NRT_LINEREC)
     900             :             {
     901           0 :                 poPReader->EstablishLayer(
     902             :                     "GENERIC_LINE",
     903             :                     OGR_GT_SetModifier(wkbLineString, bHasZ, FALSE),
     904             :                     TranslateGenericLine, NRT_LINEREC, poClass, "LINE_ID",
     905             :                     OFTInteger, 6, 0, NULL);
     906             :             }
     907           0 :             else if (iType == NRT_TEXTREC)
     908             :             {
     909           0 :                 poPReader->EstablishLayer(
     910             :                     "GENERIC_TEXT", OGR_GT_SetModifier(wkbPoint, bHasZ, FALSE),
     911             :                     TranslateGenericText, NRT_TEXTREC, poClass, "TEXT_ID",
     912             :                     OFTInteger, 6, 0, NULL);
     913             :             }
     914           0 :             else if (iType == NRT_NAMEREC)
     915             :             {
     916           0 :                 poPReader->EstablishLayer(
     917             :                     "GENERIC_NAME", OGR_GT_SetModifier(wkbPoint, bHasZ, FALSE),
     918             :                     TranslateGenericName, NRT_NAMEREC, poClass, "NAME_ID",
     919             :                     OFTInteger, 6, 0, NULL);
     920             :             }
     921           0 :             else if (iType == NRT_NODEREC)
     922             :             {
     923           0 :                 poPReader->EstablishLayer(
     924             :                     "GENERIC_NODE", OGR_GT_SetModifier(wkbPoint, bHasZ, FALSE),
     925             :                     TranslateGenericNode, NRT_NODEREC, poClass, "NODE_ID",
     926             :                     OFTInteger, 6, 0, "NUM_LINKS", OFTInteger, 4, 0,
     927             :                     "GEOM_ID_OF_LINK", OFTIntegerList, 6, 0, "DIR",
     928             :                     OFTIntegerList, 1, 0, NULL);
     929             :             }
     930           0 :             else if (iType == NRT_COLLECT)
     931             :             {
     932           0 :                 poPReader->EstablishLayer(
     933             :                     "GENERIC_COLLECTION", wkbNone, TranslateGenericCollection,
     934             :                     NRT_COLLECT, poClass, "COLL_ID", OFTInteger, 6, 0,
     935             :                     "NUM_PARTS", OFTInteger, 4, 0, "TYPE", OFTIntegerList, 2, 0,
     936             :                     "ID", OFTIntegerList, 6, 0, NULL);
     937             :             }
     938           0 :             else if (iType == NRT_POLYGON)
     939             :             {
     940           0 :                 poPReader->EstablishLayer(
     941             :                     "GENERIC_POLY", OGR_GT_SetModifier(wkbPoint, bHasZ, FALSE),
     942             :                     TranslateGenericPoly, NRT_POLYGON, poClass, "POLY_ID",
     943             :                     OFTInteger, 6, 0, "NUM_PARTS", OFTInteger, 4, 0, "DIR",
     944             :                     OFTIntegerList, 1, 0, "GEOM_ID_OF_LINK", OFTIntegerList, 6,
     945             :                     0, "RingStart", OFTIntegerList, 6, 0, NULL);
     946             :             }
     947           0 :             else if (iType == NRT_CPOLY)
     948             :             {
     949           0 :                 poPReader->EstablishLayer(
     950             :                     "GENERIC_CPOLY", OGR_GT_SetModifier(wkbPoint, bHasZ, FALSE),
     951             :                     TranslateGenericCPoly, NRT_CPOLY, poClass, "CPOLY_ID",
     952             :                     OFTInteger, 6, 0, "NUM_PARTS", OFTInteger, 4, 0, "POLY_ID",
     953             :                     OFTIntegerList, 1, 0, NULL);
     954             :             }
     955             :         }
     956             :     }
     957           0 : }

Generated by: LCOV version 1.14