LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/ntf - ntf_estlayers.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 0 730 0.0 %
Date: 2024-11-25 13:07:18 Functions: 0 34 0.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  NTF Translator
       4             :  * Purpose:  NTFFileReader methods related to establishing the schemas
       5             :  *           of features that could occur in this product and the functions
       6             :  *           for actually performing the NTFRecord to OGRFeature conversion.
       7             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       8             :  *
       9             :  ******************************************************************************
      10             :  * Copyright (c) 1999, Frank Warmerdam
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #include <stdarg.h>
      16             : #include "ntf.h"
      17             : #include "cpl_string.h"
      18             : 
      19             : /************************************************************************/
      20             : /*                         TranslateCodePoint()                         */
      21             : /*                                                                      */
      22             : /*      Used for code point, and code point plus.                       */
      23             : /************************************************************************/
      24             : 
      25           0 : static OGRFeature *TranslateCodePoint(NTFFileReader *poReader,
      26             :                                       OGRNTFLayer *poLayer,
      27             :                                       NTFRecord **papoGroup)
      28             : 
      29             : {
      30           0 :     if (CSLCount((char **)papoGroup) < 2 ||
      31           0 :         papoGroup[0]->GetType() != NRT_POINTREC ||
      32           0 :         papoGroup[1]->GetType() != NRT_GEOMETRY)
      33           0 :         return nullptr;
      34             : 
      35           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
      36             : 
      37             :     // POINT_ID
      38           0 :     poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
      39             : 
      40             :     // Geometry
      41           0 :     poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[1]));
      42             : 
      43             :     // Attributes
      44           0 :     if (EQUAL(poLayer->GetLayerDefn()->GetName(), "CODE_POINT"))
      45           0 :         poReader->ApplyAttributeValues(
      46             :             poFeature, papoGroup, "PC", 1, "PQ", 2, "PR", 3, "TP", 4, "DQ", 5,
      47             :             "RP", 6, "BP", 7, "PD", 8, "MP", 9, "UM", 10, "RV", 11, NULL);
      48             :     else
      49           0 :         poReader->ApplyAttributeValues(
      50             :             poFeature, papoGroup, "PC", 1, "PQ", 2, "PR", 3, "TP", 4, "DQ", 5,
      51             :             "RP", 6, "BP", 7, "PD", 8, "MP", 9, "UM", 10, "RV", 11, "RH", 12,
      52             :             "LH", 13, "CC", 14, "DC", 15, "WC", 16, NULL);
      53             : 
      54           0 :     return poFeature;
      55             : }
      56             : 
      57             : /************************************************************************/
      58             : /*                       TranslateAddressPoint()                        */
      59             : /************************************************************************/
      60             : 
      61           0 : static OGRFeature *TranslateAddressPoint(NTFFileReader *poReader,
      62             :                                          OGRNTFLayer *poLayer,
      63             :                                          NTFRecord **papoGroup)
      64             : 
      65             : {
      66           0 :     if (CSLCount((char **)papoGroup) < 2 ||
      67           0 :         papoGroup[0]->GetType() != NRT_POINTREC ||
      68           0 :         papoGroup[1]->GetType() != NRT_GEOMETRY)
      69           0 :         return nullptr;
      70             : 
      71           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
      72             : 
      73             :     // POINT_ID
      74           0 :     poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
      75             : 
      76             :     // CHG_TYPE
      77           0 :     poFeature->SetField(17, papoGroup[0]->GetField(22, 22));
      78             : 
      79             :     // CHG_DATE
      80           0 :     poFeature->SetField(18, papoGroup[0]->GetField(23, 28));
      81             : 
      82             :     // Geometry
      83           0 :     poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[1]));
      84             : 
      85             :     // Attributes
      86           0 :     poReader->ApplyAttributeValues(
      87             :         poFeature, papoGroup, "OA", 1, "ON", 2, "DP", 3, "PB", 4, "SB", 5, "BD",
      88             :         6, "BN", 7, "DR", 8, "TN", 9, "DD", 10, "DL", 11, "PT", 12, "CN", 13,
      89             :         "PC", 14, "SF", 15, "RV", 16, NULL);
      90             : 
      91           0 :     return poFeature;
      92             : }
      93             : 
      94             : /************************************************************************/
      95             : /*                        TranslateOscarPoint()                         */
      96             : /*                                                                      */
      97             : /*      Used for OSCAR Traffic and Asset datasets.                      */
      98             : /************************************************************************/
      99             : 
     100           0 : static OGRFeature *TranslateOscarPoint(NTFFileReader *poReader,
     101             :                                        OGRNTFLayer *poLayer,
     102             :                                        NTFRecord **papoGroup)
     103             : 
     104             : {
     105           0 :     if (CSLCount((char **)papoGroup) < 2 ||
     106           0 :         papoGroup[0]->GetType() != NRT_POINTREC ||
     107           0 :         papoGroup[1]->GetType() != NRT_GEOMETRY)
     108           0 :         return nullptr;
     109             : 
     110           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
     111             : 
     112             :     // POINT_ID
     113           0 :     poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
     114             : 
     115             :     // Geometry
     116           0 :     int nGeomId = 0;
     117             : 
     118           0 :     poFeature->SetGeometryDirectly(
     119           0 :         poReader->ProcessGeometry(papoGroup[1], &nGeomId));
     120             : 
     121           0 :     poFeature->SetField(1, nGeomId);
     122             : 
     123             :     // Attributes
     124           0 :     poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 2, "OD", 3, "JN",
     125             :                                    4, "SN", 5, NULL);
     126             : 
     127           0 :     return poFeature;
     128             : }
     129             : 
     130             : /************************************************************************/
     131             : /*                         TranslateOscarLine()                         */
     132             : /************************************************************************/
     133             : 
     134           0 : static OGRFeature *TranslateOscarLine(NTFFileReader *poReader,
     135             :                                       OGRNTFLayer *poLayer,
     136             :                                       NTFRecord **papoGroup)
     137             : 
     138             : {
     139           0 :     if (CSLCount((char **)papoGroup) < 2 ||
     140           0 :         papoGroup[0]->GetType() != NRT_LINEREC ||
     141           0 :         papoGroup[1]->GetType() != NRT_GEOMETRY)
     142           0 :         return nullptr;
     143             : 
     144           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
     145             : 
     146             :     // LINE_ID
     147           0 :     poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
     148             : 
     149             :     // Geometry
     150           0 :     int nGeomId = 0;
     151             : 
     152           0 :     poFeature->SetGeometryDirectly(
     153           0 :         poReader->ProcessGeometry(papoGroup[1], &nGeomId));
     154             : 
     155           0 :     poFeature->SetField(1, nGeomId);
     156             : 
     157             :     // Attributes
     158           0 :     poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 2, "OD", 3, "PN",
     159             :                                    4, "LL", 5, "SC", 6, "FW", 7, "RN", 8, "TR",
     160             :                                    9, NULL);
     161             : 
     162           0 :     return poFeature;
     163             : }
     164             : 
     165             : /************************************************************************/
     166             : /*                      TranslateOscarRoutePoint()                      */
     167             : /************************************************************************/
     168             : 
     169           0 : static OGRFeature *TranslateOscarRoutePoint(NTFFileReader *poReader,
     170             :                                             OGRNTFLayer *poLayer,
     171             :                                             NTFRecord **papoGroup)
     172             : 
     173             : {
     174           0 :     if (CSLCount((char **)papoGroup) < 2 ||
     175           0 :         papoGroup[0]->GetType() != NRT_POINTREC ||
     176           0 :         papoGroup[1]->GetType() != NRT_GEOMETRY)
     177           0 :         return nullptr;
     178             : 
     179           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
     180             : 
     181             :     // POINT_ID
     182           0 :     poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
     183             : 
     184             :     // Geometry
     185           0 :     int nGeomId = 0;
     186             : 
     187           0 :     poFeature->SetGeometryDirectly(
     188           0 :         poReader->ProcessGeometry(papoGroup[1], &nGeomId));
     189             : 
     190           0 :     poFeature->SetField(1, nGeomId);
     191             : 
     192             :     // Attributes
     193           0 :     poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 2, "OD", 3, "JN",
     194             :                                    4, "SN", 5, "NP", 6, "RT", 8, NULL);
     195             : 
     196             :     // PARENT_OSODR
     197             :     char **papszTypes, **papszValues;
     198             : 
     199           0 :     if (poReader->ProcessAttRecGroup(papoGroup, &papszTypes, &papszValues))
     200             :     {
     201           0 :         char **papszOSODRList = nullptr;
     202             : 
     203           0 :         for (int i = 0; papszTypes != nullptr && papszTypes[i] != nullptr; i++)
     204             :         {
     205           0 :             if (EQUAL(papszTypes[i], "PO"))
     206           0 :                 papszOSODRList = CSLAddString(papszOSODRList, papszValues[i]);
     207             :         }
     208             : 
     209           0 :         poFeature->SetField(7, papszOSODRList);
     210           0 :         CPLAssert(CSLCount(papszOSODRList) == poFeature->GetFieldAsInteger(6));
     211             : 
     212           0 :         CSLDestroy(papszOSODRList);
     213           0 :         CSLDestroy(papszTypes);
     214           0 :         CSLDestroy(papszValues);
     215             :     }
     216             : 
     217           0 :     return poFeature;
     218             : }
     219             : 
     220             : /************************************************************************/
     221             : /*                      TranslateOscarRouteLine()                       */
     222             : /************************************************************************/
     223             : 
     224           0 : static OGRFeature *TranslateOscarRouteLine(NTFFileReader *poReader,
     225             :                                            OGRNTFLayer *poLayer,
     226             :                                            NTFRecord **papoGroup)
     227             : 
     228             : {
     229           0 :     if (CSLCount((char **)papoGroup) < 2 ||
     230           0 :         papoGroup[0]->GetType() != NRT_LINEREC ||
     231           0 :         papoGroup[1]->GetType() != NRT_GEOMETRY)
     232           0 :         return nullptr;
     233             : 
     234           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
     235             : 
     236             :     // LINE_ID
     237           0 :     poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
     238             : 
     239             :     // Geometry
     240           0 :     int nGeomId = 0;
     241             : 
     242           0 :     poFeature->SetGeometryDirectly(
     243           0 :         poReader->ProcessGeometry(papoGroup[1], &nGeomId));
     244             : 
     245           0 :     poFeature->SetField(1, nGeomId);
     246             : 
     247             :     // Attributes
     248           0 :     poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 2, "OD", 3, "PN",
     249             :                                    4, "LL", 5, "RN", 6, "TR", 7, "NP", 8, NULL);
     250             : 
     251             :     // PARENT_OSODR
     252             :     char **papszTypes, **papszValues;
     253             : 
     254           0 :     if (poReader->ProcessAttRecGroup(papoGroup, &papszTypes, &papszValues))
     255             :     {
     256           0 :         char **papszOSODRList = nullptr;
     257             : 
     258           0 :         for (int i = 0; papszTypes != nullptr && papszTypes[i] != nullptr; i++)
     259             :         {
     260           0 :             if (EQUAL(papszTypes[i], "PO"))
     261           0 :                 papszOSODRList = CSLAddString(papszOSODRList, papszValues[i]);
     262             :         }
     263             : 
     264           0 :         poFeature->SetField(9, papszOSODRList);
     265           0 :         CPLAssert(CSLCount(papszOSODRList) == poFeature->GetFieldAsInteger(8));
     266             : 
     267           0 :         CSLDestroy(papszOSODRList);
     268           0 :         CSLDestroy(papszTypes);
     269           0 :         CSLDestroy(papszValues);
     270             :     }
     271             : 
     272           0 :     return poFeature;
     273             : }
     274             : 
     275             : /************************************************************************/
     276             : /*                       TranslateOscarComment()                        */
     277             : /************************************************************************/
     278             : 
     279           0 : static OGRFeature *TranslateOscarComment(CPL_UNUSED NTFFileReader *poReader,
     280             :                                          OGRNTFLayer *poLayer,
     281             :                                          NTFRecord **papoGroup)
     282             : 
     283             : {
     284           0 :     if (CSLCount((char **)papoGroup) != 1 ||
     285           0 :         papoGroup[0]->GetType() != NRT_COMMENT)
     286           0 :         return nullptr;
     287             : 
     288           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
     289             : 
     290             :     // RECORD_TYPE
     291           0 :     poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 4)));
     292             : 
     293             :     // RECORD_ID
     294           0 :     poFeature->SetField(1, papoGroup[0]->GetField(5, 17));
     295             : 
     296             :     // CHANGE_TYPE
     297           0 :     poFeature->SetField(2, papoGroup[0]->GetField(18, 18));
     298             : 
     299           0 :     return poFeature;
     300             : }
     301             : 
     302             : /************************************************************************/
     303             : /*                     TranslateOscarNetworkPoint()                     */
     304             : /************************************************************************/
     305             : 
     306           0 : static OGRFeature *TranslateOscarNetworkPoint(NTFFileReader *poReader,
     307             :                                               OGRNTFLayer *poLayer,
     308             :                                               NTFRecord **papoGroup)
     309             : 
     310             : {
     311           0 :     if (CSLCount((char **)papoGroup) < 2 ||
     312           0 :         papoGroup[0]->GetType() != NRT_POINTREC ||
     313           0 :         papoGroup[1]->GetType() != NRT_GEOMETRY)
     314           0 :         return nullptr;
     315             : 
     316           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
     317             : 
     318             :     // POINT_ID
     319           0 :     poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
     320             : 
     321             :     // Geometry
     322           0 :     int nGeomId = 0;
     323             : 
     324           0 :     poFeature->SetGeometryDirectly(
     325           0 :         poReader->ProcessGeometry(papoGroup[1], &nGeomId));
     326             : 
     327           0 :     poFeature->SetField(1, nGeomId);
     328             : 
     329             :     // Attributes
     330           0 :     poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 2, "OD", 3, "JN",
     331             :                                    4, "SN", 5, "RT", 6, NULL);
     332             : 
     333           0 :     return poFeature;
     334             : }
     335             : 
     336             : /************************************************************************/
     337             : /*                      TranslateOscarNetworkLine()                     */
     338             : /************************************************************************/
     339             : 
     340           0 : static OGRFeature *TranslateOscarNetworkLine(NTFFileReader *poReader,
     341             :                                              OGRNTFLayer *poLayer,
     342             :                                              NTFRecord **papoGroup)
     343             : 
     344             : {
     345           0 :     if (CSLCount((char **)papoGroup) < 2 ||
     346           0 :         papoGroup[0]->GetType() != NRT_LINEREC ||
     347           0 :         papoGroup[1]->GetType() != NRT_GEOMETRY)
     348           0 :         return nullptr;
     349             : 
     350           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
     351             : 
     352             :     // LINE_ID
     353           0 :     poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
     354             : 
     355             :     // Geometry
     356           0 :     int nGeomId = 0;
     357             : 
     358           0 :     poFeature->SetGeometryDirectly(
     359           0 :         poReader->ProcessGeometry(papoGroup[1], &nGeomId));
     360             : 
     361           0 :     poFeature->SetField(1, nGeomId);
     362             : 
     363             :     // Attributes
     364           0 :     poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 2, "OD", 3, "PN",
     365             :                                    4, "LL", 5, "RN", 6, NULL);
     366             : 
     367           0 :     return poFeature;
     368             : }
     369             : 
     370             : /************************************************************************/
     371             : /*                       TranslateBasedataPoint()                       */
     372             : /************************************************************************/
     373             : 
     374           0 : static OGRFeature *TranslateBasedataPoint(NTFFileReader *poReader,
     375             :                                           OGRNTFLayer *poLayer,
     376             :                                           NTFRecord **papoGroup)
     377             : 
     378             : {
     379           0 :     if (CSLCount((char **)papoGroup) < 2 ||
     380           0 :         papoGroup[0]->GetType() != NRT_POINTREC ||
     381           0 :         papoGroup[1]->GetType() != NRT_GEOMETRY)
     382           0 :         return nullptr;
     383             : 
     384           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
     385             : 
     386             :     // POINT_ID
     387           0 :     poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
     388             : 
     389             :     // Geometry
     390           0 :     int nGeomId = 0;
     391             : 
     392           0 :     poFeature->SetGeometryDirectly(
     393           0 :         poReader->ProcessGeometry(papoGroup[1], &nGeomId));
     394             : 
     395             :     // GEOM_ID
     396           0 :     poFeature->SetField(1, nGeomId);
     397             : 
     398             :     // Attributes
     399           0 :     poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 2, "PN", 3, "NU",
     400             :                                    4, "CM", 5, "UN", 6, "OR", 7, NULL);
     401             : 
     402           0 :     return poFeature;
     403             : }
     404             : 
     405             : /************************************************************************/
     406             : /*                       TranslateBasedataLine()                        */
     407             : /************************************************************************/
     408             : 
     409           0 : static OGRFeature *TranslateBasedataLine(NTFFileReader *poReader,
     410             :                                          OGRNTFLayer *poLayer,
     411             :                                          NTFRecord **papoGroup)
     412             : 
     413             : {
     414           0 :     if (CSLCount((char **)papoGroup) < 2 ||
     415           0 :         papoGroup[0]->GetType() != NRT_LINEREC ||
     416           0 :         papoGroup[1]->GetType() != NRT_GEOMETRY)
     417           0 :         return nullptr;
     418             : 
     419           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
     420             : 
     421             :     // LINE_ID
     422           0 :     poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
     423             : 
     424             :     // Geometry
     425           0 :     int nGeomId = 0;
     426             : 
     427           0 :     poFeature->SetGeometryDirectly(
     428           0 :         poReader->ProcessGeometry(papoGroup[1], &nGeomId));
     429             : 
     430             :     // GEOM_ID
     431           0 :     poFeature->SetField(2, nGeomId);
     432             : 
     433             :     // Attributes
     434           0 :     poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 1, "PN", 3, "NU",
     435             :                                    4, "RB", 5, NULL);
     436             : 
     437           0 :     return poFeature;
     438             : }
     439             : 
     440             : /************************************************************************/
     441             : /*                  TranslateBoundarylineCollection()                   */
     442             : /************************************************************************/
     443             : 
     444           0 : static OGRFeature *TranslateBoundarylineCollection(NTFFileReader *poReader,
     445             :                                                    OGRNTFLayer *poLayer,
     446             :                                                    NTFRecord **papoGroup)
     447             : 
     448             : {
     449           0 :     if (CSLCount((char **)papoGroup) != 2 ||
     450           0 :         papoGroup[0]->GetType() != NRT_COLLECT ||
     451           0 :         papoGroup[1]->GetType() != NRT_ATTREC)
     452           0 :         return nullptr;
     453             : 
     454           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
     455             : 
     456             :     // COLL_ID
     457           0 :     poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
     458             : 
     459             :     // NUM_PARTS
     460           0 :     int nNumLinks = atoi(papoGroup[0]->GetField(9, 12));
     461             : 
     462           0 :     if (nNumLinks > MAX_LINK)
     463             :     {
     464           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     465             :                  "MAX_LINK exceeded in ntf_estlayers.cpp.");
     466           0 :         return poFeature;
     467             :     }
     468             : 
     469           0 :     poFeature->SetField(1, nNumLinks);
     470             : 
     471             :     // POLY_ID
     472           0 :     int i, anList[MAX_LINK] = {0};
     473             : 
     474           0 :     for (i = 0; i < nNumLinks; i++)
     475           0 :         anList[i] = atoi(papoGroup[0]->GetField(15 + i * 8, 20 + i * 8));
     476             : 
     477           0 :     poFeature->SetField(2, nNumLinks, anList);
     478             : 
     479             :     // Attributes
     480           0 :     poReader->ApplyAttributeValues(poFeature, papoGroup, "AI", 3, "OP", 4, "NM",
     481             :                                    5, NULL);
     482             : 
     483           0 :     return poFeature;
     484             : }
     485             : 
     486             : /************************************************************************/
     487             : /*                     TranslateBoundarylinePoly()                      */
     488             : /************************************************************************/
     489             : 
     490           0 : static OGRFeature *TranslateBoundarylinePoly(NTFFileReader *poReader,
     491             :                                              OGRNTFLayer *poLayer,
     492             :                                              NTFRecord **papoGroup)
     493             : 
     494             : {
     495             :     /* ==================================================================== */
     496             :     /*      Traditional POLYGON record groups.                              */
     497             :     /* ==================================================================== */
     498           0 :     if (CSLCount((char **)papoGroup) == 4 &&
     499           0 :         papoGroup[0]->GetType() == NRT_POLYGON &&
     500           0 :         papoGroup[1]->GetType() == NRT_ATTREC &&
     501           0 :         papoGroup[2]->GetType() == NRT_CHAIN &&
     502           0 :         papoGroup[3]->GetType() == NRT_GEOMETRY)
     503             :     {
     504             : 
     505           0 :         OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
     506             : 
     507             :         // POLY_ID
     508           0 :         poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
     509             : 
     510             :         // NUM_PARTS
     511           0 :         int nNumLinks = atoi(papoGroup[2]->GetField(9, 12));
     512             : 
     513           0 :         if (nNumLinks > MAX_LINK)
     514             :         {
     515           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     516             :                      "MAX_LINK exceeded in ntf_estlayers.cpp.");
     517           0 :             return poFeature;
     518             :         }
     519             : 
     520           0 :         poFeature->SetField(4, nNumLinks);
     521             : 
     522             :         // DIR
     523           0 :         int i, anList[MAX_LINK] = {0};
     524             : 
     525           0 :         for (i = 0; i < nNumLinks; i++)
     526           0 :             anList[i] = atoi(papoGroup[2]->GetField(19 + i * 7, 19 + i * 7));
     527             : 
     528           0 :         poFeature->SetField(5, nNumLinks, anList);
     529             : 
     530             :         // GEOM_ID_OF_LINK
     531           0 :         for (i = 0; i < nNumLinks; i++)
     532           0 :             anList[i] = atoi(papoGroup[2]->GetField(13 + i * 7, 18 + i * 7));
     533             : 
     534           0 :         poFeature->SetField(6, nNumLinks, anList);
     535             : 
     536             :         // RingStart
     537           0 :         int nRingList = 0;
     538           0 :         poFeature->SetField(7, 1, &nRingList);
     539             : 
     540             :         // Attributes
     541           0 :         poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 1, "PI", 2,
     542             :                                        "HA", 3, NULL);
     543             : 
     544             :         // Read point geometry
     545           0 :         poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[3]));
     546             : 
     547             :         // Try to assemble polygon geometry.
     548           0 :         poReader->FormPolygonFromCache(poFeature);
     549             : 
     550           0 :         return poFeature;
     551             :     }
     552             : 
     553             :     /* ==================================================================== */
     554             :     /*      CPOLYGON Group                                                  */
     555             :     /* ==================================================================== */
     556             : 
     557             :     /* -------------------------------------------------------------------- */
     558             :     /*      First we do validation of the grouping.                         */
     559             :     /* -------------------------------------------------------------------- */
     560           0 :     int iRec = 0;  // Used after for.
     561             : 
     562           0 :     for (; papoGroup[iRec] != nullptr && papoGroup[iRec + 1] != nullptr &&
     563           0 :            papoGroup[iRec]->GetType() == NRT_POLYGON &&
     564           0 :            papoGroup[iRec + 1]->GetType() == NRT_CHAIN;
     565           0 :          iRec += 2)
     566             :     {
     567             :     }
     568             : 
     569           0 :     if (CSLCount((char **)papoGroup) != iRec + 3)
     570           0 :         return nullptr;
     571             : 
     572           0 :     if (papoGroup[iRec]->GetType() != NRT_CPOLY ||
     573           0 :         papoGroup[iRec + 1]->GetType() != NRT_ATTREC ||
     574           0 :         papoGroup[iRec + 2]->GetType() != NRT_GEOMETRY)
     575           0 :         return nullptr;
     576             : 
     577             :     /* -------------------------------------------------------------------- */
     578             :     /*      Collect the chains for each of the rings, and just aggregate    */
     579             :     /*      these into the master list without any concept of where the     */
     580             :     /*      boundaries are.  The boundary information will be emitted      */
     581             :     /*      in the RingStart field.                                         */
     582             :     /* -------------------------------------------------------------------- */
     583           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
     584           0 :     int nNumLink = 0;
     585           0 :     int anDirList[MAX_LINK * 2] = {};
     586           0 :     int anGeomList[MAX_LINK * 2] = {};
     587           0 :     int anRingStart[MAX_LINK] = {};
     588           0 :     int nRings = 0;
     589             : 
     590           0 :     for (iRec = 0;
     591           0 :          papoGroup[iRec] != nullptr && papoGroup[iRec + 1] != nullptr &&
     592           0 :          papoGroup[iRec]->GetType() == NRT_POLYGON &&
     593           0 :          papoGroup[iRec + 1]->GetType() == NRT_CHAIN;
     594           0 :          iRec += 2)
     595             :     {
     596           0 :         const int nLineCount = atoi(papoGroup[iRec + 1]->GetField(9, 12));
     597             : 
     598           0 :         anRingStart[nRings++] = nNumLink;
     599             : 
     600           0 :         for (int i = 0; i < nLineCount && nNumLink < MAX_LINK * 2; i++)
     601             :         {
     602           0 :             anDirList[nNumLink] =
     603           0 :                 atoi(papoGroup[iRec + 1]->GetField(19 + i * 7, 19 + i * 7));
     604           0 :             anGeomList[nNumLink] =
     605           0 :                 atoi(papoGroup[iRec + 1]->GetField(13 + i * 7, 18 + i * 7));
     606           0 :             nNumLink++;
     607             :         }
     608             : 
     609           0 :         if (nNumLink == MAX_LINK * 2)
     610             :         {
     611           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     612             :                      "MAX_LINK exceeded in ntf_estlayers.cpp.");
     613             : 
     614           0 :             delete poFeature;
     615           0 :             return nullptr;
     616             :         }
     617             :     }
     618             : 
     619             :     // NUM_PART
     620           0 :     poFeature->SetField(4, nNumLink);
     621             : 
     622             :     // DIR
     623           0 :     poFeature->SetField(5, nNumLink, anDirList);
     624             : 
     625             :     // GEOM_ID_OF_LINK
     626           0 :     poFeature->SetField(6, nNumLink, anGeomList);
     627             : 
     628             :     // RingStart
     629           0 :     poFeature->SetField(7, nRings, anRingStart);
     630             : 
     631             :     /* -------------------------------------------------------------------- */
     632             :     /*      collect information for whole complex polygon.                  */
     633             :     /* -------------------------------------------------------------------- */
     634             :     // POLY_ID
     635           0 :     if (papoGroup[iRec] != nullptr)
     636           0 :         poFeature->SetField(0, atoi(papoGroup[iRec]->GetField(3, 8)));
     637             : 
     638             :     // Attributes
     639           0 :     poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 1, "PI", 2, "HA",
     640             :                                    3, NULL);
     641             : 
     642             :     // point geometry for seed.
     643           0 :     poFeature->SetGeometryDirectly(
     644           0 :         poReader->ProcessGeometry(papoGroup[iRec + 2]));
     645             : 
     646             :     // Try to assemble polygon geometry.
     647           0 :     poReader->FormPolygonFromCache(poFeature);
     648             : 
     649           0 :     return poFeature;
     650             : }
     651             : 
     652             : /************************************************************************/
     653             : /*                     TranslateBoundarylineLink()                      */
     654             : /************************************************************************/
     655             : 
     656           0 : static OGRFeature *TranslateBoundarylineLink(NTFFileReader *poReader,
     657             :                                              OGRNTFLayer *poLayer,
     658             :                                              NTFRecord **papoGroup)
     659             : 
     660             : {
     661           0 :     if (CSLCount((char **)papoGroup) != 2 ||
     662           0 :         papoGroup[0]->GetType() != NRT_GEOMETRY ||
     663           0 :         papoGroup[1]->GetType() != NRT_ATTREC)
     664           0 :         return nullptr;
     665             : 
     666           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
     667             : 
     668             :     // Geometry
     669           0 :     int nGeomId = 0;
     670             : 
     671           0 :     poFeature->SetGeometryDirectly(
     672             :         poReader->ProcessGeometry(papoGroup[0], &nGeomId));
     673             : 
     674             :     // GEOM_ID
     675           0 :     poFeature->SetField(0, nGeomId);
     676             : 
     677             :     // Attributes
     678           0 :     poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 1, "LK", 2, "HW",
     679             :                                    3, NULL);
     680             : 
     681           0 :     return poFeature;
     682             : }
     683             : 
     684             : /************************************************************************/
     685             : /*                        TranslateBL2000Poly()                         */
     686             : /************************************************************************/
     687             : 
     688           0 : static OGRFeature *TranslateBL2000Poly(NTFFileReader *poReader,
     689             :                                        OGRNTFLayer *poLayer,
     690             :                                        NTFRecord **papoGroup)
     691             : 
     692             : {
     693             :     /* ==================================================================== */
     694             :     /*      Traditional POLYGON record groups.                              */
     695             :     /* ==================================================================== */
     696           0 :     if (CSLCount((char **)papoGroup) == 3 &&
     697           0 :         papoGroup[0]->GetType() == NRT_POLYGON &&
     698           0 :         papoGroup[1]->GetType() == NRT_ATTREC &&
     699           0 :         papoGroup[2]->GetType() == NRT_CHAIN)
     700             :     {
     701             : 
     702           0 :         OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
     703             : 
     704             :         // POLY_ID
     705           0 :         poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
     706             : 
     707             :         // NUM_PARTS
     708           0 :         int nNumLinks = atoi(papoGroup[2]->GetField(9, 12));
     709             : 
     710           0 :         if (nNumLinks > MAX_LINK)
     711             :         {
     712           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     713             :                      "MAX_LINK exceeded in ntf_estlayers.cpp.");
     714             : 
     715           0 :             return poFeature;
     716             :         }
     717             : 
     718           0 :         poFeature->SetField(3, nNumLinks);
     719             : 
     720             :         // DIR
     721           0 :         int i, anList[MAX_LINK] = {0};
     722             : 
     723           0 :         for (i = 0; i < nNumLinks; i++)
     724           0 :             anList[i] = atoi(papoGroup[2]->GetField(19 + i * 7, 19 + i * 7));
     725             : 
     726           0 :         poFeature->SetField(4, nNumLinks, anList);
     727             : 
     728             :         // GEOM_ID_OF_LINK
     729           0 :         for (i = 0; i < nNumLinks; i++)
     730           0 :             anList[i] = atoi(papoGroup[2]->GetField(13 + i * 7, 18 + i * 7));
     731             : 
     732           0 :         poFeature->SetField(5, nNumLinks, anList);
     733             : 
     734             :         // RingStart
     735           0 :         int nRingList = 0;
     736           0 :         poFeature->SetField(6, 1, &nRingList);
     737             : 
     738             :         // Attributes
     739           0 :         poReader->ApplyAttributeValues(poFeature, papoGroup, "PI", 1, "HA", 2,
     740             :                                        NULL);
     741             : 
     742             :         // Try to assemble polygon geometry.
     743           0 :         poReader->FormPolygonFromCache(poFeature);
     744             : 
     745           0 :         return poFeature;
     746             :     }
     747             : 
     748             :     /* ==================================================================== */
     749             :     /*      CPOLYGON Group                                                  */
     750             :     /* ==================================================================== */
     751             : 
     752             :     /* -------------------------------------------------------------------- */
     753             :     /*      First we do validation of the grouping.                         */
     754             :     /* -------------------------------------------------------------------- */
     755           0 :     int iRec = 0;  // Used after for.
     756             : 
     757           0 :     for (; papoGroup[iRec] != nullptr && papoGroup[iRec + 1] != nullptr &&
     758           0 :            papoGroup[iRec]->GetType() == NRT_POLYGON &&
     759           0 :            papoGroup[iRec + 1]->GetType() == NRT_CHAIN;
     760           0 :          iRec += 2)
     761             :     {
     762             :     }
     763             : 
     764           0 :     if (CSLCount((char **)papoGroup) != iRec + 2)
     765           0 :         return nullptr;
     766             : 
     767           0 :     if (papoGroup[iRec]->GetType() != NRT_CPOLY ||
     768           0 :         papoGroup[iRec + 1]->GetType() != NRT_ATTREC)
     769           0 :         return nullptr;
     770             : 
     771             :     /* -------------------------------------------------------------------- */
     772             :     /*      Collect the chains for each of the rings, and just aggregate    */
     773             :     /*      these into the master list without any concept of where the     */
     774             :     /*      boundaries are.  The boundary information will be emitted      */
     775             :     /*      in the RingStart field.                                         */
     776             :     /* -------------------------------------------------------------------- */
     777           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
     778           0 :     int nNumLink = 0;
     779           0 :     int anDirList[MAX_LINK * 2] = {};
     780           0 :     int anGeomList[MAX_LINK * 2] = {};
     781           0 :     int anRingStart[MAX_LINK] = {};
     782           0 :     int nRings = 0;
     783             : 
     784           0 :     for (iRec = 0;
     785           0 :          papoGroup[iRec] != nullptr && papoGroup[iRec + 1] != nullptr &&
     786           0 :          papoGroup[iRec]->GetType() == NRT_POLYGON &&
     787           0 :          papoGroup[iRec + 1]->GetType() == NRT_CHAIN;
     788           0 :          iRec += 2)
     789             :     {
     790           0 :         const int nLineCount = atoi(papoGroup[iRec + 1]->GetField(9, 12));
     791             : 
     792           0 :         anRingStart[nRings++] = nNumLink;
     793             : 
     794           0 :         for (int i = 0; i < nLineCount && nNumLink < MAX_LINK * 2; i++)
     795             :         {
     796           0 :             anDirList[nNumLink] =
     797           0 :                 atoi(papoGroup[iRec + 1]->GetField(19 + i * 7, 19 + i * 7));
     798           0 :             anGeomList[nNumLink] =
     799           0 :                 atoi(papoGroup[iRec + 1]->GetField(13 + i * 7, 18 + i * 7));
     800           0 :             nNumLink++;
     801             :         }
     802             : 
     803           0 :         if (nNumLink == MAX_LINK * 2)
     804             :         {
     805           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     806             :                      "MAX_LINK exceeded in ntf_estlayers.cpp.");
     807             : 
     808           0 :             delete poFeature;
     809           0 :             return nullptr;
     810             :         }
     811             :     }
     812             : 
     813             :     // NUM_PART
     814           0 :     poFeature->SetField(3, nNumLink);
     815             : 
     816             :     // DIR
     817           0 :     poFeature->SetField(4, nNumLink, anDirList);
     818             : 
     819             :     // GEOM_ID_OF_LINK
     820           0 :     poFeature->SetField(5, nNumLink, anGeomList);
     821             : 
     822             :     // RingStart
     823           0 :     poFeature->SetField(6, nRings, anRingStart);
     824             : 
     825             :     /* -------------------------------------------------------------------- */
     826             :     /*      collect information for whole complex polygon.                  */
     827             :     /* -------------------------------------------------------------------- */
     828             :     // POLY_ID
     829           0 :     if (papoGroup[iRec] != nullptr)
     830           0 :         poFeature->SetField(0, atoi(papoGroup[iRec]->GetField(3, 8)));
     831             : 
     832             :     // Attributes
     833           0 :     poReader->ApplyAttributeValues(poFeature, papoGroup, "PI", 1, "HA", 2,
     834             :                                    NULL);
     835             : 
     836             :     // Try to assemble polygon geometry.
     837           0 :     poReader->FormPolygonFromCache(poFeature);
     838             : 
     839           0 :     return poFeature;
     840             : }
     841             : 
     842             : /************************************************************************/
     843             : /*                        TranslateBL2000Link()                         */
     844             : /************************************************************************/
     845             : 
     846           0 : static OGRFeature *TranslateBL2000Link(NTFFileReader *poReader,
     847             :                                        OGRNTFLayer *poLayer,
     848             :                                        NTFRecord **papoGroup)
     849             : 
     850             : {
     851           0 :     if (CSLCount((char **)papoGroup) != 3 ||
     852           0 :         papoGroup[0]->GetType() != NRT_LINEREC ||
     853           0 :         papoGroup[1]->GetType() != NRT_GEOMETRY ||
     854           0 :         papoGroup[2]->GetType() != NRT_ATTREC)
     855           0 :         return nullptr;
     856             : 
     857           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
     858             : 
     859             :     // LINE_ID
     860           0 :     poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
     861             : 
     862             :     // Geometry
     863           0 :     int nGeomId = 0;
     864             : 
     865           0 :     poFeature->SetGeometryDirectly(
     866           0 :         poReader->ProcessGeometry(papoGroup[1], &nGeomId));
     867             : 
     868             :     // GEOM_ID
     869           0 :     poFeature->SetField(1, nGeomId);
     870             : 
     871             :     // Attributes
     872           0 :     poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 2, "LK", 3,
     873             :                                    NULL);
     874             : 
     875           0 :     return poFeature;
     876             : }
     877             : 
     878             : /************************************************************************/
     879             : /*                     TranslateBL2000Collection()                      */
     880             : /************************************************************************/
     881             : 
     882           0 : static OGRFeature *TranslateBL2000Collection(NTFFileReader *poReader,
     883             :                                              OGRNTFLayer *poLayer,
     884             :                                              NTFRecord **papoGroup)
     885             : 
     886             : {
     887           0 :     if (CSLCount((char **)papoGroup) < 2 ||
     888           0 :         papoGroup[0]->GetType() != NRT_COLLECT ||
     889           0 :         papoGroup[1]->GetType() != NRT_ATTREC)
     890           0 :         return nullptr;
     891             : 
     892           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
     893             : 
     894             :     // COLL_ID
     895           0 :     poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
     896             : 
     897             :     // NUM_PARTS
     898           0 :     int nNumLinks = atoi(papoGroup[0]->GetField(9, 12));
     899             : 
     900           0 :     if (nNumLinks > MAX_LINK)
     901             :     {
     902           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     903             :                  "MAX_LINK exceeded in ntf_estlayers.cpp.");
     904             : 
     905           0 :         return poFeature;
     906             :     }
     907             : 
     908           0 :     poFeature->SetField(1, nNumLinks);
     909             : 
     910             :     // POLY_ID / COLL_ID_REFS
     911           0 :     int anList[MAX_LINK] = {0}, anCollList[MAX_LINK] = {0};
     912           0 :     int nPolys = 0, nCollections = 0;
     913             : 
     914           0 :     for (int i = 0; i < nNumLinks; i++)
     915             :     {
     916           0 :         if (atoi(papoGroup[0]->GetField(13 + i * 8, 14 + i * 8)) == 34)
     917           0 :             anCollList[nCollections++] =
     918           0 :                 atoi(papoGroup[0]->GetField(15 + i * 8, 20 + i * 8));
     919             :         else
     920           0 :             anList[nPolys++] =
     921           0 :                 atoi(papoGroup[0]->GetField(15 + i * 8, 20 + i * 8));
     922             :     }
     923             : 
     924             :     // coverity[uninit_use_in_call]
     925           0 :     poFeature->SetField(2, nPolys, anList);
     926             :     // coverity[uninit_use_in_call]
     927           0 :     poFeature->SetField(10, nCollections, anCollList);
     928             : 
     929             :     // Attributes
     930             :     // Node that _CODE_DESC values are automatically applied if
     931             :     // the target fields exist.
     932           0 :     poReader->ApplyAttributeValues(poFeature, papoGroup, "AI", 3, "OP", 4, "NM",
     933             :                                    5, "TY", 6, "AC", 7, "NB", 8, "NA", 9, NULL);
     934             : 
     935           0 :     return poFeature;
     936             : }
     937             : 
     938             : /************************************************************************/
     939             : /*                      TranslateMeridianPoint()                        */
     940             : /************************************************************************/
     941             : 
     942           0 : static OGRFeature *TranslateMeridianPoint(NTFFileReader *poReader,
     943             :                                           OGRNTFLayer *poLayer,
     944             :                                           NTFRecord **papoGroup)
     945             : 
     946             : {
     947           0 :     if (CSLCount((char **)papoGroup) < 2 ||
     948           0 :         papoGroup[0]->GetType() != NRT_POINTREC ||
     949           0 :         papoGroup[1]->GetType() != NRT_GEOMETRY)
     950           0 :         return nullptr;
     951             : 
     952           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
     953             : 
     954             :     // POINT_ID
     955           0 :     poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
     956             : 
     957             :     // Geometry
     958           0 :     int nGeomId = 0;
     959             : 
     960           0 :     poFeature->SetGeometryDirectly(
     961           0 :         poReader->ProcessGeometry(papoGroup[1], &nGeomId));
     962             : 
     963             :     // GEOM_ID
     964           0 :     poFeature->SetField(1, nGeomId);
     965             : 
     966             :     // Attributes
     967           0 :     poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 2, "PN", 3, "OS",
     968             :                                    4, "JN", 5, "RT", 6, "SI", 7, "PI", 8, "NM",
     969             :                                    9, "DA", 10, NULL);
     970             : 
     971           0 :     return poFeature;
     972             : }
     973             : 
     974             : /************************************************************************/
     975             : /*                       TranslateMeridianLine()                        */
     976             : /************************************************************************/
     977             : 
     978           0 : static OGRFeature *TranslateMeridianLine(NTFFileReader *poReader,
     979             :                                          OGRNTFLayer *poLayer,
     980             :                                          NTFRecord **papoGroup)
     981             : 
     982             : {
     983           0 :     if (CSLCount((char **)papoGroup) < 2 ||
     984           0 :         papoGroup[0]->GetType() != NRT_LINEREC ||
     985           0 :         papoGroup[1]->GetType() != NRT_GEOMETRY)
     986           0 :         return nullptr;
     987             : 
     988           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
     989             : 
     990             :     // LINE_ID
     991           0 :     poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
     992             : 
     993             :     // Geometry
     994           0 :     int nGeomId = 0;
     995             : 
     996           0 :     poFeature->SetGeometryDirectly(
     997           0 :         poReader->ProcessGeometry(papoGroup[1], &nGeomId));
     998             : 
     999             :     // GEOM_ID
    1000           0 :     poFeature->SetField(2, nGeomId);
    1001             : 
    1002             :     // Attributes
    1003           0 :     poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 1, "OM", 3, "RN",
    1004             :                                    4, "TR", 5, "RI", 6, "LC", 7, "RC", 8, "LD",
    1005             :                                    9, "RD", 10, NULL);
    1006             : 
    1007           0 :     return poFeature;
    1008             : }
    1009             : 
    1010             : /************************************************************************/
    1011             : /*                      TranslateMeridian2Point()                       */
    1012             : /************************************************************************/
    1013             : 
    1014           0 : static OGRFeature *TranslateMeridian2Point(NTFFileReader *poReader,
    1015             :                                            OGRNTFLayer *poLayer,
    1016             :                                            NTFRecord **papoGroup)
    1017             : 
    1018             : {
    1019           0 :     if (CSLCount((char **)papoGroup) < 2 ||
    1020           0 :         papoGroup[0]->GetType() != NRT_POINTREC ||
    1021           0 :         papoGroup[1]->GetType() != NRT_GEOMETRY)
    1022           0 :         return nullptr;
    1023             : 
    1024           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
    1025             : 
    1026             :     // POINT_ID
    1027           0 :     poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
    1028             : 
    1029             :     // Geometry
    1030           0 :     int nGeomId = 0;
    1031             : 
    1032           0 :     poFeature->SetGeometryDirectly(
    1033           0 :         poReader->ProcessGeometry(papoGroup[1], &nGeomId));
    1034             : 
    1035             :     // GEOM_ID
    1036           0 :     poFeature->SetField(1, nGeomId);
    1037             : 
    1038             :     // Attributes
    1039           0 :     poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 2, "PN", 3, "OD",
    1040             :                                    4, "PO", 5, "JN", 6, "RT", 7, "SN", 8, "SI",
    1041             :                                    9, "PI", 10, "NM", 11, "DA", 12, "WA", 13,
    1042             :                                    "HT", 14, "FA", 15, NULL);
    1043             : 
    1044           0 :     return poFeature;
    1045             : }
    1046             : 
    1047             : /************************************************************************/
    1048             : /*                       TranslateMeridian2Line()                       */
    1049             : /************************************************************************/
    1050             : 
    1051           0 : static OGRFeature *TranslateMeridian2Line(NTFFileReader *poReader,
    1052             :                                           OGRNTFLayer *poLayer,
    1053             :                                           NTFRecord **papoGroup)
    1054             : 
    1055             : {
    1056           0 :     if (CSLCount((char **)papoGroup) < 2 ||
    1057           0 :         papoGroup[0]->GetType() != NRT_LINEREC ||
    1058           0 :         papoGroup[1]->GetType() != NRT_GEOMETRY)
    1059           0 :         return nullptr;
    1060             : 
    1061           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
    1062             : 
    1063             :     // LINE_ID
    1064           0 :     poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
    1065             : 
    1066             :     // Geometry
    1067           0 :     int nGeomId = 0;
    1068             : 
    1069           0 :     poFeature->SetGeometryDirectly(
    1070           0 :         poReader->ProcessGeometry(papoGroup[1], &nGeomId));
    1071             : 
    1072             :     // GEOM_ID
    1073           0 :     poFeature->SetField(2, nGeomId);
    1074             : 
    1075             :     // Attributes
    1076           0 :     poReader->ApplyAttributeValues(
    1077             :         poFeature, papoGroup, "FC", 1, "OD", 3, "PO", 4, "RN", 5, "TR", 6, "PN",
    1078             :         7, "RI", 8, "LC", 9, "RC", 10, "LD", 11, "RD", 12, "WI", 14, NULL);
    1079             : 
    1080           0 :     return poFeature;
    1081             : }
    1082             : 
    1083             : /************************************************************************/
    1084             : /*                       TranslateStrategiNode()                        */
    1085             : /*                                                                      */
    1086             : /*      Also used for Meridian, Oscar and BaseData.GB nodes.            */
    1087             : /************************************************************************/
    1088             : 
    1089           0 : static OGRFeature *TranslateStrategiNode(CPL_UNUSED NTFFileReader *poReader,
    1090             :                                          OGRNTFLayer *poLayer,
    1091             :                                          NTFRecord **papoGroup)
    1092             : 
    1093             : {
    1094           0 :     if (CSLCount((char **)papoGroup) != 1 ||
    1095           0 :         papoGroup[0]->GetType() != NRT_NODEREC)
    1096           0 :         return nullptr;
    1097             : 
    1098           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
    1099             : 
    1100             :     // NODE_ID
    1101           0 :     poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
    1102             : 
    1103             :     // GEOM_ID_OF_POINT
    1104           0 :     poFeature->SetField(1, atoi(papoGroup[0]->GetField(9, 14)));
    1105             : 
    1106             :     // NUM_LINKS
    1107           0 :     int nNumLinks = atoi(papoGroup[0]->GetField(15, 18));
    1108             : 
    1109           0 :     if (nNumLinks < 0 || nNumLinks > MAX_LINK)
    1110             :     {
    1111           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1112             :                  "MAX_LINK exceeded in ntf_estlayers.cpp.");
    1113             : 
    1114           0 :         return poFeature;
    1115             :     }
    1116             : 
    1117           0 :     poFeature->SetField(2, nNumLinks);
    1118             : 
    1119             :     // DIR
    1120           0 :     int i, anList[MAX_LINK] = {0};
    1121             : 
    1122           0 :     for (i = 0; i < nNumLinks; i++)
    1123           0 :         anList[i] = atoi(papoGroup[0]->GetField(19 + i * 12, 19 + i * 12));
    1124             : 
    1125           0 :     poFeature->SetField(3, nNumLinks, anList);
    1126             : 
    1127             :     // GEOM_ID_OF_POINT
    1128           0 :     for (i = 0; i < nNumLinks; i++)
    1129           0 :         anList[i] =
    1130           0 :             atoi(papoGroup[0]->GetField(19 + i * 12 + 1, 19 + i * 12 + 6));
    1131             : 
    1132           0 :     poFeature->SetField(4, nNumLinks, anList);
    1133             : 
    1134             :     // LEVEL
    1135           0 :     for (i = 0; i < nNumLinks; i++)
    1136           0 :         anList[i] =
    1137           0 :             atoi(papoGroup[0]->GetField(19 + i * 12 + 11, 19 + i * 12 + 11));
    1138             : 
    1139           0 :     poFeature->SetField(5, nNumLinks, anList);
    1140             : 
    1141             :     // ORIENT (optional)
    1142           0 :     if (EQUAL(poFeature->GetDefnRef()->GetFieldDefn(6)->GetNameRef(), "ORIENT"))
    1143             :     {
    1144           0 :         double adfList[MAX_LINK] = {0};
    1145             : 
    1146           0 :         for (i = 0; i < nNumLinks; i++)
    1147           0 :             adfList[i] = atoi(papoGroup[0]->GetField(19 + i * 12 + 7,
    1148           0 :                                                      19 + i * 12 + 10)) *
    1149             :                          0.1;
    1150             : 
    1151           0 :         poFeature->SetField(6, nNumLinks, adfList);
    1152             :     }
    1153             : 
    1154           0 :     return poFeature;
    1155             : }
    1156             : 
    1157             : /************************************************************************/
    1158             : /*                       TranslateStrategiText()                        */
    1159             : /*                                                                      */
    1160             : /*      Also used for Meridian, BaseData and Generic text.              */
    1161             : /************************************************************************/
    1162             : 
    1163           0 : static OGRFeature *TranslateStrategiText(NTFFileReader *poReader,
    1164             :                                          OGRNTFLayer *poLayer,
    1165             :                                          NTFRecord **papoGroup)
    1166             : 
    1167             : {
    1168           0 :     if (CSLCount((char **)papoGroup) < 4 ||
    1169           0 :         papoGroup[0]->GetType() != NRT_TEXTREC ||
    1170           0 :         papoGroup[1]->GetType() != NRT_TEXTPOS ||
    1171           0 :         papoGroup[2]->GetType() != NRT_TEXTREP ||
    1172           0 :         papoGroup[3]->GetType() != NRT_GEOMETRY)
    1173           0 :         return nullptr;
    1174             : 
    1175           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
    1176             : 
    1177             :     // POINT_ID
    1178           0 :     poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
    1179             : 
    1180             :     // FONT
    1181           0 :     poFeature->SetField(2, atoi(papoGroup[2]->GetField(9, 12)));
    1182             : 
    1183             :     // TEXT_HT
    1184           0 :     poFeature->SetField(3, atoi(papoGroup[2]->GetField(13, 15)) * 0.1);
    1185             : 
    1186             :     // DIG_POSTN
    1187           0 :     poFeature->SetField(4, atoi(papoGroup[2]->GetField(16, 16)));
    1188             : 
    1189             :     // ORIENT
    1190           0 :     poFeature->SetField(5, atoi(papoGroup[2]->GetField(17, 20)) * 0.1);
    1191             : 
    1192             :     // TEXT_HT_GROUND
    1193           0 :     poFeature->SetField(7, poFeature->GetFieldAsDouble(3) *
    1194           0 :                                poReader->GetPaperToGround());
    1195             : 
    1196             :     // Geometry
    1197           0 :     poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[3]));
    1198             : 
    1199             :     // Attributes
    1200           0 :     poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 1, "TX", 6, "DE",
    1201             :                                    8, NULL);
    1202             : 
    1203           0 :     return poFeature;
    1204             : }
    1205             : 
    1206             : /************************************************************************/
    1207             : /*                      TranslateStrategiPoint()                        */
    1208             : /************************************************************************/
    1209             : 
    1210           0 : static OGRFeature *TranslateStrategiPoint(NTFFileReader *poReader,
    1211             :                                           OGRNTFLayer *poLayer,
    1212             :                                           NTFRecord **papoGroup)
    1213             : 
    1214             : {
    1215           0 :     if (CSLCount((char **)papoGroup) < 2 ||
    1216           0 :         papoGroup[0]->GetType() != NRT_POINTREC ||
    1217           0 :         papoGroup[1]->GetType() != NRT_GEOMETRY)
    1218           0 :         return nullptr;
    1219             : 
    1220           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
    1221             : 
    1222             :     // POINT_ID
    1223           0 :     poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
    1224             : 
    1225             :     // Geometry
    1226           0 :     int nGeomId = 0;
    1227             : 
    1228           0 :     poFeature->SetGeometryDirectly(
    1229           0 :         poReader->ProcessGeometry(papoGroup[1], &nGeomId));
    1230             : 
    1231             :     // GEOM_ID
    1232           0 :     poFeature->SetField(10, nGeomId);
    1233             : 
    1234             :     // Attributes
    1235           0 :     poReader->ApplyAttributeValues(
    1236             :         poFeature, papoGroup, "FC", 1, "PN", 2, "NU", 3, "RB", 4, "RU", 5, "AN",
    1237             :         6, "AO", 7, "CM", 8, "UN", 9, "DE", 11, "DN", 12, "FM", 13, "GS", 14,
    1238             :         "HI", 15, "HM", 16, "LO", 17, "OR", 18, "OW", 19, "RJ", 20, "RL", 21,
    1239             :         "RM", 22, "RQ", 23, "RW", 24, "RZ", 25, "UE", 26, NULL);
    1240             : 
    1241           0 :     return poFeature;
    1242             : }
    1243             : 
    1244             : /************************************************************************/
    1245             : /*                       TranslateStrategiLine()                        */
    1246             : /************************************************************************/
    1247             : 
    1248           0 : static OGRFeature *TranslateStrategiLine(NTFFileReader *poReader,
    1249             :                                          OGRNTFLayer *poLayer,
    1250             :                                          NTFRecord **papoGroup)
    1251             : 
    1252             : {
    1253           0 :     if (CSLCount((char **)papoGroup) < 2 ||
    1254           0 :         papoGroup[0]->GetType() != NRT_LINEREC ||
    1255           0 :         papoGroup[1]->GetType() != NRT_GEOMETRY)
    1256           0 :         return nullptr;
    1257             : 
    1258           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
    1259             : 
    1260             :     // LINE_ID
    1261           0 :     poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
    1262             : 
    1263             :     // Geometry
    1264           0 :     int nGeomId = 0;
    1265             : 
    1266           0 :     poFeature->SetGeometryDirectly(
    1267           0 :         poReader->ProcessGeometry(papoGroup[1], &nGeomId));
    1268             : 
    1269             :     // GEOM_ID
    1270           0 :     poFeature->SetField(3, nGeomId);
    1271             : 
    1272             :     // Attributes
    1273           0 :     poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 1, "PN", 2, "DE",
    1274             :                                    4, "FE", 5, "FF", 6, "FI", 7, "FM", 8, "FP",
    1275             :                                    9, "FR", 10, "FT", 11, "GS", 12, "NU", 13,
    1276             :                                    "TX", 14, NULL);
    1277             : 
    1278           0 :     return poFeature;
    1279             : }
    1280             : 
    1281             : /************************************************************************/
    1282             : /*                      TranslateLandrangerPoint()                      */
    1283             : /************************************************************************/
    1284             : 
    1285           0 : static OGRFeature *TranslateLandrangerPoint(NTFFileReader *poReader,
    1286             :                                             OGRNTFLayer *poLayer,
    1287             :                                             NTFRecord **papoGroup)
    1288             : 
    1289             : {
    1290           0 :     if (CSLCount((char **)papoGroup) != 2 ||
    1291           0 :         papoGroup[0]->GetType() != NRT_POINTREC ||
    1292           0 :         papoGroup[1]->GetType() != NRT_GEOMETRY)
    1293           0 :         return nullptr;
    1294             : 
    1295           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
    1296             : 
    1297             :     // POINT_ID
    1298           0 :     poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
    1299             : 
    1300             :     // FEAT_CODE
    1301           0 :     poFeature->SetField(1, papoGroup[0]->GetField(17, 20));
    1302             : 
    1303             :     // HEIGHT
    1304           0 :     poFeature->SetField(2, atoi(papoGroup[0]->GetField(11, 16)));
    1305             : 
    1306             :     // Geometry
    1307           0 :     poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[1]));
    1308             : 
    1309           0 :     return poFeature;
    1310             : }
    1311             : 
    1312             : /************************************************************************/
    1313             : /*                      TranslateLandrangerLine()                       */
    1314             : /************************************************************************/
    1315             : 
    1316           0 : static OGRFeature *TranslateLandrangerLine(NTFFileReader *poReader,
    1317             :                                            OGRNTFLayer *poLayer,
    1318             :                                            NTFRecord **papoGroup)
    1319             : 
    1320             : {
    1321           0 :     if (CSLCount((char **)papoGroup) != 2 ||
    1322           0 :         papoGroup[0]->GetType() != NRT_LINEREC ||
    1323           0 :         papoGroup[1]->GetType() != NRT_GEOMETRY)
    1324           0 :         return nullptr;
    1325             : 
    1326           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
    1327             : 
    1328             :     // LINE_ID
    1329           0 :     poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
    1330             : 
    1331             :     // FEAT_CODE
    1332           0 :     poFeature->SetField(1, papoGroup[0]->GetField(17, 20));
    1333             : 
    1334             :     // HEIGHT
    1335           0 :     poFeature->SetField(2, atoi(papoGroup[0]->GetField(11, 16)));
    1336             : 
    1337             :     // Geometry
    1338           0 :     poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[1]));
    1339             : 
    1340           0 :     return poFeature;
    1341             : }
    1342             : 
    1343             : /************************************************************************/
    1344             : /*                       TranslateProfilePoint()                        */
    1345             : /************************************************************************/
    1346             : 
    1347           0 : static OGRFeature *TranslateProfilePoint(NTFFileReader *poReader,
    1348             :                                          OGRNTFLayer *poLayer,
    1349             :                                          NTFRecord **papoGroup)
    1350             : 
    1351             : {
    1352           0 :     if (CSLCount((char **)papoGroup) < 2 ||
    1353           0 :         papoGroup[0]->GetType() != NRT_POINTREC ||
    1354           0 :         (papoGroup[1]->GetType() != NRT_GEOMETRY &&
    1355           0 :          papoGroup[1]->GetType() != NRT_GEOMETRY3D))
    1356           0 :         return nullptr;
    1357             : 
    1358           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
    1359             : 
    1360             :     // POINT_ID
    1361           0 :     poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
    1362             : 
    1363             :     // FEAT_CODE
    1364           0 :     poFeature->SetField(1, papoGroup[0]->GetField(17, 20));
    1365             : 
    1366             :     // Geometry
    1367           0 :     poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[1]));
    1368             : 
    1369             :     // Attributes
    1370           0 :     poReader->ApplyAttributeValues(poFeature, papoGroup, "HT", 2, NULL);
    1371             : 
    1372             :     // Set HEIGHT/elevation
    1373           0 :     OGRPoint *poPoint = dynamic_cast<OGRPoint *>(poFeature->GetGeometryRef());
    1374             : 
    1375           0 :     if (poPoint != nullptr && poPoint->getCoordinateDimension() == 3)
    1376             :     {
    1377           0 :         poFeature->SetField(2, poPoint->getZ());
    1378             :     }
    1379           0 :     else if (poPoint != nullptr)
    1380             :     {
    1381           0 :         poFeature->SetField(2, poFeature->GetFieldAsDouble(2) * 0.01);
    1382           0 :         poPoint->setZ(poFeature->GetFieldAsDouble(2));
    1383             :     }
    1384             : 
    1385           0 :     return poFeature;
    1386             : }
    1387             : 
    1388             : /************************************************************************/
    1389             : /*                      TranslateProfileLine()                          */
    1390             : /************************************************************************/
    1391             : 
    1392           0 : static OGRFeature *TranslateProfileLine(NTFFileReader *poReader,
    1393             :                                         OGRNTFLayer *poLayer,
    1394             :                                         NTFRecord **papoGroup)
    1395             : 
    1396             : {
    1397           0 :     if (CSLCount((char **)papoGroup) < 2 ||
    1398           0 :         papoGroup[0]->GetType() != NRT_LINEREC ||
    1399           0 :         (papoGroup[1]->GetType() != NRT_GEOMETRY &&
    1400           0 :          papoGroup[1]->GetType() != NRT_GEOMETRY3D))
    1401           0 :         return nullptr;
    1402             : 
    1403           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
    1404             : 
    1405             :     // LINE_ID
    1406           0 :     poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
    1407             : 
    1408             :     // FEAT_CODE
    1409           0 :     poFeature->SetField(1, papoGroup[0]->GetField(17, 20));
    1410             : 
    1411             :     // Geometry
    1412           0 :     poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[1]));
    1413             : 
    1414             :     // Attributes
    1415           0 :     poReader->ApplyAttributeValues(poFeature, papoGroup, "HT", 2, NULL);
    1416             : 
    1417             :     // Set HEIGHT/elevation
    1418             :     OGRLineString *poLine =
    1419           0 :         dynamic_cast<OGRLineString *>(poFeature->GetGeometryRef());
    1420             : 
    1421           0 :     poFeature->SetField(2, poFeature->GetFieldAsDouble(2) * 0.01);
    1422           0 :     if (poLine != nullptr && poLine->getCoordinateDimension() == 2)
    1423             :     {
    1424           0 :         for (int i = 0; i < poLine->getNumPoints(); i++)
    1425             :         {
    1426           0 :             poLine->setPoint(i, poLine->getX(i), poLine->getY(i),
    1427             :                              poFeature->GetFieldAsDouble(2));
    1428             :         }
    1429             :     }
    1430           0 :     else if (poLine != nullptr)
    1431             :     {
    1432           0 :         double dfAccum = 0.0;
    1433             : 
    1434           0 :         for (int i = 0; i < poLine->getNumPoints(); i++)
    1435             :         {
    1436           0 :             dfAccum += poLine->getZ(i);
    1437             :         }
    1438           0 :         poFeature->SetField(2, dfAccum / poLine->getNumPoints());
    1439             :     }
    1440             : 
    1441           0 :     return poFeature;
    1442             : }
    1443             : 
    1444             : /************************************************************************/
    1445             : /*                      TranslateLandlinePoint()                        */
    1446             : /************************************************************************/
    1447             : 
    1448           0 : static OGRFeature *TranslateLandlinePoint(NTFFileReader *poReader,
    1449             :                                           OGRNTFLayer *poLayer,
    1450             :                                           NTFRecord **papoGroup)
    1451             : 
    1452             : {
    1453           0 :     if (CSLCount((char **)papoGroup) < 2 ||
    1454           0 :         papoGroup[0]->GetType() != NRT_POINTREC ||
    1455           0 :         papoGroup[1]->GetType() != NRT_GEOMETRY)
    1456           0 :         return nullptr;
    1457             : 
    1458           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
    1459             : 
    1460             :     // POINT_ID
    1461           0 :     poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
    1462             : 
    1463             :     // FEAT_CODE
    1464           0 :     poFeature->SetField(1, papoGroup[0]->GetField(17, 20));
    1465             : 
    1466             :     // ORIENT
    1467           0 :     poFeature->SetField(2, atoi(papoGroup[0]->GetField(11, 16)) * 0.1);
    1468             : 
    1469             :     // DISTANCE
    1470           0 :     poReader->ApplyAttributeValues(poFeature, papoGroup, "DT", 3, NULL);
    1471             : 
    1472             :     // Geometry
    1473           0 :     poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[1]));
    1474             : 
    1475             :     // CHG_DATE (optional)
    1476           0 :     if (poFeature->GetFieldIndex("CHG_DATE") == 4)
    1477             :     {
    1478           0 :         poFeature->SetField(4, papoGroup[0]->GetField(23, 28));
    1479             :     }
    1480             : 
    1481             :     // CHG_TYPE (optional)
    1482           0 :     if (poFeature->GetFieldIndex("CHG_TYPE") == 5)
    1483             :     {
    1484           0 :         poFeature->SetField(5, papoGroup[0]->GetField(22, 22));
    1485             :     }
    1486             : 
    1487           0 :     return poFeature;
    1488             : }
    1489             : 
    1490             : /************************************************************************/
    1491             : /*                       TranslateLandlineLine()                        */
    1492             : /************************************************************************/
    1493             : 
    1494           0 : static OGRFeature *TranslateLandlineLine(NTFFileReader *poReader,
    1495             :                                          OGRNTFLayer *poLayer,
    1496             :                                          NTFRecord **papoGroup)
    1497             : 
    1498             : {
    1499           0 :     if (CSLCount((char **)papoGroup) != 2 ||
    1500           0 :         papoGroup[0]->GetType() != NRT_LINEREC ||
    1501           0 :         papoGroup[1]->GetType() != NRT_GEOMETRY)
    1502           0 :         return nullptr;
    1503             : 
    1504           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
    1505             : 
    1506             :     // LINE_ID
    1507           0 :     poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
    1508             : 
    1509             :     // FEAT_CODE
    1510           0 :     poFeature->SetField(1, papoGroup[0]->GetField(17, 20));
    1511             : 
    1512             :     // Geometry
    1513           0 :     poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[1]));
    1514             : 
    1515             :     // CHG_DATE (optional)
    1516           0 :     if (poFeature->GetFieldIndex("CHG_DATE") == 2)
    1517             :     {
    1518           0 :         poFeature->SetField(2, papoGroup[0]->GetField(23, 28));
    1519             :     }
    1520             : 
    1521             :     // CHG_TYPE (optional)
    1522           0 :     if (poFeature->GetFieldIndex("CHG_TYPE") == 3)
    1523             :     {
    1524           0 :         poFeature->SetField(3, papoGroup[0]->GetField(22, 22));
    1525             :     }
    1526           0 :     return poFeature;
    1527             : }
    1528             : 
    1529             : /************************************************************************/
    1530             : /*                       TranslateLandlineName()                        */
    1531             : /************************************************************************/
    1532             : 
    1533           0 : static OGRFeature *TranslateLandlineName(NTFFileReader *poReader,
    1534             :                                          OGRNTFLayer *poLayer,
    1535             :                                          NTFRecord **papoGroup)
    1536             : 
    1537             : {
    1538           0 :     if (CSLCount((char **)papoGroup) != 3 ||
    1539           0 :         papoGroup[0]->GetType() != NRT_NAMEREC ||
    1540           0 :         papoGroup[1]->GetType() != NRT_NAMEPOSTN ||
    1541           0 :         papoGroup[2]->GetType() != NRT_GEOMETRY)
    1542           0 :         return nullptr;
    1543             : 
    1544           0 :     int nNumChar = atoi(papoGroup[0]->GetField(13, 14));
    1545           0 :     if (nNumChar <= 0)
    1546           0 :         return nullptr;
    1547             : 
    1548           0 :     OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
    1549             : 
    1550             :     // NAME_ID
    1551           0 :     poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8)));
    1552             : 
    1553             :     // TEXT_CODE
    1554           0 :     poFeature->SetField(1, papoGroup[0]->GetField(9, 12));
    1555             : 
    1556             :     // TEXT
    1557           0 :     poFeature->SetField(2, papoGroup[0]->GetField(15, 15 + nNumChar - 1));
    1558             : 
    1559             :     // FONT
    1560           0 :     poFeature->SetField(3, atoi(papoGroup[1]->GetField(3, 6)));
    1561             : 
    1562             :     // TEXT_HT
    1563           0 :     poFeature->SetField(4, atoi(papoGroup[1]->GetField(7, 9)) * 0.1);
    1564             : 
    1565             :     // DIG_POSTN
    1566           0 :     poFeature->SetField(5, atoi(papoGroup[1]->GetField(10, 10)));
    1567             : 
    1568             :     // ORIENT
    1569           0 :     poFeature->SetField(6, CPLAtof(papoGroup[1]->GetField(11, 14)) * 0.1);
    1570             : 
    1571             :     // TEXT_HT_GROUND
    1572           0 :     poFeature->SetField(7, poFeature->GetFieldAsDouble(4) *
    1573           0 :                                poReader->GetPaperToGround());
    1574             : 
    1575             :     // CHG_DATE (optional)
    1576           0 :     if (poFeature->GetFieldIndex("CHG_DATE") == 7)
    1577             :     {
    1578           0 :         poFeature->SetField(8, papoGroup[0]->GetField(15 + nNumChar + 2,
    1579             :                                                       15 + nNumChar + 2 + 5));
    1580             :     }
    1581             : 
    1582             :     // CHG_TYPE (optional)
    1583           0 :     if (poFeature->GetFieldIndex("CHG_TYPE") == 9)
    1584             :     {
    1585           0 :         poFeature->SetField(
    1586             :             9, papoGroup[0]->GetField(15 + nNumChar + 1, 15 + nNumChar + 1));
    1587             :     }
    1588             : 
    1589             :     // Geometry
    1590           0 :     poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[2]));
    1591             : 
    1592           0 :     return poFeature;
    1593             : }
    1594             : 
    1595             : /************************************************************************/
    1596             : /*                           EstablishLayer()                           */
    1597             : /*                                                                      */
    1598             : /*      Establish one layer based on a simplified description of the    */
    1599             : /*      fields to be present.                                           */
    1600             : /************************************************************************/
    1601             : 
    1602           0 : void NTFFileReader::EstablishLayer(const char *pszLayerName,
    1603             :                                    OGRwkbGeometryType eGeomType,
    1604             :                                    NTFFeatureTranslator pfnTranslator,
    1605             :                                    int nLeadRecordType,
    1606             :                                    NTFGenericClass *poClass, ...)
    1607             : 
    1608             : {
    1609             :     /* -------------------------------------------------------------------- */
    1610             :     /*      Does this layer already exist?  If so, we do nothing            */
    1611             :     /*      ... note that we don't check the definition.                    */
    1612             :     /* -------------------------------------------------------------------- */
    1613           0 :     OGRNTFLayer *poLayer = poDS->GetNamedLayer(pszLayerName);
    1614             : 
    1615             :     /* ==================================================================== */
    1616             :     /*      Create a new layer matching the request if we don't already      */
    1617             :     /*      have one.                                                       */
    1618             :     /* ==================================================================== */
    1619           0 :     if (poLayer == nullptr)
    1620             :     {
    1621             :         /* --------------------------------------------------------------------
    1622             :          */
    1623             :         /*      Create a new feature definition. */
    1624             :         /* --------------------------------------------------------------------
    1625             :          */
    1626           0 :         OGRFeatureDefn *poDefn = new OGRFeatureDefn(pszLayerName);
    1627           0 :         poDefn->GetGeomFieldDefn(0)->SetSpatialRef(poDS->DSGetSpatialRef());
    1628           0 :         poDefn->SetGeomType(eGeomType);
    1629           0 :         poDefn->Reference();
    1630             : 
    1631             :         /* --------------------------------------------------------------------
    1632             :          */
    1633             :         /*      Fetch definitions of each field in turn. */
    1634             :         /* --------------------------------------------------------------------
    1635             :          */
    1636             :         va_list hVaArgs;
    1637           0 :         va_start(hVaArgs, poClass);
    1638             :         while (true)
    1639             :         {
    1640           0 :             const char *pszFieldName = va_arg(hVaArgs, const char *);
    1641             : 
    1642           0 :             if (pszFieldName == nullptr)
    1643           0 :                 break;
    1644             : 
    1645           0 :             const OGRFieldType eType = (OGRFieldType)va_arg(hVaArgs, int);
    1646           0 :             const int nWidth = va_arg(hVaArgs, int);
    1647           0 :             const int nPrecision = va_arg(hVaArgs, int);
    1648             : 
    1649           0 :             OGRFieldDefn oFieldDefn(pszFieldName, eType);
    1650           0 :             oFieldDefn.SetWidth(nWidth);
    1651           0 :             oFieldDefn.SetPrecision(nPrecision);
    1652             : 
    1653           0 :             poDefn->AddFieldDefn(&oFieldDefn);
    1654           0 :         }
    1655             : 
    1656           0 :         va_end(hVaArgs);
    1657             : 
    1658             :         /* --------------------------------------------------------------------
    1659             :          */
    1660             :         /*      Add attributes collected in the generic class survey. */
    1661             :         /* --------------------------------------------------------------------
    1662             :          */
    1663           0 :         if (poClass != nullptr)
    1664             :         {
    1665           0 :             for (int iGAtt = 0; iGAtt < poClass->nAttrCount; iGAtt++)
    1666             :             {
    1667           0 :                 const char *pszFormat = poClass->papszAttrFormats[iGAtt];
    1668           0 :                 OGRFieldDefn oFieldDefn(poClass->papszAttrNames[iGAtt],
    1669           0 :                                         OFTInteger);
    1670             : 
    1671           0 :                 if (STARTS_WITH_CI(pszFormat, "I"))
    1672             :                 {
    1673           0 :                     oFieldDefn.SetType(OFTInteger);
    1674           0 :                     oFieldDefn.SetWidth(poClass->panAttrMaxWidth[iGAtt]);
    1675             :                 }
    1676           0 :                 else if (STARTS_WITH_CI(pszFormat, "D") ||
    1677           0 :                          STARTS_WITH_CI(pszFormat, "A"))
    1678             :                 {
    1679           0 :                     oFieldDefn.SetType(OFTString);
    1680           0 :                     oFieldDefn.SetWidth(poClass->panAttrMaxWidth[iGAtt]);
    1681             :                 }
    1682           0 :                 else if (STARTS_WITH_CI(pszFormat, "R"))
    1683             :                 {
    1684           0 :                     oFieldDefn.SetType(OFTReal);
    1685           0 :                     oFieldDefn.SetWidth(poClass->panAttrMaxWidth[iGAtt] + 1);
    1686           0 :                     const size_t nFormatLen = strlen(pszFormat);
    1687           0 :                     if (nFormatLen >= 4 && pszFormat[2] == ',')
    1688           0 :                         oFieldDefn.SetPrecision(atoi(pszFormat + 3));
    1689           0 :                     else if (nFormatLen >= 5 && pszFormat[3] == ',')
    1690           0 :                         oFieldDefn.SetPrecision(atoi(pszFormat + 4));
    1691             :                 }
    1692             : 
    1693           0 :                 poDefn->AddFieldDefn(&oFieldDefn);
    1694             : 
    1695             :                 /*
    1696             :                 ** If this field can appear multiple times, create an
    1697             :                 ** additional attribute to hold lists of values.  This
    1698             :                 ** is always created as a variable length string field.
    1699             :                 */
    1700           0 :                 if (poClass->pabAttrMultiple[iGAtt])
    1701             :                 {
    1702             :                     char szName[128];
    1703             : 
    1704           0 :                     snprintf(szName, sizeof(szName), "%s_LIST",
    1705           0 :                              poClass->papszAttrNames[iGAtt]);
    1706             : 
    1707           0 :                     OGRFieldDefn oFieldDefnL(szName, OFTString);
    1708             : 
    1709           0 :                     poDefn->AddFieldDefn(&oFieldDefnL);
    1710             :                 }
    1711             :             }
    1712             :         }
    1713             : 
    1714             :         /* --------------------------------------------------------------------
    1715             :          */
    1716             :         /*      Add the TILE_REF attribute. */
    1717             :         /* --------------------------------------------------------------------
    1718             :          */
    1719           0 :         OGRFieldDefn oTileID("TILE_REF", OFTString);
    1720             : 
    1721           0 :         oTileID.SetWidth(10);
    1722             : 
    1723           0 :         poDefn->AddFieldDefn(&oTileID);
    1724             : 
    1725             :         /* --------------------------------------------------------------------
    1726             :          */
    1727             :         /*      Create the layer, and give over to the data source object to */
    1728             :         /*      maintain. */
    1729             :         /* --------------------------------------------------------------------
    1730             :          */
    1731           0 :         poLayer = new OGRNTFLayer(poDS, poDefn, pfnTranslator);
    1732             : 
    1733           0 :         poDS->AddLayer(poLayer);
    1734             :     }
    1735             : 
    1736             :     /* -------------------------------------------------------------------- */
    1737             :     /*      Register this translator with this file reader for handling     */
    1738             :     /*      the indicate record type.                                       */
    1739             :     /* -------------------------------------------------------------------- */
    1740           0 :     apoTypeTranslation[nLeadRecordType] = poLayer;
    1741           0 : }
    1742             : 
    1743             : /************************************************************************/
    1744             : /*                          EstablishLayers()                           */
    1745             : /*                                                                      */
    1746             : /*      This method is responsible for creating any missing             */
    1747             : /*      OGRNTFLayers needed for the current product based on the        */
    1748             : /*      product name.                                                   */
    1749             : /*                                                                      */
    1750             : /*      NOTE: Any changes to the order of attribute fields in the       */
    1751             : /*      following EstablishLayer() calls must also result in updates    */
    1752             : /*      to the translate functions.  Changes of names, widths and to    */
    1753             : /*      some extent types can be done without side effects.             */
    1754             : /************************************************************************/
    1755             : 
    1756           0 : void NTFFileReader::EstablishLayers()
    1757             : 
    1758             : {
    1759           0 :     if (poDS == nullptr || fp == nullptr)
    1760           0 :         return;
    1761             : 
    1762           0 :     if (GetProductId() == NPC_LANDLINE)
    1763             :     {
    1764           0 :         EstablishLayer("LANDLINE_POINT", wkbPoint, TranslateLandlinePoint,
    1765             :                        NRT_POINTREC, nullptr, "POINT_ID", OFTInteger, 6, 0,
    1766             :                        "FEAT_CODE", OFTString, 4, 0, "ORIENT", OFTReal, 5, 1,
    1767             :                        "DISTANCE", OFTReal, 6, 3, NULL);
    1768             : 
    1769           0 :         EstablishLayer("LANDLINE_LINE", wkbLineString, TranslateLandlineLine,
    1770             :                        NRT_LINEREC, nullptr, "LINE_ID", OFTInteger, 6, 0,
    1771             :                        "FEAT_CODE", OFTString, 4, 0, NULL);
    1772             : 
    1773           0 :         EstablishLayer("LANDLINE_NAME", wkbPoint, TranslateLandlineName,
    1774             :                        NRT_NAMEREC, nullptr, "NAME_ID", OFTInteger, 6, 0,
    1775             :                        "TEXT_CODE", OFTString, 4, 0, "TEXT", OFTString, 0, 0,
    1776             :                        "FONT", OFTInteger, 4, 0, "TEXT_HT", OFTReal, 4, 1,
    1777             :                        "DIG_POSTN", OFTInteger, 1, 0, "ORIENT", OFTReal, 5, 1,
    1778             :                        "TEXT_HT_GROUND", OFTReal, 10, 3, NULL);
    1779             :     }
    1780           0 :     else if (GetProductId() == NPC_LANDLINE99)
    1781             :     {
    1782           0 :         EstablishLayer("LANDLINE99_POINT", wkbPoint, TranslateLandlinePoint,
    1783             :                        NRT_POINTREC, nullptr, "POINT_ID", OFTInteger, 6, 0,
    1784             :                        "FEAT_CODE", OFTString, 4, 0, "ORIENT", OFTReal, 5, 1,
    1785             :                        "DISTANCE", OFTReal, 6, 3, "CHG_DATE", OFTString, 6, 0,
    1786             :                        "CHG_TYPE", OFTString, 1, 0, NULL);
    1787             : 
    1788           0 :         EstablishLayer("LANDLINE99_LINE", wkbLineString, TranslateLandlineLine,
    1789             :                        NRT_LINEREC, nullptr, "LINE_ID", OFTInteger, 6, 0,
    1790             :                        "FEAT_CODE", OFTString, 4, 0, "CHG_DATE", OFTString, 6,
    1791             :                        0, "CHG_TYPE", OFTString, 1, 0, NULL);
    1792             : 
    1793           0 :         EstablishLayer("LANDLINE99_NAME", wkbPoint, TranslateLandlineName,
    1794             :                        NRT_NAMEREC, nullptr, "NAME_ID", OFTInteger, 6, 0,
    1795             :                        "TEXT_CODE", OFTString, 4, 0, "TEXT", OFTString, 0, 0,
    1796             :                        "FONT", OFTInteger, 4, 0, "TEXT_HT", OFTReal, 4, 1,
    1797             :                        "DIG_POSTN", OFTInteger, 1, 0, "ORIENT", OFTReal, 5, 1,
    1798             :                        "TEXT_HT_GROUND", OFTReal, 10, 3, "CHG_DATE", OFTString,
    1799             :                        6, 0, "CHG_TYPE", OFTString, 1, 0, NULL);
    1800             :     }
    1801           0 :     else if (GetProductId() == NPC_LANDRANGER_CONT)
    1802             :     {
    1803           0 :         EstablishLayer("PANORAMA_POINT", wkbPoint, TranslateLandrangerPoint,
    1804             :                        NRT_POINTREC, nullptr, "POINT_ID", OFTInteger, 6, 0,
    1805             :                        "FEAT_CODE", OFTString, 4, 0, "HEIGHT", OFTReal, 7, 2,
    1806             :                        NULL);
    1807             : 
    1808           0 :         EstablishLayer("PANORAMA_CONTOUR", wkbLineString,
    1809             :                        TranslateLandrangerLine, NRT_LINEREC, nullptr, "LINE_ID",
    1810             :                        OFTInteger, 6, 0, "FEAT_CODE", OFTString, 4, 0, "HEIGHT",
    1811             :                        OFTReal, 7, 2, NULL);
    1812             :     }
    1813           0 :     else if (GetProductId() == NPC_LANDFORM_PROFILE_CONT)
    1814             :     {
    1815           0 :         EstablishLayer("PROFILE_POINT", wkbPoint25D, TranslateProfilePoint,
    1816             :                        NRT_POINTREC, nullptr, "POINT_ID", OFTInteger, 6, 0,
    1817             :                        "FEAT_CODE", OFTString, 4, 0, "HEIGHT", OFTReal, 7, 2,
    1818             :                        NULL);
    1819             : 
    1820           0 :         EstablishLayer("PROFILE_LINE", wkbLineString25D, TranslateProfileLine,
    1821             :                        NRT_LINEREC, nullptr, "LINE_ID", OFTInteger, 6, 0,
    1822             :                        "FEAT_CODE", OFTString, 4, 0, "HEIGHT", OFTReal, 7, 2,
    1823             :                        NULL);
    1824             :     }
    1825           0 :     else if (GetProductId() == NPC_STRATEGI)
    1826             :     {
    1827           0 :         EstablishLayer(
    1828             :             "STRATEGI_POINT", wkbPoint, TranslateStrategiPoint, NRT_POINTREC,
    1829             :             nullptr, "POINT_ID", OFTInteger, 6, 0, "FEAT_CODE", OFTString, 4, 0,
    1830             :             "PROPER_NAME", OFTString, 0, 0, "FEATURE_NUMBER", OFTString, 0, 0,
    1831             :             "RB", OFTString, 1, 0, "RU", OFTString, 1, 0, "AN", OFTString, 0, 0,
    1832             :             "AO", OFTString, 0, 0, "COUNTY_NAME", OFTString, 0, 0,
    1833             :             "UNITARY_NAME", OFTString, 0, 0, "GEOM_ID", OFTInteger, 6, 0,
    1834             :             "DATE", OFTInteger, 8, 0, "DISTRICT_NAME", OFTString, 0, 0,
    1835             :             "FEATURE_NAME", OFTString, 0, 0, "GIS", OFTString, 0, 0,
    1836             :             "HEIGHT_IMPERIAL", OFTInteger, 4, 0, "HEIGHT_METRIC", OFTInteger, 4,
    1837             :             0, "LOCATION", OFTInteger, 1, 0, "ORIENTATION", OFTReal, 4, 1,
    1838             :             "OWNER", OFTString, 0, 0, "RESTRICTION_NORTH", OFTString, 0, 0,
    1839             :             "RESTRICTION_SOUTH", OFTString, 0, 0, "RESTRICTION_EAST", OFTString,
    1840             :             0, 0, "RESTRICTION_WEST", OFTString, 0, 0, "RESTRICTION_CLOCKWISE",
    1841             :             OFTString, 0, 0, "RESTRICTION_ANTICLOCKWISE", OFTString, 0, 0,
    1842             :             "USAGE", OFTInteger, 1, 0, NULL);
    1843             : 
    1844           0 :         EstablishLayer(
    1845             :             "STRATEGI_LINE", wkbLineString, TranslateStrategiLine, NRT_LINEREC,
    1846             :             nullptr, "LINE_ID", OFTInteger, 6, 0, "FEAT_CODE", OFTString, 4, 0,
    1847             :             "PROPER_NAME", OFTString, 0, 0, "GEOM_ID", OFTInteger, 6, 0, "DATE",
    1848             :             OFTInteger, 8, 0, "FERRY_ACCESS", OFTString, 0, 0, "FERRY_FROM",
    1849             :             OFTString, 0, 0, "FERRY_TIME", OFTString, 0, 0, "FEATURE_NAME",
    1850             :             OFTString, 0, 0, "FERRY_TYPE", OFTString, 0, 0,
    1851             :             "FERRY_RESTRICTIONS", OFTString, 0, 0, "FERRY_TO", OFTString, 0, 0,
    1852             :             "GIS", OFTString, 0, 0, "FEATURE_NUMBER", OFTString, 0, 0, NULL);
    1853             : 
    1854           0 :         EstablishLayer(
    1855             :             "STRATEGI_TEXT", wkbPoint, TranslateStrategiText, NRT_TEXTREC,
    1856             :             nullptr, "TEXT_ID", OFTInteger, 6, 0, "FEAT_CODE", OFTString, 4, 0,
    1857             :             "FONT", OFTInteger, 4, 0, "TEXT_HT", OFTReal, 5, 1, "DIG_POSTN",
    1858             :             OFTInteger, 1, 0, "ORIENT", OFTReal, 5, 1, "TEXT", OFTString, 0, 0,
    1859             :             "TEXT_HT_GROUND", OFTReal, 10, 3, "DATE", OFTInteger, 8, 0, NULL);
    1860             : 
    1861           0 :         EstablishLayer("STRATEGI_NODE", wkbNone, TranslateStrategiNode,
    1862             :                        NRT_NODEREC, nullptr, "NODE_ID", OFTInteger, 6, 0,
    1863             :                        "GEOM_ID_OF_POINT", OFTInteger, 6, 0, "NUM_LINKS",
    1864             :                        OFTInteger, 4, 0, "DIR", OFTIntegerList, 1, 0,
    1865             :                        "GEOM_ID_OF_LINK", OFTIntegerList, 6, 0, "LEVEL",
    1866             :                        OFTIntegerList, 1, 0, "ORIENT", OFTRealList, 5, 1, NULL);
    1867             :     }
    1868           0 :     else if (GetProductId() == NPC_MERIDIAN)
    1869             :     {
    1870           0 :         EstablishLayer("MERIDIAN_POINT", wkbPoint, TranslateMeridianPoint,
    1871             :                        NRT_POINTREC, nullptr, "POINT_ID", OFTInteger, 6, 0,
    1872             :                        "GEOM_ID", OFTInteger, 6, 0, "FEAT_CODE", OFTString, 4,
    1873             :                        0, "PROPER_NAME", OFTString, 0, 0, "OSMDR", OFTString,
    1874             :                        13, 0, "JUNCTION_NAME", OFTString, 0, 0, "ROUNDABOUT",
    1875             :                        OFTString, 1, 0, "STATION_ID", OFTString, 13, 0,
    1876             :                        "GLOBAL_ID", OFTInteger, 6, 0, "ADMIN_NAME", OFTString,
    1877             :                        0, 0, "DA_DLUA_ID", OFTString, 13, 0, NULL);
    1878             : 
    1879           0 :         EstablishLayer("MERIDIAN_LINE", wkbLineString, TranslateMeridianLine,
    1880             :                        NRT_LINEREC, nullptr, "LINE_ID", OFTInteger, 6, 0,
    1881             :                        "FEAT_CODE", OFTString, 4, 0, "GEOM_ID", OFTInteger, 6,
    1882             :                        0, "OSMDR", OFTString, 13, 0, "ROAD_NUM", OFTString, 0,
    1883             :                        0, "TRUNK_ROAD", OFTString, 1, 0, "RAIL_ID", OFTString,
    1884             :                        13, 0, "LEFT_COUNTY", OFTInteger, 6, 0, "RIGHT_COUNTY",
    1885             :                        OFTInteger, 6, 0, "LEFT_DISTRICT", OFTInteger, 6, 0,
    1886             :                        "RIGHT_DISTRICT", OFTInteger, 6, 0, NULL);
    1887             : 
    1888           0 :         EstablishLayer("MERIDIAN_TEXT", wkbPoint, TranslateStrategiText,
    1889             :                        NRT_TEXTREC, nullptr, "TEXT_ID", OFTInteger, 6, 0,
    1890             :                        "FEAT_CODE", OFTString, 4, 0, "FONT", OFTInteger, 4, 0,
    1891             :                        "TEXT_HT", OFTReal, 5, 1, "DIG_POSTN", OFTInteger, 1, 0,
    1892             :                        "ORIENT", OFTReal, 5, 1, "TEXT", OFTString, 0, 0,
    1893             :                        "TEXT_HT_GROUND", OFTReal, 10, 3, NULL);
    1894             : 
    1895           0 :         EstablishLayer("MERIDIAN_NODE", wkbNone, TranslateStrategiNode,
    1896             :                        NRT_NODEREC, nullptr, "NODE_ID", OFTInteger, 6, 0,
    1897             :                        "GEOM_ID_OF_POINT", OFTInteger, 6, 0, "NUM_LINKS",
    1898             :                        OFTInteger, 4, 0, "DIR", OFTIntegerList, 1, 0,
    1899             :                        "GEOM_ID_OF_LINK", OFTIntegerList, 6, 0, "LEVEL",
    1900             :                        OFTIntegerList, 1, 0, "ORIENT", OFTRealList, 5, 1, NULL);
    1901             :     }
    1902           0 :     else if (GetProductId() == NPC_MERIDIAN2)
    1903             :     {
    1904           0 :         EstablishLayer(
    1905             :             "MERIDIAN2_POINT", wkbPoint, TranslateMeridian2Point, NRT_POINTREC,
    1906             :             nullptr, "POINT_ID", OFTInteger, 6, 0, "GEOM_ID", OFTInteger, 6, 0,
    1907             :             "FEAT_CODE", OFTString, 4, 0, "PROPER_NAME", OFTString, 0, 0,
    1908             :             "OSODR", OFTString, 13, 0, "PARENT_OSODR", OFTString, 13, 0,
    1909             :             "JUNCTION_NAME", OFTString, 0, 0, "ROUNDABOUT", OFTString, 1, 0,
    1910             :             "SETTLEMENT_NAME", OFTString, 0, 0, "STATION_ID", OFTString, 13, 0,
    1911             :             "GLOBAL_ID", OFTInteger, 6, 0, "ADMIN_NAME", OFTString, 0, 0,
    1912             :             "DA_DLUA_ID", OFTString, 13, 0, "WATER_AREA", OFTString, 13, 0,
    1913             :             "HEIGHT", OFTInteger, 8, 0, "FOREST_ID", OFTString, 13, 0, NULL);
    1914             : 
    1915           0 :         EstablishLayer("MERIDIAN2_LINE", wkbLineString, TranslateMeridian2Line,
    1916             :                        NRT_LINEREC, nullptr, "LINE_ID", OFTInteger, 6, 0,
    1917             :                        "FEAT_CODE", OFTString, 4, 0, "GEOM_ID", OFTInteger, 6,
    1918             :                        0, "OSODR", OFTString, 13, 0, "PARENT_OSODR", OFTString,
    1919             :                        13, 0, "ROAD_NUM", OFTString, 0, 0, "TRUNK_ROAD",
    1920             :                        OFTString, 1, 0, "PROPER_NAME", OFTString, 0, 0,
    1921             :                        "RAIL_ID", OFTString, 13, 0, "LEFT_COUNTY", OFTInteger,
    1922             :                        6, 0, "RIGHT_COUNTY", OFTInteger, 6, 0, "LEFT_DISTRICT",
    1923             :                        OFTInteger, 6, 0, "RIGHT_DISTRICT", OFTInteger, 6, 0,
    1924             :                        "WATER_LINK_ID", OFTString, 13, 0, NULL);
    1925             : 
    1926           0 :         EstablishLayer("MERIDIAN2_TEXT", wkbPoint, TranslateStrategiText,
    1927             :                        NRT_TEXTREC, nullptr, "TEXT_ID", OFTInteger, 6, 0,
    1928             :                        "FEAT_CODE", OFTString, 4, 0, "FONT", OFTInteger, 4, 0,
    1929             :                        "TEXT_HT", OFTReal, 5, 1, "DIG_POSTN", OFTInteger, 1, 0,
    1930             :                        "ORIENT", OFTReal, 5, 1, "TEXT", OFTString, 0, 0,
    1931             :                        "TEXT_HT_GROUND", OFTReal, 10, 3, NULL);
    1932             : 
    1933           0 :         EstablishLayer("MERIDIAN2_NODE", wkbNone, TranslateStrategiNode,
    1934             :                        NRT_NODEREC, nullptr, "NODE_ID", OFTInteger, 6, 0,
    1935             :                        "GEOM_ID_OF_POINT", OFTInteger, 6, 0, "NUM_LINKS",
    1936             :                        OFTInteger, 4, 0, "DIR", OFTIntegerList, 1, 0,
    1937             :                        "GEOM_ID_OF_LINK", OFTIntegerList, 6, 0, "LEVEL",
    1938             :                        OFTIntegerList, 1, 0, "ORIENT", OFTRealList, 5, 1, NULL);
    1939             :     }
    1940           0 :     else if (GetProductId() == NPC_BOUNDARYLINE)
    1941             :     {
    1942           0 :         EstablishLayer("BOUNDARYLINE_LINK", wkbLineString,
    1943             :                        TranslateBoundarylineLink, NRT_GEOMETRY, nullptr,
    1944             :                        "GEOM_ID", OFTInteger, 6, 0, "FEAT_CODE", OFTString, 4,
    1945             :                        0, "GLOBAL_LINK_ID", OFTInteger, 10, 0, "HWM_FLAG",
    1946             :                        OFTInteger, 1, 0, NULL);
    1947             : 
    1948           0 :         EstablishLayer("BOUNDARYLINE_POLY", bCacheLines ? wkbPolygon : wkbPoint,
    1949             :                        TranslateBoundarylinePoly, NRT_POLYGON, nullptr,
    1950             :                        "POLY_ID", OFTInteger, 6, 0, "FEAT_CODE", OFTString, 4,
    1951             :                        0, "GLOBAL_SEED_ID", OFTInteger, 6, 0, "HECTARES",
    1952             :                        OFTReal, 9, 3, "NUM_PARTS", OFTInteger, 4, 0, "DIR",
    1953             :                        OFTIntegerList, 1, 0, "GEOM_ID_OF_LINK", OFTIntegerList,
    1954             :                        6, 0, "RingStart", OFTIntegerList, 6, 0, NULL);
    1955             : 
    1956           0 :         EstablishLayer("BOUNDARYLINE_COLLECTIONS", wkbNone,
    1957             :                        TranslateBoundarylineCollection, NRT_COLLECT, nullptr,
    1958             :                        "COLL_ID", OFTInteger, 6, 0, "NUM_PARTS", OFTInteger, 4,
    1959             :                        0, "POLY_ID", OFTIntegerList, 6, 0, "ADMIN_AREA_ID",
    1960             :                        OFTInteger, 6, 0, "OPCS_CODE", OFTString, 6, 0,
    1961             :                        "ADMIN_NAME", OFTString, 0, 0, NULL);
    1962             :     }
    1963           0 :     else if (GetProductId() == NPC_BL2000)
    1964             :     {
    1965           0 :         EstablishLayer("BL2000_LINK", wkbLineString, TranslateBL2000Link,
    1966             :                        NRT_LINEREC, nullptr, "LINE_ID", OFTInteger, 6, 0,
    1967             :                        "GEOM_ID", OFTInteger, 6, 0, "FEAT_CODE", OFTString, 4,
    1968             :                        0, "GLOBAL_LINK_ID", OFTInteger, 10, 0, NULL);
    1969           0 :         EstablishLayer("BL2000_POLY", bCacheLines ? wkbPolygon : wkbNone,
    1970             :                        TranslateBL2000Poly, NRT_POLYGON, nullptr, "POLY_ID",
    1971             :                        OFTInteger, 6, 0, "GLOBAL_SEED_ID", OFTInteger, 6, 0,
    1972             :                        "HECTARES", OFTReal, 12, 3, "NUM_PARTS", OFTInteger, 4,
    1973             :                        0, "DIR", OFTIntegerList, 1, 0, "GEOM_ID_OF_LINK",
    1974             :                        OFTIntegerList, 6, 0, "RingStart", OFTIntegerList, 6, 0,
    1975             :                        NULL);
    1976           0 :         if (poDS->GetOption("CODELIST") != nullptr &&
    1977           0 :             EQUAL(poDS->GetOption("CODELIST"), "ON"))
    1978           0 :             EstablishLayer(
    1979             :                 "BL2000_COLLECTIONS", wkbNone, TranslateBL2000Collection,
    1980             :                 NRT_COLLECT, nullptr, "COLL_ID", OFTInteger, 6, 0, "NUM_PARTS",
    1981             :                 OFTInteger, 4, 0, "POLY_ID", OFTIntegerList, 6, 0,
    1982             :                 "ADMIN_AREA_ID", OFTInteger, 6, 0, "CENSUS_CODE", OFTString, 7,
    1983             :                 0, "ADMIN_NAME", OFTString, 0, 0, "AREA_TYPE", OFTString, 2, 0,
    1984             :                 "AREA_CODE", OFTString, 3, 0, "NON_TYPE_CODE", OFTString, 3, 0,
    1985             :                 "NON_INLAND_AREA", OFTReal, 12, 3, "COLL_ID_REFS",
    1986             :                 OFTIntegerList, 6, 0, "AREA_TYPE_DESC", OFTString, 0, 0,
    1987             :                 "AREA_CODE_DESC", OFTString, 0, 0, "NON_TYPE_CODE_DESC",
    1988             :                 OFTString, 0, 0, NULL);
    1989             :         else
    1990           0 :             EstablishLayer(
    1991             :                 "BL2000_COLLECTIONS", wkbNone, TranslateBL2000Collection,
    1992             :                 NRT_COLLECT, nullptr, "COLL_ID", OFTInteger, 6, 0, "NUM_PARTS",
    1993             :                 OFTInteger, 4, 0, "POLY_ID", OFTIntegerList, 6, 0,
    1994             :                 "ADMIN_AREA_ID", OFTInteger, 6, 0, "CENSUS_CODE", OFTString, 7,
    1995             :                 0, "ADMIN_NAME", OFTString, 0, 0, "AREA_TYPE", OFTString, 2, 0,
    1996             :                 "AREA_CODE", OFTString, 3, 0, "NON_TYPE_CODE", OFTString, 3, 0,
    1997             :                 "NON_INLAND_AREA", OFTReal, 12, 3, "COLL_ID_REFS",
    1998             :                 OFTIntegerList, 6, 0, NULL);
    1999             :     }
    2000           0 :     else if (GetProductId() == NPC_BASEDATA)
    2001             :     {
    2002           0 :         EstablishLayer(
    2003             :             "BASEDATA_POINT", wkbPoint, TranslateBasedataPoint, NRT_POINTREC,
    2004             :             nullptr, "POINT_ID", OFTInteger, 6, 0, "GEOM_ID", OFTInteger, 6, 0,
    2005             :             "FEAT_CODE", OFTString, 4, 0, "PROPER_NAME", OFTString, 0, 0,
    2006             :             "FEATURE_NUMBER", OFTString, 0, 0, "COUNTY_NAME", OFTString, 0, 0,
    2007             :             "UNITARY_NAME", OFTString, 0, 0, "ORIENT", OFTRealList, 5, 1, NULL);
    2008             : 
    2009           0 :         EstablishLayer("BASEDATA_LINE", wkbLineString, TranslateBasedataLine,
    2010             :                        NRT_LINEREC, nullptr, "LINE_ID", OFTInteger, 6, 0,
    2011             :                        "FEAT_CODE", OFTString, 4, 0, "GEOM_ID", OFTInteger, 6,
    2012             :                        0, "PROPER_NAME", OFTString, 0, 0, "FEATURE_NUMBER",
    2013             :                        OFTString, 0, 0, "RB", OFTString, 1, 0, NULL);
    2014             : 
    2015           0 :         EstablishLayer("BASEDATA_TEXT", wkbPoint, TranslateStrategiText,
    2016             :                        NRT_TEXTREC, nullptr, "TEXT_ID", OFTInteger, 6, 0,
    2017             :                        "FEAT_CODE", OFTString, 4, 0, "FONT", OFTInteger, 4, 0,
    2018             :                        "TEXT_HT", OFTReal, 5, 1, "DIG_POSTN", OFTInteger, 1, 0,
    2019             :                        "ORIENT", OFTReal, 5, 1, "TEXT", OFTString, 0, 0,
    2020             :                        "TEXT_HT_GROUND", OFTReal, 10, 3, NULL);
    2021             : 
    2022           0 :         EstablishLayer("BASEDATA_NODE", wkbNone, TranslateStrategiNode,
    2023             :                        NRT_NODEREC, nullptr, "NODE_ID", OFTInteger, 6, 0,
    2024             :                        "GEOM_ID_OF_POINT", OFTInteger, 6, 0, "NUM_LINKS",
    2025             :                        OFTInteger, 4, 0, "DIR", OFTIntegerList, 1, 0,
    2026             :                        "GEOM_ID_OF_LINK", OFTIntegerList, 6, 0, "LEVEL",
    2027             :                        OFTIntegerList, 1, 0, "ORIENT", OFTRealList, 5, 1, NULL);
    2028             :     }
    2029           0 :     else if (GetProductId() == NPC_OSCAR_ASSET ||
    2030           0 :              GetProductId() == NPC_OSCAR_TRAFFIC)
    2031             :     {
    2032           0 :         EstablishLayer("OSCAR_POINT", wkbPoint, TranslateOscarPoint,
    2033             :                        NRT_POINTREC, nullptr, "POINT_ID", OFTInteger, 6, 0,
    2034             :                        "GEOM_ID", OFTInteger, 6, 0, "FEAT_CODE", OFTString, 4,
    2035             :                        0, "OSODR", OFTString, 13, 0, "JUNCTION_NAME", OFTString,
    2036             :                        0, 0, "SETTLE_NAME", OFTString, 0, 0, NULL);
    2037             : 
    2038           0 :         EstablishLayer(
    2039             :             "OSCAR_LINE", wkbLineString, TranslateOscarLine, NRT_LINEREC,
    2040             :             nullptr, "LINE_ID", OFTInteger, 6, 0, "GEOM_ID", OFTInteger, 6, 0,
    2041             :             "FEAT_CODE", OFTString, 4, 0, "OSODR", OFTString, 13, 0,
    2042             :             "PROPER_NAME", OFTString, 0, 0, "LINE_LENGTH", OFTInteger, 5, 0,
    2043             :             "SOURCE", OFTString, 1, 0, "FORM_OF_WAY", OFTString, 1, 0,
    2044             :             "ROAD_NUM", OFTString, 0, 0, "TRUNK_ROAD", OFTString, 1, 0, NULL);
    2045             : 
    2046           0 :         EstablishLayer("OSCAR_NODE", wkbNone, TranslateStrategiNode,
    2047             :                        NRT_NODEREC, nullptr, "NODE_ID", OFTInteger, 6, 0,
    2048             :                        "GEOM_ID_OF_POINT", OFTInteger, 6, 0, "NUM_LINKS",
    2049             :                        OFTInteger, 4, 0, "DIR", OFTIntegerList, 1, 0,
    2050             :                        "GEOM_ID_OF_LINK", OFTIntegerList, 6, 0, "LEVEL",
    2051             :                        OFTIntegerList, 1, 0, NULL);
    2052             : 
    2053           0 :         EstablishLayer("OSCAR_COMMENT", wkbNone, TranslateOscarComment,
    2054             :                        NRT_COMMENT, nullptr, "RECORD_TYPE", OFTInteger, 2, 0,
    2055             :                        "RECORD_ID", OFTString, 13, 0, "CHANGE_TYPE", OFTString,
    2056             :                        1, 0, NULL);
    2057             :     }
    2058           0 :     else if (GetProductId() == NPC_OSCAR_ROUTE)
    2059             :     {
    2060           0 :         EstablishLayer("OSCAR_ROUTE_POINT", wkbPoint, TranslateOscarRoutePoint,
    2061             :                        NRT_POINTREC, nullptr, "POINT_ID", OFTInteger, 6, 0,
    2062             :                        "GEOM_ID", OFTInteger, 6, 0, "FEAT_CODE", OFTString, 4,
    2063             :                        0, "OSODR", OFTString, 13, 0, "JUNCTION_NAME", OFTString,
    2064             :                        0, 0, "SETTLE_NAME", OFTString, 0, 0, "NUM_PARENTS",
    2065             :                        OFTInteger, 2, 0, "PARENT_OSODR", OFTStringList, 13, 0,
    2066             :                        "ROUNDABOUT", OFTString, 1, 0, NULL);
    2067             : 
    2068           0 :         EstablishLayer("OSCAR_ROUTE_LINE", wkbLineString,
    2069             :                        TranslateOscarRouteLine, NRT_LINEREC, nullptr, "LINE_ID",
    2070             :                        OFTInteger, 6, 0, "GEOM_ID", OFTInteger, 6, 0,
    2071             :                        "FEAT_CODE", OFTString, 4, 0, "OSODR", OFTString, 13, 0,
    2072             :                        "PROPER_NAME", OFTString, 0, 0, "LINE_LENGTH",
    2073             :                        OFTInteger, 5, 0, "ROAD_NUM", OFTString, 0, 0,
    2074             :                        "TRUNK_ROAD", OFTString, 1, 0, "NUM_PARENTS", OFTInteger,
    2075             :                        2, 0, "PARENT_OSODR", OFTStringList, 13, 0, NULL);
    2076             : 
    2077           0 :         EstablishLayer("OSCAR_ROUTE_NODE", wkbNone, TranslateStrategiNode,
    2078             :                        NRT_NODEREC, nullptr, "NODE_ID", OFTInteger, 6, 0,
    2079             :                        "GEOM_ID_OF_POINT", OFTInteger, 6, 0, "NUM_LINKS",
    2080             :                        OFTInteger, 4, 0, "DIR", OFTIntegerList, 1, 0,
    2081             :                        "GEOM_ID_OF_LINK", OFTIntegerList, 6, 0, "LEVEL",
    2082             :                        OFTIntegerList, 1, 0, NULL);
    2083             : 
    2084           0 :         EstablishLayer("OSCAR_COMMENT", wkbNone, TranslateOscarComment,
    2085             :                        NRT_COMMENT, nullptr, "RECORD_TYPE", OFTInteger, 2, 0,
    2086             :                        "RECORD_ID", OFTString, 13, 0, "CHANGE_TYPE", OFTString,
    2087             :                        1, 0, NULL);
    2088             :     }
    2089           0 :     else if (GetProductId() == NPC_OSCAR_NETWORK)
    2090             :     {
    2091           0 :         EstablishLayer("OSCAR_NETWORK_POINT", wkbPoint,
    2092             :                        TranslateOscarNetworkPoint, NRT_POINTREC, nullptr,
    2093             :                        "POINT_ID", OFTInteger, 6, 0, "GEOM_ID", OFTInteger, 6,
    2094             :                        0, "FEAT_CODE", OFTString, 4, 0, "OSODR", OFTString, 13,
    2095             :                        0, "JUNCTION_NAME", OFTString, 0, 0, "SETTLE_NAME",
    2096             :                        OFTString, 0, 0, "ROUNDABOUT", OFTString, 1, 0, NULL);
    2097             : 
    2098           0 :         EstablishLayer("OSCAR_NETWORK_LINE", wkbLineString,
    2099             :                        TranslateOscarNetworkLine, NRT_LINEREC, nullptr,
    2100             :                        "LINE_ID", OFTInteger, 6, 0, "GEOM_ID", OFTInteger, 6, 0,
    2101             :                        "FEAT_CODE", OFTString, 4, 0, "OSODR", OFTString, 13, 0,
    2102             :                        "PROPER_NAME", OFTString, 0, 0, "LINE_LENGTH",
    2103             :                        OFTInteger, 5, 0, "ROAD_NUM", OFTString, 0, 0, NULL);
    2104             : 
    2105           0 :         EstablishLayer("OSCAR_NETWORK_NODE", wkbNone, TranslateStrategiNode,
    2106             :                        NRT_NODEREC, nullptr, "NODE_ID", OFTInteger, 6, 0,
    2107             :                        "GEOM_ID_OF_POINT", OFTInteger, 6, 0, "NUM_LINKS",
    2108             :                        OFTInteger, 4, 0, "DIR", OFTIntegerList, 1, 0,
    2109             :                        "GEOM_ID_OF_LINK", OFTIntegerList, 6, 0, "LEVEL",
    2110             :                        OFTIntegerList, 1, 0, NULL);
    2111             : 
    2112           0 :         EstablishLayer("OSCAR_COMMENT", wkbNone, TranslateOscarComment,
    2113             :                        NRT_COMMENT, nullptr, "RECORD_TYPE", OFTInteger, 2, 0,
    2114             :                        "RECORD_ID", OFTString, 13, 0, "CHANGE_TYPE", OFTString,
    2115             :                        1, 0, NULL);
    2116             :     }
    2117           0 :     else if (GetProductId() == NPC_ADDRESS_POINT)
    2118             :     {
    2119           0 :         EstablishLayer(
    2120             :             "ADDRESS_POINT", wkbPoint, TranslateAddressPoint, NRT_POINTREC,
    2121             :             nullptr, "POINT_ID", OFTInteger, 6, 0, "OSAPR", OFTString, 18, 0,
    2122             :             "ORGANISATION_NAME", OFTString, 0, 0, "DEPARTMENT_NAME", OFTString,
    2123             :             0, 0, "PO_BOX", OFTString, 6, 0, "SUBBUILDING_NAME", OFTString, 0,
    2124             :             0, "BUILDING_NAME", OFTString, 0, 0, "BUILDING_NUMBER", OFTInteger,
    2125             :             4, 0, "DEPENDENT_THOROUGHFARE_NAME", OFTString, 0, 0,
    2126             :             "THOROUGHFARE_NAME", OFTString, 0, 0,
    2127             :             "DOUBLE_DEPENDENT_LOCALITY_NAME", OFTString, 0, 0,
    2128             :             "DEPENDENT_LOCALITY_NAME", OFTString, 0, 0, "POST_TOWN_NAME",
    2129             :             OFTString, 0, 0, "COUNTY_NAME", OFTString, 0, 0, "POSTCODE",
    2130             :             OFTString, 7, 0, "STATUS_FLAG", OFTString, 4, 0, "RM_VERSION_DATE",
    2131             :             OFTString, 8, 0, "CHG_TYPE", OFTString, 1, 0, "CHG_DATE", OFTString,
    2132             :             6, 0, NULL);
    2133             :     }
    2134           0 :     else if (GetProductId() == NPC_CODE_POINT)
    2135             :     {
    2136           0 :         EstablishLayer(
    2137             :             "CODE_POINT", wkbPoint, TranslateCodePoint, NRT_POINTREC, nullptr,
    2138             :             "POINT_ID", OFTInteger, 6, 0, "UNIT_POSTCODE", OFTString, 7, 0,
    2139             :             "POSITIONAL_QUALITY", OFTInteger, 1, 0, "PO_BOX_INDICATOR",
    2140             :             OFTString, 1, 0, "TOTAL_DELIVERY_POINTS", OFTInteger, 3, 0,
    2141             :             "DELIVERY_POINTS", OFTInteger, 3, 0, "DOMESTIC_DELIVERY_POINTS",
    2142             :             OFTInteger, 3, 0, "NONDOMESTIC_DELIVERY_POINTS", OFTInteger, 3, 0,
    2143             :             "POBOX_DELIVERY_POINTS", OFTInteger, 3, 0,
    2144             :             "MATCHED_ADDRESS_PREMISES", OFTInteger, 3, 0,
    2145             :             "UNMATCHED_DELIVERY_POINTS", OFTInteger, 3, 0, "RM_VERSION_DATA",
    2146             :             OFTString, 8, 0, NULL);
    2147             :     }
    2148           0 :     else if (GetProductId() == NPC_CODE_POINT_PLUS)
    2149             :     {
    2150           0 :         EstablishLayer(
    2151             :             "CODE_POINT_PLUS", wkbPoint, TranslateCodePoint, NRT_POINTREC,
    2152             :             nullptr, "POINT_ID", OFTInteger, 6, 0, "UNIT_POSTCODE", OFTString,
    2153             :             7, 0, "POSITIONAL_QUALITY", OFTInteger, 1, 0, "PO_BOX_INDICATOR",
    2154             :             OFTString, 1, 0, "TOTAL_DELIVERY_POINTS", OFTInteger, 3, 0,
    2155             :             "DELIVERY_POINTS", OFTInteger, 3, 0, "DOMESTIC_DELIVERY_POINTS",
    2156             :             OFTInteger, 3, 0, "NONDOMESTIC_DELIVERY_POINTS", OFTInteger, 3, 0,
    2157             :             "POBOX_DELIVERY_POINTS", OFTInteger, 3, 0,
    2158             :             "MATCHED_ADDRESS_PREMISES", OFTInteger, 3, 0,
    2159             :             "UNMATCHED_DELIVERY_POINTS", OFTInteger, 3, 0, "RM_VERSION_DATA",
    2160             :             OFTString, 8, 0, "NHS_REGIONAL_HEALTH_AUTHORITY", OFTString, 3, 0,
    2161             :             "NHS_HEALTH_AUTHORITY", OFTString, 3, 0, "ADMIN_COUNTY", OFTString,
    2162             :             2, 0, "ADMIN_DISTRICT", OFTString, 2, 0, "ADMIN_WARD", OFTString, 2,
    2163             :             0, NULL);
    2164             :     }
    2165             :     else  // generic case
    2166             :     {
    2167           0 :         CPLAssert(GetProductId() == NPC_UNKNOWN);
    2168             : 
    2169           0 :         poDS->WorkupGeneric(this);
    2170             :     }
    2171             : }

Generated by: LCOV version 1.14