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

Generated by: LCOV version 1.14