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

Generated by: LCOV version 1.14