LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/miramon - ogrmiramonlayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1293 1505 85.9 %
Date: 2024-11-21 22:18:42 Functions: 21 21 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implements OGRMiraMonLayer class.
       5             :  * Author:   Abel Pau
       6             :  ******************************************************************************
       7             :  * Copyright (c) 2024, Xavier Pons
       8             :  *
       9             :  * SPDX-License-Identifier: MIT
      10             :  ****************************************************************************/
      11             : #include "ogrmiramon.h"
      12             : 
      13             : #include "mm_gdal_functions.h"  // For MMCreateExtendedDBFIndex()
      14             : #include "mm_rdlayr.h"          // For MMInitLayerToRead()
      15             : #include <algorithm>            // For std::clamp()
      16             : #include <string>               // For std::string
      17             : #include <algorithm>            // For std::max
      18             : 
      19             : /****************************************************************************/
      20             : /*                            OGRMiraMonLayer()                             */
      21             : /****************************************************************************/
      22         201 : OGRMiraMonLayer::OGRMiraMonLayer(GDALDataset *poDS, const char *pszFilename,
      23             :                                  VSILFILE *fp, const OGRSpatialReference *poSRS,
      24             :                                  int bUpdateIn, CSLConstList papszOpenOptions,
      25         201 :                                  struct MiraMonVectMapInfo *MMMap)
      26             :     : m_poDS(poDS), m_poSRS(nullptr), m_poFeatureDefn(nullptr), m_iNextFID(0),
      27             :       phMiraMonLayer(nullptr), hMiraMonLayerPNT(), hMiraMonLayerARC(),
      28             :       hMiraMonLayerPOL(), hMiraMonLayerReadOrNonGeom(), hMMFeature(),
      29         201 :       m_bUpdate(CPL_TO_BOOL(bUpdateIn)),
      30         201 :       m_fp(fp ? fp : VSIFOpenL(pszFilename, (bUpdateIn ? "r+" : "r"))),
      31         201 :       padfValues(nullptr), pnInt64Values(nullptr), bValidFile(false)
      32             : {
      33             : 
      34         201 :     CPLDebugOnly("MiraMon", "Creating/Opening MiraMon layer...");
      35             :     /* -------------------------------------------------------------------- */
      36             :     /*      Create the feature definition                                   */
      37             :     /* -------------------------------------------------------------------- */
      38         201 :     m_poFeatureDefn = new OGRFeatureDefn(CPLGetBasename(pszFilename));
      39         201 :     SetDescription(m_poFeatureDefn->GetName());
      40         201 :     m_poFeatureDefn->Reference();
      41             : 
      42         201 :     if (m_bUpdate)
      43             :     {
      44             :         /* ---------------------------------------------------------------- */
      45             :         /*      Establish the version to use                                */
      46             :         /* ---------------------------------------------------------------- */
      47          82 :         const char *pszVersion = CSLFetchNameValue(papszOpenOptions, "Version");
      48             :         int nMMVersion;
      49             : 
      50          82 :         if (pszVersion)
      51             :         {
      52          10 :             if (EQUAL(pszVersion, "V1.1"))
      53           3 :                 nMMVersion = MM_32BITS_VERSION;
      54           7 :             else if (EQUAL(pszVersion, "V2.0") ||
      55           4 :                      EQUAL(pszVersion, "last_version"))
      56           6 :                 nMMVersion = MM_64BITS_VERSION;
      57             :             else
      58           1 :                 nMMVersion = MM_32BITS_VERSION;  // Default
      59             :         }
      60             :         else
      61          72 :             nMMVersion = MM_32BITS_VERSION;  // Default
      62             : 
      63             :         /* ---------------------------------------------------------------- */
      64             :         /*      Establish the charset of the .dbf files                     */
      65             :         /* ---------------------------------------------------------------- */
      66             :         const char *pszdbfEncoding =
      67          82 :             CSLFetchNameValue(papszOpenOptions, "DBFEncoding");
      68             :         char nMMRecode;
      69             : 
      70          82 :         if (pszdbfEncoding)
      71             :         {
      72           2 :             if (EQUAL(pszdbfEncoding, "UTF8"))
      73           1 :                 nMMRecode = MM_RECODE_UTF8;
      74             :             else  //if (EQUAL(pszdbfEncoding, "ANSI"))
      75           1 :                 nMMRecode = MM_RECODE_ANSI;
      76             :         }
      77             :         else
      78          80 :             nMMRecode = MM_RECODE_ANSI;  // Default
      79             : 
      80             :         /* ----------------------------------------------------------------- */
      81             :         /*   Establish the descriptors language when                         */
      82             :         /*   creating .rel files                                             */
      83             :         /* ----------------------------------------------------------------- */
      84             :         const char *pszLanguage =
      85          82 :             CSLFetchNameValue(papszOpenOptions, "CreationLanguage");
      86             :         char nMMLanguage;
      87             : 
      88          82 :         if (pszLanguage)
      89             :         {
      90           3 :             if (EQUAL(pszLanguage, "CAT"))
      91           1 :                 nMMLanguage = MM_CAT_LANGUAGE;
      92           2 :             else if (EQUAL(pszLanguage, "SPA"))
      93           1 :                 nMMLanguage = MM_SPA_LANGUAGE;
      94             :             else
      95           1 :                 nMMLanguage = MM_ENG_LANGUAGE;
      96             :         }
      97             :         else
      98          79 :             nMMLanguage = MM_DEF_LANGUAGE;  // Default
      99             : 
     100             :         /* ---------------------------------------------------------------- */
     101             :         /*      Preparing to write the layer                                */
     102             :         /* ---------------------------------------------------------------- */
     103             :         // Init the feature (memory, num,...)
     104          82 :         if (MMInitFeature(&hMMFeature))
     105             :         {
     106           0 :             bValidFile = false;
     107           0 :             return;
     108             :         }
     109             : 
     110             :         // Init the Layers (not in disk, only in memory until
     111             :         // the first element is read)
     112          82 :         CPLDebugOnly("MiraMon", "Initializing MiraMon points layer...");
     113          82 :         if (MMInitLayer(&hMiraMonLayerPNT, pszFilename, nMMVersion, nMMRecode,
     114          82 :                         nMMLanguage, nullptr, MM_WRITING_MODE, MMMap))
     115             :         {
     116           0 :             bValidFile = false;
     117           0 :             return;
     118             :         }
     119          82 :         hMiraMonLayerPNT.bIsBeenInit = 0;
     120             : 
     121          82 :         CPLDebugOnly("MiraMon", "Initializing MiraMon arcs layer...");
     122          82 :         if (MMInitLayer(&hMiraMonLayerARC, pszFilename, nMMVersion, nMMRecode,
     123          82 :                         nMMLanguage, nullptr, MM_WRITING_MODE, MMMap))
     124             :         {
     125           0 :             bValidFile = false;
     126           0 :             return;
     127             :         }
     128          82 :         hMiraMonLayerARC.bIsBeenInit = 0;
     129             : 
     130          82 :         CPLDebugOnly("MiraMon", "Initializing MiraMon polygons layer...");
     131          82 :         if (MMInitLayer(&hMiraMonLayerPOL, pszFilename, nMMVersion, nMMRecode,
     132          82 :                         nMMLanguage, nullptr, MM_WRITING_MODE, MMMap))
     133             :         {
     134           0 :             bValidFile = false;
     135           0 :             return;
     136             :         }
     137          82 :         hMiraMonLayerPOL.bIsBeenInit = 0;
     138             : 
     139             :         // Just in case that there is no geometry but some other
     140             :         // information to get. A DBF will be generated
     141          82 :         CPLDebugOnly("MiraMon", "Initializing MiraMon only-ext-DBF layer...");
     142          82 :         if (MMInitLayer(&hMiraMonLayerReadOrNonGeom, pszFilename, nMMVersion,
     143             :                         nMMRecode, nMMLanguage, nullptr, MM_WRITING_MODE,
     144          82 :                         nullptr))
     145             :         {
     146           0 :             bValidFile = false;
     147           0 :             return;
     148             :         }
     149          82 :         hMiraMonLayerPOL.bIsBeenInit = 0;
     150             : 
     151             :         // This helps the map to be created
     152             :         //GetLayerDefn()->SetName(hMiraMonLayerPNT.pszSrcLayerName);
     153          82 :         m_poFeatureDefn->SetName(hMiraMonLayerPNT.pszSrcLayerName);
     154             : 
     155             :         // Saving the HRS in the layer structure
     156          82 :         if (poSRS)
     157             :         {
     158          18 :             const char *pszAuthorityName = poSRS->GetAuthorityName(nullptr);
     159          18 :             const char *pszAuthorityCode = poSRS->GetAuthorityCode(nullptr);
     160             : 
     161          18 :             if (pszAuthorityName && pszAuthorityCode &&
     162          18 :                 EQUAL(pszAuthorityName, "EPSG"))
     163             :             {
     164          18 :                 CPLDebugOnly("MiraMon", "Setting EPSG code %s",
     165             :                              pszAuthorityCode);
     166          18 :                 hMiraMonLayerPNT.pSRS = CPLStrdup(pszAuthorityCode);
     167          18 :                 hMiraMonLayerARC.pSRS = CPLStrdup(pszAuthorityCode);
     168          18 :                 hMiraMonLayerPOL.pSRS = CPLStrdup(pszAuthorityCode);
     169             :             }
     170             :             // In the DBF, there are some reserved fields that need to
     171             :             // know if the layer is geographic or not to write the
     172             :             // precision (they are real)
     173          18 :             if (poSRS->IsGeographic())
     174             :             {
     175           3 :                 hMiraMonLayerPNT.nSRSType = hMiraMonLayerARC.nSRSType =
     176           3 :                     hMiraMonLayerPOL.nSRSType = MM_SRS_LAYER_IS_GEOGRAPHIC_TYPE;
     177             :             }
     178             :             else
     179             :             {
     180          15 :                 hMiraMonLayerPNT.nSRSType = hMiraMonLayerARC.nSRSType =
     181          15 :                     hMiraMonLayerPOL.nSRSType = MM_SRS_LAYER_IS_PROJECTED_TYPE;
     182             :             }
     183             :         }
     184             :         else
     185             :         {
     186          64 :             hMiraMonLayerPNT.nSRSType = hMiraMonLayerARC.nSRSType =
     187          64 :                 hMiraMonLayerPOL.nSRSType = MM_SRS_LAYER_IS_UNKNOWN_TYPE;
     188             :         }
     189             :     }
     190             :     else
     191             :     {
     192         119 :         if (m_fp == nullptr)
     193             :         {
     194           0 :             bValidFile = false;
     195           0 :             return;
     196             :         }
     197             : 
     198             :         /* ------------------------------------------------------------------*/
     199             :         /*      Read the header.                                             */
     200             :         /* ------------------------------------------------------------------*/
     201             :         int nMMLayerVersion;
     202             : 
     203         119 :         if (MMInitLayerToRead(&hMiraMonLayerReadOrNonGeom, m_fp, pszFilename))
     204             :         {
     205           8 :             phMiraMonLayer = &hMiraMonLayerReadOrNonGeom;
     206           8 :             bValidFile = false;
     207           8 :             return;
     208             :         }
     209         111 :         phMiraMonLayer = &hMiraMonLayerReadOrNonGeom;
     210             : 
     211         111 :         nMMLayerVersion = MMGetVectorVersion(&phMiraMonLayer->TopHeader);
     212         111 :         if (nMMLayerVersion == MM_UNKNOWN_VERSION)
     213             :         {
     214           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     215             :                      "MiraMon version file unknown.");
     216           0 :             bValidFile = false;
     217           0 :             return;
     218             :         }
     219         111 :         if (phMiraMonLayer->bIsPoint)
     220             :         {
     221          39 :             if (phMiraMonLayer->TopHeader.bIs3d)
     222          12 :                 m_poFeatureDefn->SetGeomType(wkbPoint25D);
     223             :             else
     224          27 :                 m_poFeatureDefn->SetGeomType(wkbPoint);
     225             :         }
     226          72 :         else if (phMiraMonLayer->bIsArc && !phMiraMonLayer->bIsPolygon)
     227             :         {
     228          28 :             if (phMiraMonLayer->TopHeader.bIs3d)
     229           7 :                 m_poFeatureDefn->SetGeomType(wkbLineString25D);
     230             :             else
     231          21 :                 m_poFeatureDefn->SetGeomType(wkbLineString);
     232             :         }
     233          44 :         else if (phMiraMonLayer->bIsPolygon)
     234             :         {
     235             :             // 3D
     236          44 :             if (phMiraMonLayer->TopHeader.bIs3d)
     237             :             {
     238           6 :                 if (phMiraMonLayer->TopHeader.bIsMultipolygon)
     239           1 :                     m_poFeatureDefn->SetGeomType(wkbMultiPolygon25D);
     240             :                 else
     241           5 :                     m_poFeatureDefn->SetGeomType(wkbPolygon25D);
     242             :             }
     243             :             else
     244             :             {
     245          38 :                 if (phMiraMonLayer->TopHeader.bIsMultipolygon)
     246          20 :                     m_poFeatureDefn->SetGeomType(wkbMultiPolygon);
     247             :                 else
     248          18 :                     m_poFeatureDefn->SetGeomType(wkbPolygon);
     249             :             }
     250             :         }
     251             :         else
     252             :         {
     253           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     254             :                      "MiraMon file type not supported.");
     255           0 :             bValidFile = false;
     256           0 :             return;
     257             :         }
     258             : 
     259         111 :         if (phMiraMonLayer->TopHeader.bIs3d)
     260             :         {
     261             :             const char *szHeight =
     262          25 :                 CSLFetchNameValue(papszOpenOptions, "Height");
     263          25 :             if (szHeight)
     264             :             {
     265           3 :                 if (EQUAL(szHeight, "Highest"))
     266           1 :                     phMiraMonLayer->nSelectCoordz = MM_SELECT_HIGHEST_COORDZ;
     267           2 :                 else if (EQUAL(szHeight, "Lowest"))
     268           1 :                     phMiraMonLayer->nSelectCoordz = MM_SELECT_LOWEST_COORDZ;
     269             :                 else
     270           1 :                     phMiraMonLayer->nSelectCoordz = MM_SELECT_FIRST_COORDZ;
     271             :             }
     272             :             else
     273          22 :                 phMiraMonLayer->nSelectCoordz = MM_SELECT_FIRST_COORDZ;
     274             :         }
     275             : 
     276             :         /* ------------------------------------------------------------ */
     277             :         /*   Establish the descriptors language when                    */
     278             :         /*   opening .rel files                                        */
     279             :         /* ------------------------------------------------------------ */
     280             :         const char *pszLanguage =
     281         111 :             CSLFetchNameValue(papszOpenOptions, "OpenLanguage");
     282             : 
     283         111 :         if (pszLanguage)
     284             :         {
     285           6 :             if (EQUAL(pszLanguage, "CAT"))
     286           2 :                 phMiraMonLayer->nMMLanguage = MM_CAT_LANGUAGE;
     287           4 :             else if (EQUAL(pszLanguage, "SPA"))
     288           2 :                 phMiraMonLayer->nMMLanguage = MM_SPA_LANGUAGE;
     289             :             else
     290           2 :                 phMiraMonLayer->nMMLanguage = MM_ENG_LANGUAGE;
     291             :         }
     292             :         else
     293         105 :             phMiraMonLayer->nMMLanguage = MM_DEF_LANGUAGE;  // Default
     294             : 
     295         111 :         if (phMiraMonLayer->nSRS_EPSG != 0)
     296             :         {
     297          60 :             m_poSRS = new OGRSpatialReference();
     298          60 :             m_poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     299          60 :             if (m_poSRS->importFromEPSG(phMiraMonLayer->nSRS_EPSG) !=
     300             :                 OGRERR_NONE)
     301             :             {
     302           0 :                 delete m_poSRS;
     303           0 :                 m_poSRS = nullptr;
     304             :             }
     305             :             else
     306          60 :                 m_poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(m_poSRS);
     307             :         }
     308             : 
     309             :         // If there is associated information
     310         111 :         if (phMiraMonLayer->pMMBDXP)
     311             :         {
     312         111 :             if (!phMiraMonLayer->pMMBDXP->pfDataBase)
     313             :             {
     314         111 :                 if ((phMiraMonLayer->pMMBDXP->pfDataBase = fopen_function(
     315         111 :                          phMiraMonLayer->pMMBDXP->szFileName, "r")) == nullptr)
     316             :                 {
     317           0 :                     CPLDebugOnly("MiraMon", "File '%s' cannot be opened.",
     318             :                                  phMiraMonLayer->pMMBDXP->szFileName);
     319           0 :                     bValidFile = false;
     320           0 :                     return;
     321             :                 }
     322             : 
     323         111 :                 if (phMiraMonLayer->pMMBDXP->nFields == 0)
     324             :                 {
     325             :                     // TODO: is this correct? At least this prevents a
     326             :                     // nullptr dereference of phMiraMonLayer->pMMBDXP->pField
     327             :                     // below
     328           0 :                     CPLDebug("MiraMon",
     329             :                              "phMiraMonLayer->pMMBDXP->nFields == 0");
     330           0 :                     bValidFile = false;
     331           0 :                     return;
     332             :                 }
     333             : 
     334             :                 // First time we open the extended DBF we create an index
     335             :                 // to fastly find all non geometrical features.
     336         222 :                 phMiraMonLayer->pMultRecordIndex = MMCreateExtendedDBFIndex(
     337         111 :                     phMiraMonLayer->pMMBDXP->pfDataBase,
     338         111 :                     phMiraMonLayer->pMMBDXP->nRecords,
     339         111 :                     phMiraMonLayer->pMMBDXP->FirstRecordOffset,
     340         111 :                     phMiraMonLayer->pMMBDXP->BytesPerRecord,
     341         111 :                     phMiraMonLayer->pMMBDXP
     342         111 :                         ->pField[phMiraMonLayer->pMMBDXP->IdGraficField]
     343             :                         .AccumulatedBytes,
     344         111 :                     phMiraMonLayer->pMMBDXP
     345         111 :                         ->pField[phMiraMonLayer->pMMBDXP->IdGraficField]
     346             :                         .BytesPerField,
     347         111 :                     &phMiraMonLayer->isListField, &phMiraMonLayer->nMaxN);
     348             : 
     349             :                 // Creation of maximum number needed for processing
     350             :                 // multiple records
     351         111 :                 if (phMiraMonLayer->pMultRecordIndex)
     352             :                 {
     353         204 :                     padfValues = static_cast<double *>(CPLCalloc(
     354         102 :                         (size_t)phMiraMonLayer->nMaxN, sizeof(*padfValues)));
     355             : 
     356         102 :                     pnInt64Values = static_cast<GInt64 *>(CPLCalloc(
     357         102 :                         (size_t)phMiraMonLayer->nMaxN, sizeof(*pnInt64Values)));
     358             :                 }
     359             : 
     360         111 :                 phMiraMonLayer->iMultiRecord =
     361             :                     MM_MULTIRECORD_NO_MULTIRECORD;  // No option iMultiRecord
     362             :                 const char *szMultiRecord =
     363         111 :                     CSLFetchNameValue(papszOpenOptions, "MultiRecordIndex");
     364         111 :                 if (phMiraMonLayer->isListField && szMultiRecord)
     365             :                 {
     366          12 :                     if (EQUAL(szMultiRecord, "Last"))
     367           3 :                         phMiraMonLayer->iMultiRecord = MM_MULTIRECORD_LAST;
     368           9 :                     else if (EQUAL(szMultiRecord, "JSON"))
     369           3 :                         phMiraMonLayer->iMultiRecord = MM_MULTIRECORD_JSON;
     370             :                     else
     371           6 :                         phMiraMonLayer->iMultiRecord = atoi(szMultiRecord);
     372             :                 }
     373             :             }
     374             : 
     375        1161 :             for (MM_EXT_DBF_N_FIELDS nIField = 0;
     376        1161 :                  nIField < phMiraMonLayer->pMMBDXP->nFields; nIField++)
     377             :             {
     378        2100 :                 OGRFieldDefn oField("", OFTString);
     379        1050 :                 oField.SetName(
     380        1050 :                     phMiraMonLayer->pMMBDXP->pField[nIField].FieldName);
     381             : 
     382        1050 :                 oField.SetAlternativeName(
     383        1050 :                     phMiraMonLayer->pMMBDXP->pField[nIField]
     384        1050 :                         .FieldDescription[phMiraMonLayer->nMMLanguage <
     385             :                                                   MM_NUM_IDIOMES_MD_MULTIDIOMA
     386        1050 :                                               ? phMiraMonLayer->nMMLanguage
     387        1050 :                                               : 0]);
     388             : 
     389        1050 :                 if (phMiraMonLayer->pMMBDXP->pField[nIField].FieldType == 'C' ||
     390         880 :                     phMiraMonLayer->pMMBDXP->pField[nIField].FieldType == 'L')
     391             :                 {
     392             :                     // It's a list?
     393         254 :                     if (phMiraMonLayer->iMultiRecord ==
     394             :                         MM_MULTIRECORD_NO_MULTIRECORD)
     395             :                     {
     396         230 :                         if (phMiraMonLayer->pMMBDXP->pField[nIField]
     397         230 :                                 .FieldType == 'L')
     398             :                         {
     399          72 :                             if (phMiraMonLayer->isListField)
     400          20 :                                 oField.SetType(OFTIntegerList);
     401             :                             else
     402          52 :                                 oField.SetType(OFTInteger);
     403             : 
     404          72 :                             oField.SetSubType(OFSTBoolean);
     405             :                         }
     406             :                         else
     407             :                         {
     408         158 :                             if (phMiraMonLayer->isListField)
     409          39 :                                 oField.SetType(OFTStringList);
     410             :                             else
     411         119 :                                 oField.SetType(OFTString);
     412             :                         }
     413             :                     }
     414             :                     // It's a serialized JSON array
     415          24 :                     else if (phMiraMonLayer->iMultiRecord ==
     416             :                              MM_MULTIRECORD_JSON)
     417             :                     {
     418           6 :                         oField.SetType(OFTString);
     419           6 :                         oField.SetSubType(OFSTJSON);
     420             :                     }
     421             :                     else  // iMultiRecord decides which Record translate
     422          18 :                         oField.SetType(OFTString);
     423             :                 }
     424         796 :                 else if (phMiraMonLayer->pMMBDXP->pField[nIField].FieldType ==
     425             :                          'N')
     426             :                 {
     427             :                     // It's a list?
     428         756 :                     if (phMiraMonLayer->iMultiRecord ==
     429             :                         MM_MULTIRECORD_NO_MULTIRECORD)
     430             :                     {
     431         624 :                         if (phMiraMonLayer->pMMBDXP->pField[nIField]
     432         624 :                                 .DecimalsIfFloat)
     433         182 :                             oField.SetType(phMiraMonLayer->isListField
     434             :                                                ? OFTRealList
     435             :                                                : OFTReal);
     436             :                         else
     437             :                         {
     438         442 :                             if (phMiraMonLayer->pMMBDXP->pField[nIField]
     439         442 :                                     .BytesPerField < 10)
     440             :                             {
     441         202 :                                 oField.SetType(phMiraMonLayer->isListField
     442             :                                                    ? OFTIntegerList
     443             :                                                    : OFTInteger);
     444             :                             }
     445             :                             else
     446             :                             {
     447         240 :                                 oField.SetType(phMiraMonLayer->isListField
     448             :                                                    ? OFTInteger64List
     449             :                                                    : OFTInteger64);
     450             :                             }
     451             :                         }
     452             :                     }
     453             :                     // It's a serialized JSON array
     454         132 :                     else if (phMiraMonLayer->iMultiRecord ==
     455             :                              MM_MULTIRECORD_JSON)
     456             :                     {
     457          33 :                         oField.SetType(OFTString);
     458          33 :                         oField.SetSubType(OFSTJSON);
     459             :                     }
     460             :                     else
     461             :                     {
     462          99 :                         if (phMiraMonLayer->pMMBDXP->pField[nIField]
     463          99 :                                 .DecimalsIfFloat)
     464          45 :                             oField.SetType(OFTReal);
     465             :                         else
     466          54 :                             oField.SetType(OFTInteger);
     467             :                     }
     468             :                 }
     469          40 :                 else if (phMiraMonLayer->pMMBDXP->pField[nIField].FieldType ==
     470             :                          'D')
     471             :                 {
     472             :                     // It's a serialized JSON array
     473          40 :                     oField.SetType(OFTDate);
     474          40 :                     if (phMiraMonLayer->iMultiRecord == MM_MULTIRECORD_JSON)
     475             :                     {
     476           3 :                         oField.SetType(OFTString);
     477           3 :                         oField.SetSubType(OFSTJSON);
     478             :                     }
     479             :                 }
     480             : 
     481        1050 :                 oField.SetWidth(
     482        1050 :                     phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField);
     483        1050 :                 oField.SetPrecision(
     484        1050 :                     phMiraMonLayer->pMMBDXP->pField[nIField].DecimalsIfFloat);
     485             : 
     486        1050 :                 m_poFeatureDefn->AddFieldDefn(&oField);
     487             :             }
     488             :         }
     489             :     }
     490             : 
     491         193 :     bValidFile = true;
     492             : }
     493             : 
     494             : /****************************************************************************/
     495             : /*                           ~OGRMiraMonLayer()                             */
     496             : /****************************************************************************/
     497             : 
     498         402 : OGRMiraMonLayer::~OGRMiraMonLayer()
     499             : 
     500             : {
     501         201 :     if (m_nFeaturesRead > 0 && m_poFeatureDefn != nullptr)
     502             :     {
     503          82 :         CPLDebugOnly("MiraMon", "%d features read on layer '%s'.",
     504             :                      static_cast<int>(m_nFeaturesRead),
     505             :                      m_poFeatureDefn->GetName());
     506             :     }
     507             : 
     508         201 :     if (hMiraMonLayerPOL.bIsPolygon)
     509             :     {
     510          27 :         CPLDebugOnly("MiraMon", "Closing MiraMon polygons layer...");
     511          27 :         if (MMCloseLayer(&hMiraMonLayerPOL))
     512             :         {
     513           0 :             CPLDebugOnly("MiraMon", "Error closing polygons layer");
     514             : 
     515             :             // In case of closing we need to destroy memory
     516           0 :             MMDestroyLayer(&hMiraMonLayerPOL);
     517             :         }
     518          27 :         if (hMiraMonLayerPOL.TopHeader.nElemCount)
     519             :         {
     520          27 :             CPLDebugOnly("MiraMon",
     521             :                          sprintf_UINT64 " polygon(s) written in file %s.pol",
     522             :                          hMiraMonLayerPOL.TopHeader.nElemCount,
     523             :                          hMiraMonLayerPOL.pszSrcLayerName);
     524             :         }
     525          27 :         CPLDebugOnly("MiraMon", "MiraMon polygons layer closed");
     526             :     }
     527         174 :     else if (hMiraMonLayerPOL.ReadOrWrite == MM_WRITING_MODE)
     528             :     {
     529          55 :         CPLDebugOnly("MiraMon", "No MiraMon polygons layer created.");
     530             :     }
     531             : 
     532         201 :     if (hMiraMonLayerARC.bIsArc)
     533             :     {
     534          30 :         CPLDebugOnly("MiraMon", "Closing MiraMon arcs layer...");
     535          30 :         if (MMCloseLayer(&hMiraMonLayerARC))
     536             :         {
     537           0 :             CPLDebugOnly("MiraMon", "Error closing arcs layer");
     538             : 
     539             :             // In case of closing we need to destroy memory
     540           0 :             MMDestroyLayer(&hMiraMonLayerARC);
     541             :         }
     542          30 :         if (hMiraMonLayerARC.TopHeader.nElemCount)
     543             :         {
     544          30 :             CPLDebugOnly("MiraMon",
     545             :                          sprintf_UINT64 " arc(s) written in file %s.arc",
     546             :                          hMiraMonLayerARC.TopHeader.nElemCount,
     547             :                          hMiraMonLayerARC.pszSrcLayerName);
     548             :         }
     549             : 
     550          30 :         CPLDebugOnly("MiraMon", "MiraMon arcs layer closed");
     551             :     }
     552         171 :     else if (hMiraMonLayerARC.ReadOrWrite == MM_WRITING_MODE)
     553             :     {
     554          52 :         CPLDebugOnly("MiraMon", "No MiraMon arcs layer created.");
     555             :     }
     556             : 
     557         201 :     if (hMiraMonLayerPNT.bIsPoint)
     558             :     {
     559          33 :         CPLDebugOnly("MiraMon", "Closing MiraMon points layer...");
     560          33 :         if (MMCloseLayer(&hMiraMonLayerPNT))
     561             :         {
     562           0 :             CPLDebugOnly("MiraMon", "Error closing points layer");
     563             : 
     564             :             // In case of closing we need to destroy memory
     565           0 :             MMDestroyLayer(&hMiraMonLayerPNT);
     566             :         }
     567          33 :         if (hMiraMonLayerPNT.TopHeader.nElemCount)
     568             :         {
     569          33 :             CPLDebugOnly("MiraMon",
     570             :                          sprintf_UINT64 " point(s) written in file %s.pnt",
     571             :                          hMiraMonLayerPNT.TopHeader.nElemCount,
     572             :                          hMiraMonLayerPNT.pszSrcLayerName);
     573             :         }
     574          33 :         CPLDebugOnly("MiraMon", "MiraMon points layer closed");
     575             :     }
     576         168 :     else if (hMiraMonLayerPNT.ReadOrWrite == MM_WRITING_MODE)
     577             :     {
     578          49 :         CPLDebugOnly("MiraMon", "No MiraMon points layer created.");
     579             :     }
     580             : 
     581         201 :     if (hMiraMonLayerARC.ReadOrWrite == MM_WRITING_MODE)
     582             :     {
     583          82 :         if (hMiraMonLayerReadOrNonGeom.bIsDBF)
     584             :         {
     585          17 :             if (hMiraMonLayerReadOrNonGeom.ReadOrWrite == MM_WRITING_MODE)
     586             :             {
     587          17 :                 CPLDebugOnly("MiraMon", "Closing MiraMon DBF table ...");
     588             :             }
     589          17 :             if (MMCloseLayer(&hMiraMonLayerReadOrNonGeom))
     590             :             {
     591             :                 // In case of closing we need to destroy memory
     592           0 :                 MMDestroyLayer(&hMiraMonLayerReadOrNonGeom);
     593             :             }
     594          17 :             if (hMiraMonLayerReadOrNonGeom.ReadOrWrite == MM_WRITING_MODE)
     595             :             {
     596          17 :                 CPLDebugOnly("MiraMon", "MiraMon DBF table closed");
     597             :             }
     598             :         }
     599          65 :         else if (hMiraMonLayerReadOrNonGeom.ReadOrWrite == MM_WRITING_MODE)
     600             :         {
     601          65 :             CPLDebugOnly("MiraMon", "No MiraMon DBF table created.");
     602             :         }
     603             :     }
     604             :     else
     605             :     {
     606         119 :         if (hMiraMonLayerReadOrNonGeom.ReadOrWrite == MM_WRITING_MODE)
     607             :         {
     608           0 :             CPLDebugOnly("MiraMon", "Closing MiraMon layer ...");
     609             :         }
     610         119 :         if (MMCloseLayer(&hMiraMonLayerReadOrNonGeom))
     611             :         {
     612             :             // In case of closing we need to destroy memory
     613           0 :             MMDestroyLayer(&hMiraMonLayerReadOrNonGeom);
     614             :         }
     615         119 :         if (hMiraMonLayerReadOrNonGeom.ReadOrWrite == MM_WRITING_MODE)
     616             :         {
     617           0 :             CPLDebugOnly("MiraMon", "MiraMon layer closed");
     618             :         }
     619             :     }
     620             : 
     621         201 :     if (hMiraMonLayerPOL.ReadOrWrite == MM_WRITING_MODE)
     622             :     {
     623          82 :         MMCPLDebug("MiraMon", "Destroying MiraMon polygons layer memory");
     624             :     }
     625         201 :     MMDestroyLayer(&hMiraMonLayerPOL);
     626         201 :     if (hMiraMonLayerPOL.ReadOrWrite == MM_WRITING_MODE)
     627             :     {
     628          82 :         MMCPLDebug("MiraMon", "MiraMon polygons layer memory destroyed");
     629             :     }
     630             : 
     631         201 :     if (hMiraMonLayerARC.ReadOrWrite == MM_WRITING_MODE)
     632             :     {
     633          82 :         MMCPLDebug("MiraMon", "Destroying MiraMon arcs layer memory");
     634             :     }
     635         201 :     MMDestroyLayer(&hMiraMonLayerARC);
     636         201 :     if (hMiraMonLayerARC.ReadOrWrite == MM_WRITING_MODE)
     637             :     {
     638          82 :         MMCPLDebug("MiraMon", "MiraMon arcs layer memory destroyed");
     639             :     }
     640             : 
     641         201 :     if (hMiraMonLayerPNT.ReadOrWrite == MM_WRITING_MODE)
     642             :     {
     643          82 :         MMCPLDebug("MiraMon", "Destroying MiraMon points layer memory");
     644             :     }
     645         201 :     MMDestroyLayer(&hMiraMonLayerPNT);
     646         201 :     if (hMiraMonLayerPNT.ReadOrWrite == MM_WRITING_MODE)
     647             :     {
     648          82 :         MMCPLDebug("MiraMon", "MiraMon points layer memory destroyed");
     649             :     }
     650             : 
     651         201 :     if (hMiraMonLayerReadOrNonGeom.ReadOrWrite == MM_WRITING_MODE)
     652             :     {
     653          82 :         MMCPLDebug("MiraMon", "Destroying MiraMon DBF table layer memory");
     654             :     }
     655             :     else
     656             :     {
     657         119 :         MMCPLDebug("MiraMon", "Destroying MiraMon layer memory");
     658             :     }
     659             : 
     660         201 :     MMDestroyLayer(&hMiraMonLayerReadOrNonGeom);
     661         201 :     if (hMiraMonLayerReadOrNonGeom.ReadOrWrite == MM_WRITING_MODE)
     662             :     {
     663          82 :         MMCPLDebug("MiraMon", "MiraMon DBF table layer memory destroyed");
     664             :     }
     665             :     else
     666             :     {
     667         119 :         MMCPLDebug("MiraMon", "MiraMon layer memory destroyed");
     668             :     }
     669             : 
     670         201 :     memset(&hMiraMonLayerReadOrNonGeom, 0, sizeof(hMiraMonLayerReadOrNonGeom));
     671         201 :     memset(&hMiraMonLayerPNT, 0, sizeof(hMiraMonLayerPNT));
     672         201 :     memset(&hMiraMonLayerARC, 0, sizeof(hMiraMonLayerARC));
     673         201 :     memset(&hMiraMonLayerPOL, 0, sizeof(hMiraMonLayerPOL));
     674             : 
     675         201 :     MMCPLDebug("MiraMon", "Destroying MiraMon temporary feature memory");
     676         201 :     MMDestroyFeature(&hMMFeature);
     677         201 :     MMCPLDebug("MiraMon", "MiraMon temporary feature memory");
     678         201 :     memset(&hMMFeature, 0, sizeof(hMMFeature));
     679             : 
     680             :     /* -------------------------------------------------------------------- */
     681             :     /*      Clean up.                                                       */
     682             :     /* -------------------------------------------------------------------- */
     683             : 
     684         201 :     if (m_poFeatureDefn)
     685         201 :         m_poFeatureDefn->Release();
     686             : 
     687         201 :     if (m_poSRS)
     688          60 :         m_poSRS->Release();
     689             : 
     690         201 :     if (m_fp != nullptr)
     691         119 :         VSIFCloseL(m_fp);
     692             : 
     693         201 :     if (padfValues != nullptr)
     694         102 :         CPLFree(padfValues);
     695             : 
     696         201 :     if (pnInt64Values != nullptr)
     697         102 :         CPLFree(pnInt64Values);
     698         402 : }
     699             : 
     700             : /****************************************************************************/
     701             : /*                            ResetReading()                                */
     702             : /****************************************************************************/
     703             : 
     704         731 : void OGRMiraMonLayer::ResetReading()
     705             : 
     706             : {
     707         731 :     if (m_iNextFID == 0)
     708         482 :         return;
     709             : 
     710         249 :     m_iNextFID = 0;
     711             : 
     712             :     //VSIFSeekL(m_fp, 0, SEEK_SET);
     713         249 :     if (!phMiraMonLayer)
     714           0 :         return;
     715             : 
     716         249 :     if (phMiraMonLayer->bIsPoint && phMiraMonLayer->MMPoint.pF)
     717             :     {
     718          74 :         VSIFSeekL(phMiraMonLayer->MMPoint.pF, 0, SEEK_SET);
     719          74 :         return;
     720             :     }
     721         175 :     if (phMiraMonLayer->bIsArc && !phMiraMonLayer->bIsPolygon &&
     722          74 :         phMiraMonLayer->MMArc.pF)
     723             :     {
     724          74 :         VSIFSeekL(phMiraMonLayer->MMArc.pF, 0, SEEK_SET);
     725          74 :         return;
     726             :     }
     727         101 :     if (phMiraMonLayer->bIsPolygon && phMiraMonLayer->MMPolygon.pF)
     728             :     {
     729         101 :         VSIFSeekL(phMiraMonLayer->MMPolygon.pF, 0, SEEK_SET);
     730         101 :         return;
     731             :     }
     732             : }
     733             : 
     734             : /****************************************************************************/
     735             : /*                         GetNextRawFeature()                              */
     736             : /****************************************************************************/
     737             : 
     738       16542 : void OGRMiraMonLayer::GoToFieldOfMultipleRecord(MM_INTERNAL_FID iFID,
     739             :                                                 MM_EXT_DBF_N_RECORDS nIRecord,
     740             :                                                 MM_EXT_DBF_N_FIELDS nIField)
     741             : 
     742             : {
     743             :     // Not an error. Simply there are no features, but there are fields
     744       16542 :     if (!phMiraMonLayer->pMultRecordIndex)
     745           0 :         return;
     746             : 
     747       16542 :     fseek_function(
     748             :         phMiraMonLayer->pMMBDXP->pfDataBase,
     749             :         phMiraMonLayer->pMultRecordIndex[iFID].offset +
     750             :             (MM_FILE_OFFSET)nIRecord * phMiraMonLayer->pMMBDXP->BytesPerRecord +
     751             :             phMiraMonLayer->pMMBDXP->pField[nIField].AccumulatedBytes,
     752             :         SEEK_SET);
     753             : }
     754             : 
     755             : /****************************************************************************/
     756             : /*                         GetNextRawFeature()                              */
     757             : /****************************************************************************/
     758             : 
     759        1923 : OGRFeature *OGRMiraMonLayer::GetNextRawFeature()
     760             : {
     761        1923 :     if (!phMiraMonLayer)
     762           0 :         return nullptr;
     763             : 
     764        1923 :     if (m_iNextFID >= (GUInt64)phMiraMonLayer->TopHeader.nElemCount)
     765         154 :         return nullptr;
     766             : 
     767        1769 :     OGRFeature *poFeature = GetFeature(m_iNextFID);
     768             : 
     769        1769 :     if (!poFeature)
     770         115 :         return nullptr;
     771             : 
     772        1654 :     m_iNextFID++;
     773        1654 :     return poFeature;
     774             : }
     775             : 
     776             : /****************************************************************************/
     777             : /*                         GetFeature()                                     */
     778             : /****************************************************************************/
     779             : 
     780        1834 : OGRFeature *OGRMiraMonLayer::GetFeature(GIntBig nFeatureId)
     781             : 
     782             : {
     783        1834 :     OGRGeometry *poGeom = nullptr;
     784        1834 :     OGRPoint *poPoint = nullptr;
     785        1834 :     OGRLineString *poLS = nullptr;
     786             :     MM_INTERNAL_FID nIElem;
     787        1834 :     MM_EXT_DBF_N_MULTIPLE_RECORDS nIRecord = 0;
     788             : 
     789        1834 :     if (!phMiraMonLayer)
     790           0 :         return nullptr;
     791             : 
     792        1834 :     if (nFeatureId < 0)
     793          10 :         return nullptr;
     794             : 
     795        1824 :     if (phMiraMonLayer->bIsPolygon)
     796             :     {
     797         443 :         if (nFeatureId == GINTBIG_MAX)
     798           0 :             return nullptr;
     799             : 
     800         443 :         nIElem = (MM_INTERNAL_FID)(nFeatureId + 1);
     801             :     }
     802             :     else
     803        1381 :         nIElem = (MM_INTERNAL_FID)nFeatureId;
     804             : 
     805        1824 :     if (nIElem >= phMiraMonLayer->TopHeader.nElemCount)
     806         115 :         return nullptr;
     807             : 
     808             :     /* -------------------------------------------------------------------- */
     809             :     /*      Read nFeatureId feature directly from the file.                 */
     810             :     /* -------------------------------------------------------------------- */
     811        1709 :     switch (phMiraMonLayer->eLT)
     812             :     {
     813        1015 :         case MM_LayerType_Point:
     814             :         case MM_LayerType_Point3d:
     815             :             // Read point
     816        1015 :             poGeom = new OGRPoint();
     817        1015 :             poPoint = poGeom->toPoint();
     818             : 
     819             :             // Get X,Y (z). MiraMon has no multipoints
     820        1015 :             if (MMGetGeoFeatureFromVector(phMiraMonLayer, nIElem))
     821             :             {
     822           5 :                 CPLError(CE_Failure, CPLE_AppDefined, "Wrong file format.");
     823           5 :                 delete poGeom;
     824          20 :                 return nullptr;
     825             :             }
     826             : 
     827        1010 :             poPoint->setX(phMiraMonLayer->ReadFeature.pCoord[0].dfX);
     828        1010 :             poPoint->setY(phMiraMonLayer->ReadFeature.pCoord[0].dfY);
     829        1010 :             if (phMiraMonLayer->TopHeader.bIs3d)
     830         874 :                 poPoint->setZ(phMiraMonLayer->ReadFeature.pZCoord[0]);
     831        1689 :             break;
     832             : 
     833         354 :         case MM_LayerType_Arc:
     834             :         case MM_LayerType_Arc3d:
     835         354 :             poGeom = new OGRLineString();
     836         354 :             poLS = poGeom->toLineString();
     837             : 
     838             :             // Get X,Y (Z) n times MiraMon has no multilines
     839         354 :             if (MMGetGeoFeatureFromVector(phMiraMonLayer, nIElem))
     840             :             {
     841           7 :                 CPLError(CE_Failure, CPLE_AppDefined, "Wrong file format.");
     842           7 :                 delete poGeom;
     843           7 :                 return nullptr;
     844             :             }
     845             : 
     846        1638 :             for (MM_N_VERTICES_TYPE nIVrt = 0;
     847        1638 :                  nIVrt < phMiraMonLayer->ReadFeature.pNCoordRing[0]; nIVrt++)
     848             :             {
     849        1291 :                 if (phMiraMonLayer->TopHeader.bIs3d)
     850         540 :                     poLS->addPoint(
     851         540 :                         phMiraMonLayer->ReadFeature.pCoord[nIVrt].dfX,
     852         540 :                         phMiraMonLayer->ReadFeature.pCoord[nIVrt].dfY,
     853         540 :                         phMiraMonLayer->ReadFeature.pZCoord[nIVrt]);
     854             :                 else
     855         751 :                     poLS->addPoint(
     856         751 :                         phMiraMonLayer->ReadFeature.pCoord[nIVrt].dfX,
     857         751 :                         phMiraMonLayer->ReadFeature.pCoord[nIVrt].dfY);
     858             :             }
     859         347 :             break;
     860             : 
     861         340 :         case MM_LayerType_Pol:
     862             :         case MM_LayerType_Pol3d:
     863             :             // Read polygon
     864         340 :             auto poPoly = std::make_unique<OGRPolygon>();
     865             :             MM_POLYGON_RINGS_COUNT nIRing;
     866             :             MM_N_VERTICES_TYPE nIVrtAcum;
     867             : 
     868         340 :             if (phMiraMonLayer->TopHeader.bIsMultipolygon)
     869             :             {
     870          47 :                 OGRMultiPolygon *poMP = nullptr;
     871             : 
     872          47 :                 poGeom = new OGRMultiPolygon();
     873          47 :                 poMP = poGeom->toMultiPolygon();
     874             : 
     875             :                 // Get X,Y (Z) n times MiraMon has no multilines
     876          47 :                 if (MMGetGeoFeatureFromVector(phMiraMonLayer, nIElem))
     877             :                 {
     878           0 :                     CPLError(CE_Failure, CPLE_AppDefined, "Wrong file format.");
     879           0 :                     delete poGeom;
     880           0 :                     return nullptr;
     881             :                 }
     882             : 
     883          47 :                 nIVrtAcum = 0;
     884          47 :                 if (!(phMiraMonLayer->ReadFeature.flag_VFG[0] &
     885             :                       MM_EXTERIOR_ARC_SIDE))
     886             :                 {
     887           1 :                     CPLError(CE_Failure, CPLE_NoWriteAccess,
     888             :                              "Wrong polygon format.");
     889           1 :                     delete poGeom;
     890           1 :                     return nullptr;
     891             :                 }
     892             : 
     893         230 :                 for (nIRing = 0; nIRing < phMiraMonLayer->ReadFeature.nNRings;
     894             :                      nIRing++)
     895             :                 {
     896         368 :                     auto poRing = std::make_unique<OGRLinearRing>();
     897             : 
     898         184 :                     for (MM_N_VERTICES_TYPE nIVrt = 0;
     899        2652 :                          nIVrt <
     900        2652 :                          phMiraMonLayer->ReadFeature.pNCoordRing[nIRing];
     901             :                          nIVrt++)
     902             :                     {
     903        2468 :                         if (phMiraMonLayer->TopHeader.bIs3d)
     904             :                         {
     905          20 :                             poRing->addPoint(
     906          20 :                                 phMiraMonLayer->ReadFeature.pCoord[nIVrtAcum]
     907             :                                     .dfX,
     908          20 :                                 phMiraMonLayer->ReadFeature.pCoord[nIVrtAcum]
     909             :                                     .dfY,
     910          20 :                                 phMiraMonLayer->ReadFeature.pZCoord[nIVrtAcum]);
     911             :                         }
     912             :                         else
     913             :                         {
     914        2448 :                             poRing->addPoint(
     915        2448 :                                 phMiraMonLayer->ReadFeature.pCoord[nIVrtAcum]
     916             :                                     .dfX,
     917        2448 :                                 phMiraMonLayer->ReadFeature.pCoord[nIVrtAcum]
     918             :                                     .dfY);
     919             :                         }
     920             : 
     921        2468 :                         nIVrtAcum++;
     922             :                     }
     923             : 
     924             :                     // If I'm going to start a new polygon...
     925         184 :                     if ((nIRing + 1 < phMiraMonLayer->ReadFeature.nNRings &&
     926         138 :                          ((phMiraMonLayer->ReadFeature.flag_VFG[nIRing + 1]) &
     927         138 :                           MM_EXTERIOR_ARC_SIDE)) ||
     928         138 :                         nIRing + 1 >= phMiraMonLayer->ReadFeature.nNRings)
     929             :                     {
     930          92 :                         poPoly->addRingDirectly(poRing.release());
     931          92 :                         poMP->addGeometryDirectly(poPoly.release());
     932          92 :                         poPoly = std::make_unique<OGRPolygon>();
     933             :                     }
     934             :                     else
     935          92 :                         poPoly->addRingDirectly(poRing.release());
     936             :                 }
     937             :             }
     938             :             else
     939             :             {
     940         293 :                 OGRPolygon *poP = nullptr;
     941             : 
     942         293 :                 poGeom = new OGRPolygon();
     943         293 :                 poP = poGeom->toPolygon();
     944             : 
     945             :                 // Get X,Y (Z) n times because MiraMon has no multilinetrings
     946         293 :                 if (MMGetGeoFeatureFromVector(phMiraMonLayer, nIElem))
     947             :                 {
     948           7 :                     CPLError(CE_Failure, CPLE_AppDefined, "Wrong file format.");
     949           7 :                     delete poGeom;
     950           7 :                     return nullptr;
     951             :                 }
     952             : 
     953         286 :                 if (phMiraMonLayer->ReadFeature.nNRings &&
     954         286 :                     phMiraMonLayer->ReadFeature.nNumpCoord)
     955             :                 {
     956         286 :                     nIVrtAcum = 0;
     957         286 :                     if (!(phMiraMonLayer->ReadFeature.flag_VFG[0] &
     958             :                           MM_EXTERIOR_ARC_SIDE))
     959             :                     {
     960           0 :                         CPLError(CE_Failure, CPLE_AssertionFailed,
     961             :                                  "Wrong polygon format.");
     962           0 :                         delete poGeom;
     963           0 :                         return nullptr;
     964             :                     }
     965             : 
     966         572 :                     for (nIRing = 0;
     967         572 :                          nIRing < phMiraMonLayer->ReadFeature.nNRings; nIRing++)
     968             :                     {
     969         572 :                         auto poRing = std::make_unique<OGRLinearRing>();
     970             : 
     971         286 :                         for (MM_N_VERTICES_TYPE nIVrt = 0;
     972        1735 :                              nIVrt <
     973        1735 :                              phMiraMonLayer->ReadFeature.pNCoordRing[nIRing];
     974             :                              nIVrt++)
     975             :                         {
     976        1449 :                             if (phMiraMonLayer->TopHeader.bIs3d)
     977             :                             {
     978         668 :                                 poRing->addPoint(phMiraMonLayer->ReadFeature
     979         668 :                                                      .pCoord[nIVrtAcum]
     980             :                                                      .dfX,
     981         668 :                                                  phMiraMonLayer->ReadFeature
     982         668 :                                                      .pCoord[nIVrtAcum]
     983             :                                                      .dfY,
     984         668 :                                                  phMiraMonLayer->ReadFeature
     985         668 :                                                      .pZCoord[nIVrtAcum]);
     986             :                             }
     987             :                             else
     988             :                             {
     989         781 :                                 poRing->addPoint(phMiraMonLayer->ReadFeature
     990         781 :                                                      .pCoord[nIVrtAcum]
     991             :                                                      .dfX,
     992         781 :                                                  phMiraMonLayer->ReadFeature
     993         781 :                                                      .pCoord[nIVrtAcum]
     994             :                                                      .dfY);
     995             :                             }
     996             : 
     997        1449 :                             nIVrtAcum++;
     998             :                         }
     999         286 :                         poP->addRingDirectly(poRing.release());
    1000             :                     }
    1001             :                 }
    1002             :             }
    1003             : 
    1004         332 :             break;
    1005             :     }
    1006             : 
    1007        1689 :     if (poGeom == nullptr)
    1008           0 :         return nullptr;
    1009             : 
    1010             :     /* -------------------------------------------------------------------- */
    1011             :     /*      Create feature.                                                 */
    1012             :     /* -------------------------------------------------------------------- */
    1013        3378 :     auto poFeature = std::make_unique<OGRFeature>(m_poFeatureDefn);
    1014        1689 :     poGeom->assignSpatialReference(m_poSRS);
    1015        1689 :     poFeature->SetGeometryDirectly(poGeom);
    1016             : 
    1017             :     /* -------------------------------------------------------------------- */
    1018             :     /*      Process field values if its possible.                           */
    1019             :     /* -------------------------------------------------------------------- */
    1020        1689 :     if (phMiraMonLayer->pMMBDXP &&
    1021        1689 :         (MM_EXT_DBF_N_RECORDS)nIElem < phMiraMonLayer->pMMBDXP->nRecords)
    1022             :     {
    1023             :         MM_EXT_DBF_N_FIELDS nIField;
    1024             : 
    1025       17461 :         for (nIField = 0; nIField < phMiraMonLayer->pMMBDXP->nFields; nIField++)
    1026             :         {
    1027       31544 :             if (MMResizeStringToOperateIfNeeded(
    1028             :                     phMiraMonLayer,
    1029       15772 :                     phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField + 1))
    1030             :             {
    1031           0 :                 return nullptr;
    1032             :             }
    1033             : 
    1034       15772 :             if (poFeature->GetDefnRef()->GetFieldDefn(nIField)->GetType() ==
    1035       34062 :                     OFTStringList ||
    1036       15698 :                 (poFeature->GetDefnRef()->GetFieldDefn(nIField)->GetType() ==
    1037        2592 :                      OFTString &&
    1038        2592 :                  poFeature->GetDefnRef()->GetFieldDefn(nIField)->GetSubType() ==
    1039             :                      OFSTJSON))
    1040             :             {
    1041         116 :                 if (!phMiraMonLayer->pMultRecordIndex ||
    1042         116 :                     phMiraMonLayer->pMultRecordIndex[nIElem].nMR == 0)
    1043             :                 {
    1044           0 :                     memset(
    1045           0 :                         phMiraMonLayer->szStringToOperate, 0,
    1046           0 :                         phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField);
    1047           0 :                     continue;
    1048             :                 }
    1049         116 :                 if (poFeature->GetDefnRef()
    1050         116 :                         ->GetFieldDefn(nIField)
    1051         116 :                         ->GetSubType() == OFSTJSON)
    1052             :                 {
    1053          84 :                     if (MMResizeStringToOperateIfNeeded(
    1054             :                             phMiraMonLayer,
    1055          42 :                             phMiraMonLayer->pMMBDXP->BytesPerRecord +
    1056          42 :                                 2 * phMiraMonLayer->pMultRecordIndex[nIElem]
    1057          42 :                                         .nMR +
    1058          42 :                                 8))
    1059             :                     {
    1060           0 :                         return nullptr;
    1061             :                     }
    1062          84 :                     std::string szStringToOperate = "[";
    1063         126 :                     for (nIRecord = 0;
    1064         126 :                          nIRecord <
    1065         126 :                          phMiraMonLayer->pMultRecordIndex[nIElem].nMR;
    1066             :                          nIRecord++)
    1067             :                     {
    1068          84 :                         GoToFieldOfMultipleRecord(nIElem, nIRecord, nIField);
    1069             : 
    1070          84 :                         fread_function(phMiraMonLayer->szStringToOperate,
    1071             :                                        phMiraMonLayer->pMMBDXP->pField[nIField]
    1072             :                                            .BytesPerField,
    1073             :                                        1, phMiraMonLayer->pMMBDXP->pfDataBase);
    1074          84 :                         phMiraMonLayer
    1075          84 :                             ->szStringToOperate[phMiraMonLayer->pMMBDXP
    1076          84 :                                                     ->pField[nIField]
    1077          84 :                                                     .BytesPerField] = '\0';
    1078          84 :                         MM_RemoveLeadingWhitespaceOfString(
    1079          84 :                             phMiraMonLayer->szStringToOperate);
    1080          84 :                         MM_RemoveWhitespacesFromEndOfString(
    1081          84 :                             phMiraMonLayer->szStringToOperate);
    1082             : 
    1083          84 :                         if (phMiraMonLayer->pMMBDXP->CharSet ==
    1084             :                             MM_JOC_CARAC_OEM850_DBASE)
    1085          84 :                             MM_oemansi_n(
    1086          84 :                                 phMiraMonLayer->szStringToOperate,
    1087          84 :                                 phMiraMonLayer->pMMBDXP->pField[nIField]
    1088          84 :                                     .BytesPerField);
    1089             : 
    1090          84 :                         if (phMiraMonLayer->pMMBDXP->CharSet !=
    1091             :                             MM_JOC_CARAC_UTF8_DBF)
    1092             :                         {
    1093             :                             // MiraMon encoding is ISO 8859-1 (Latin1) -> Recode to UTF-8
    1094             :                             char *pszString =
    1095          84 :                                 CPLRecode(phMiraMonLayer->szStringToOperate,
    1096             :                                           CPL_ENC_ISO8859_1, CPL_ENC_UTF8);
    1097             : 
    1098          84 :                             CPLStrlcpy(
    1099          84 :                                 phMiraMonLayer->szStringToOperate, pszString,
    1100          84 :                                 (size_t)phMiraMonLayer->pMMBDXP->pField[nIField]
    1101          84 :                                         .BytesPerField +
    1102             :                                     1);
    1103             : 
    1104          84 :                             CPLFree(pszString);
    1105             :                         }
    1106             :                         szStringToOperate.append(
    1107          84 :                             phMiraMonLayer->szStringToOperate);
    1108             : 
    1109          84 :                         if (nIRecord <
    1110          84 :                             phMiraMonLayer->pMultRecordIndex[nIElem].nMR - 1)
    1111             :                         {
    1112          42 :                             szStringToOperate.append(",");
    1113             :                         }
    1114             :                         else
    1115             :                         {
    1116          42 :                             szStringToOperate.append("]");
    1117             :                         }
    1118             :                     }
    1119          42 :                     poFeature->SetField(nIField, szStringToOperate.c_str());
    1120             :                 }
    1121             :                 else
    1122             :                 {
    1123         148 :                     CPLStringList aosValues;
    1124         242 :                     for (nIRecord = 0;
    1125         242 :                          nIRecord <
    1126         242 :                          phMiraMonLayer->pMultRecordIndex[nIElem].nMR;
    1127             :                          nIRecord++)
    1128             :                     {
    1129         168 :                         GoToFieldOfMultipleRecord(nIElem, nIRecord, nIField);
    1130         168 :                         memset(phMiraMonLayer->szStringToOperate, 0,
    1131         168 :                                phMiraMonLayer->pMMBDXP->pField[nIField]
    1132         168 :                                    .BytesPerField);
    1133         168 :                         fread_function(phMiraMonLayer->szStringToOperate,
    1134             :                                        phMiraMonLayer->pMMBDXP->pField[nIField]
    1135             :                                            .BytesPerField,
    1136             :                                        1, phMiraMonLayer->pMMBDXP->pfDataBase);
    1137         168 :                         phMiraMonLayer
    1138         168 :                             ->szStringToOperate[phMiraMonLayer->pMMBDXP
    1139         168 :                                                     ->pField[nIField]
    1140         168 :                                                     .BytesPerField] = '\0';
    1141         168 :                         MM_RemoveWhitespacesFromEndOfString(
    1142         168 :                             phMiraMonLayer->szStringToOperate);
    1143             : 
    1144         168 :                         if (phMiraMonLayer->pMMBDXP->CharSet ==
    1145             :                             MM_JOC_CARAC_OEM850_DBASE)
    1146          60 :                             MM_oemansi_n(
    1147          60 :                                 phMiraMonLayer->szStringToOperate,
    1148          60 :                                 phMiraMonLayer->pMMBDXP->pField[nIField]
    1149          60 :                                     .BytesPerField);
    1150             : 
    1151         168 :                         if (phMiraMonLayer->pMMBDXP->CharSet !=
    1152             :                             MM_JOC_CARAC_UTF8_DBF)
    1153             :                         {
    1154             :                             // MiraMon encoding is ISO 8859-1 (Latin1) -> Recode to UTF-8
    1155             :                             char *pszString =
    1156         160 :                                 CPLRecode(phMiraMonLayer->szStringToOperate,
    1157             :                                           CPL_ENC_ISO8859_1, CPL_ENC_UTF8);
    1158             : 
    1159         160 :                             CPLStrlcpy(
    1160         160 :                                 phMiraMonLayer->szStringToOperate, pszString,
    1161         160 :                                 (size_t)phMiraMonLayer->pMMBDXP->pField[nIField]
    1162         160 :                                         .BytesPerField +
    1163             :                                     1);
    1164             : 
    1165         160 :                             CPLFree(pszString);
    1166             :                         }
    1167         168 :                         aosValues.AddString(phMiraMonLayer->szStringToOperate);
    1168             :                     }
    1169          74 :                     poFeature->SetField(nIField, aosValues.List());
    1170             :                 }
    1171             :             }
    1172       15656 :             else if (poFeature->GetDefnRef()
    1173       15656 :                          ->GetFieldDefn(nIField)
    1174       15656 :                          ->GetType() == OFTString)
    1175             :             {
    1176        2550 :                 if (!phMiraMonLayer->pMultRecordIndex ||
    1177        2550 :                     phMiraMonLayer->pMultRecordIndex[nIElem].nMR == 0)
    1178             :                 {
    1179           0 :                     memset(
    1180           0 :                         phMiraMonLayer->szStringToOperate, 0,
    1181           0 :                         phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField);
    1182           0 :                     continue;
    1183             :                 }
    1184        2550 :                 if (phMiraMonLayer->iMultiRecord !=
    1185             :                     MM_MULTIRECORD_NO_MULTIRECORD)
    1186             :                 {
    1187          18 :                     if (phMiraMonLayer->iMultiRecord == MM_MULTIRECORD_LAST)
    1188           6 :                         GoToFieldOfMultipleRecord(
    1189             :                             nIElem,
    1190           6 :                             phMiraMonLayer->pMultRecordIndex[nIElem].nMR - 1,
    1191             :                             nIField);
    1192          12 :                     else if ((MM_EXT_DBF_N_MULTIPLE_RECORDS)
    1193          12 :                                  phMiraMonLayer->iMultiRecord <
    1194          12 :                              phMiraMonLayer->pMultRecordIndex[nIElem].nMR)
    1195          12 :                         GoToFieldOfMultipleRecord(
    1196             :                             nIElem,
    1197          12 :                             (MM_EXT_DBF_N_MULTIPLE_RECORDS)
    1198          12 :                                 phMiraMonLayer->iMultiRecord,
    1199             :                             nIField);
    1200             :                     else
    1201             :                     {
    1202           0 :                         memset(phMiraMonLayer->szStringToOperate, 0,
    1203           0 :                                phMiraMonLayer->pMMBDXP->pField[nIField]
    1204           0 :                                    .BytesPerField);
    1205           0 :                         continue;
    1206             :                     }
    1207             :                 }
    1208             :                 else
    1209        2532 :                     GoToFieldOfMultipleRecord(nIElem, 0, nIField);
    1210             : 
    1211        2550 :                 memset(phMiraMonLayer->szStringToOperate, 0,
    1212        2550 :                        phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField);
    1213        2550 :                 fread_function(
    1214             :                     phMiraMonLayer->szStringToOperate,
    1215             :                     phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField, 1,
    1216             :                     phMiraMonLayer->pMMBDXP->pfDataBase);
    1217        2550 :                 phMiraMonLayer
    1218        2550 :                     ->szStringToOperate[phMiraMonLayer->pMMBDXP->pField[nIField]
    1219        2550 :                                             .BytesPerField] = '\0';
    1220        2550 :                 MM_RemoveWhitespacesFromEndOfString(
    1221        2550 :                     phMiraMonLayer->szStringToOperate);
    1222             : 
    1223        2550 :                 if (phMiraMonLayer->pMMBDXP->CharSet ==
    1224             :                     MM_JOC_CARAC_OEM850_DBASE)
    1225        2460 :                     MM_oemansi(phMiraMonLayer->szStringToOperate);
    1226             : 
    1227        2550 :                 if (phMiraMonLayer->pMMBDXP->CharSet != MM_JOC_CARAC_UTF8_DBF)
    1228             :                 {
    1229             :                     // MiraMon encoding is ISO 8859-1 (Latin1) -> Recode to UTF-8
    1230             :                     char *pszString =
    1231        2550 :                         CPLRecode(phMiraMonLayer->szStringToOperate,
    1232             :                                   CPL_ENC_ISO8859_1, CPL_ENC_UTF8);
    1233        2550 :                     CPLStrlcpy(phMiraMonLayer->szStringToOperate, pszString,
    1234        2550 :                                (size_t)phMiraMonLayer->pMMBDXP->pField[nIField]
    1235        2550 :                                        .BytesPerField +
    1236             :                                    1);
    1237        2550 :                     CPLFree(pszString);
    1238             :                 }
    1239        2550 :                 poFeature->SetField(nIField, phMiraMonLayer->szStringToOperate);
    1240             :             }
    1241       13106 :             else if (poFeature->GetDefnRef()
    1242       13106 :                              ->GetFieldDefn(nIField)
    1243       26034 :                              ->GetType() == OFTIntegerList ||
    1244       12928 :                      poFeature->GetDefnRef()
    1245       12928 :                              ->GetFieldDefn(nIField)
    1246       12928 :                              ->GetType() == OFTRealList)
    1247             :             {
    1248         393 :                 if (!phMiraMonLayer->pMultRecordIndex ||
    1249         393 :                     phMiraMonLayer->pMultRecordIndex[nIElem].nMR == 0)
    1250             :                 {
    1251           0 :                     memset(
    1252           0 :                         phMiraMonLayer->szStringToOperate, 0,
    1253           0 :                         phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField);
    1254           0 :                     continue;
    1255             :                 }
    1256         393 :                 MM_EXT_DBF_N_MULTIPLE_RECORDS nRealMR = 0;
    1257        1227 :                 for (nIRecord = 0;
    1258        1227 :                      nIRecord < phMiraMonLayer->pMultRecordIndex[nIElem].nMR;
    1259             :                      nIRecord++)
    1260             :                 {
    1261         834 :                     GoToFieldOfMultipleRecord(nIElem, nIRecord, nIField);
    1262         834 :                     memset(
    1263         834 :                         phMiraMonLayer->szStringToOperate, 0,
    1264         834 :                         phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField);
    1265         834 :                     fread_function(
    1266             :                         phMiraMonLayer->szStringToOperate,
    1267             :                         phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField,
    1268             :                         1, phMiraMonLayer->pMMBDXP->pfDataBase);
    1269         834 :                     phMiraMonLayer->szStringToOperate[phMiraMonLayer->pMMBDXP
    1270         834 :                                                           ->pField[nIField]
    1271         834 :                                                           .BytesPerField] =
    1272             :                         '\0';
    1273             : 
    1274         834 :                     if (!MMIsEmptyString(phMiraMonLayer->szStringToOperate))
    1275             :                     {
    1276         734 :                         if (poFeature->GetDefnRef()
    1277         734 :                                     ->GetFieldDefn(nIField)
    1278        1048 :                                     ->GetType() == OFTIntegerList &&
    1279         314 :                             poFeature->GetDefnRef()
    1280         314 :                                     ->GetFieldDefn(nIField)
    1281         314 :                                     ->GetSubType() == OFSTBoolean)
    1282             :                         {
    1283          81 :                             if (*phMiraMonLayer->szStringToOperate == 'T' ||
    1284          30 :                                 *phMiraMonLayer->szStringToOperate == 'S' ||
    1285           0 :                                 *phMiraMonLayer->szStringToOperate == 'Y')
    1286          81 :                                 padfValues[nRealMR] = 1;
    1287             :                             else
    1288           0 :                                 padfValues[nRealMR] = 0;
    1289             :                         }
    1290             :                         else
    1291             :                         {
    1292         653 :                             padfValues[nRealMR] =
    1293         653 :                                 atof(phMiraMonLayer->szStringToOperate);
    1294             :                         }
    1295         734 :                         nRealMR++;
    1296             :                     }
    1297             :                 }
    1298             : 
    1299         393 :                 poFeature->SetField(nIField, nRealMR, padfValues);
    1300             :             }
    1301       12713 :             else if (poFeature->GetDefnRef()
    1302       12713 :                          ->GetFieldDefn(nIField)
    1303       12713 :                          ->GetType() == OFTInteger64List)
    1304             :             {
    1305         193 :                 if (!phMiraMonLayer->pMultRecordIndex ||
    1306         193 :                     phMiraMonLayer->pMultRecordIndex[nIElem].nMR == 0)
    1307             :                 {
    1308           0 :                     memset(
    1309           0 :                         phMiraMonLayer->szStringToOperate, 0,
    1310           0 :                         phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField);
    1311           0 :                     continue;
    1312             :                 }
    1313         193 :                 MM_EXT_DBF_N_MULTIPLE_RECORDS nRealMR = 0;
    1314         579 :                 for (nIRecord = 0;
    1315         579 :                      nIRecord < phMiraMonLayer->pMultRecordIndex[nIElem].nMR;
    1316             :                      nIRecord++)
    1317             :                 {
    1318         386 :                     GoToFieldOfMultipleRecord(nIElem, nIRecord, nIField);
    1319         386 :                     memset(
    1320         386 :                         phMiraMonLayer->szStringToOperate, 0,
    1321         386 :                         phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField);
    1322         386 :                     fread_function(
    1323             :                         phMiraMonLayer->szStringToOperate,
    1324             :                         phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField,
    1325             :                         1, phMiraMonLayer->pMMBDXP->pfDataBase);
    1326         386 :                     phMiraMonLayer->szStringToOperate[phMiraMonLayer->pMMBDXP
    1327         386 :                                                           ->pField[nIField]
    1328         386 :                                                           .BytesPerField] =
    1329             :                         '\0';
    1330             : 
    1331         386 :                     if (!MMIsEmptyString(phMiraMonLayer->szStringToOperate))
    1332             :                     {
    1333         696 :                         pnInt64Values[nRealMR] =
    1334         348 :                             CPLAtoGIntBig(phMiraMonLayer->szStringToOperate);
    1335         348 :                         nRealMR++;
    1336             :                     }
    1337             :                 }
    1338             : 
    1339         193 :                 poFeature->SetField(nIField, nRealMR, pnInt64Values);
    1340             :             }
    1341       12520 :             else if (poFeature->GetDefnRef()
    1342       12520 :                              ->GetFieldDefn(nIField)
    1343       17811 :                              ->GetType() == OFTInteger ||
    1344        5291 :                      poFeature->GetDefnRef()
    1345        5291 :                              ->GetFieldDefn(nIField)
    1346       23102 :                              ->GetType() == OFTInteger64 ||
    1347        3330 :                      poFeature->GetDefnRef()
    1348        3330 :                              ->GetFieldDefn(nIField)
    1349        3330 :                              ->GetType() == OFTReal)
    1350             :             {
    1351       11589 :                 if (!phMiraMonLayer->pMultRecordIndex ||
    1352       11589 :                     phMiraMonLayer->pMultRecordIndex[nIElem].nMR == 0)
    1353             :                 {
    1354           0 :                     memset(
    1355           0 :                         phMiraMonLayer->szStringToOperate, 0,
    1356           0 :                         phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField);
    1357           0 :                     continue;
    1358             :                 }
    1359       11589 :                 if (phMiraMonLayer->iMultiRecord !=
    1360             :                     MM_MULTIRECORD_NO_MULTIRECORD)
    1361             :                 {
    1362          99 :                     if (phMiraMonLayer->iMultiRecord == MM_MULTIRECORD_LAST)
    1363             :                     {
    1364          33 :                         GoToFieldOfMultipleRecord(
    1365             :                             nIElem,
    1366          33 :                             phMiraMonLayer->pMultRecordIndex[nIElem].nMR - 1,
    1367             :                             nIField);
    1368             :                     }
    1369          66 :                     else if ((MM_EXT_DBF_N_MULTIPLE_RECORDS)
    1370          66 :                                  phMiraMonLayer->iMultiRecord <
    1371          66 :                              phMiraMonLayer->pMultRecordIndex[nIElem].nMR)
    1372             :                     {
    1373          66 :                         GoToFieldOfMultipleRecord(
    1374             :                             nIElem,
    1375          66 :                             (MM_EXT_DBF_N_MULTIPLE_RECORDS)
    1376          66 :                                 phMiraMonLayer->iMultiRecord,
    1377             :                             nIField);
    1378             :                     }
    1379             :                     else
    1380             :                     {
    1381           0 :                         memset(phMiraMonLayer->szStringToOperate, 0,
    1382           0 :                                phMiraMonLayer->pMMBDXP->pField[nIField]
    1383           0 :                                    .BytesPerField);
    1384           0 :                         continue;
    1385             :                     }
    1386             :                 }
    1387             :                 else
    1388       11490 :                     GoToFieldOfMultipleRecord(nIElem, 0, nIField);
    1389             : 
    1390       11589 :                 memset(phMiraMonLayer->szStringToOperate, 0,
    1391       11589 :                        phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField);
    1392       11589 :                 fread_function(
    1393             :                     phMiraMonLayer->szStringToOperate,
    1394             :                     phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField, 1,
    1395             :                     phMiraMonLayer->pMMBDXP->pfDataBase);
    1396       11589 :                 phMiraMonLayer
    1397       11589 :                     ->szStringToOperate[phMiraMonLayer->pMMBDXP->pField[nIField]
    1398       11589 :                                             .BytesPerField] = '\0';
    1399       11589 :                 MM_RemoveWhitespacesFromEndOfString(
    1400       11589 :                     phMiraMonLayer->szStringToOperate);
    1401             : 
    1402       11589 :                 if (poFeature->GetDefnRef()->GetFieldDefn(nIField)->GetType() ==
    1403             :                     OFTInteger64)
    1404             :                 {
    1405        3922 :                     poFeature->SetField(
    1406             :                         nIField,
    1407        1961 :                         CPLAtoGIntBig(phMiraMonLayer->szStringToOperate));
    1408             :                 }
    1409             :                 else
    1410             :                 {
    1411        9628 :                     if (poFeature->GetDefnRef()
    1412        9628 :                                 ->GetFieldDefn(nIField)
    1413       16857 :                                 ->GetType() == OFTInteger &&
    1414        7229 :                         poFeature->GetDefnRef()
    1415        7229 :                                 ->GetFieldDefn(nIField)
    1416        7229 :                                 ->GetSubType() == OFSTBoolean)
    1417             :                     {
    1418        1130 :                         if (*phMiraMonLayer->szStringToOperate == 'T' ||
    1419        1001 :                             *phMiraMonLayer->szStringToOperate == 'S' ||
    1420        1001 :                             *phMiraMonLayer->szStringToOperate == 'Y')
    1421         129 :                             poFeature->SetField(nIField, 1);
    1422             :                         else
    1423        1001 :                             poFeature->SetField(nIField, 0);
    1424             :                     }
    1425             :                     else
    1426             :                     {
    1427        8498 :                         poFeature->SetField(
    1428        8498 :                             nIField, atof(phMiraMonLayer->szStringToOperate));
    1429             :                     }
    1430             :                 }
    1431             :             }
    1432         931 :             else if (poFeature->GetDefnRef()
    1433         931 :                          ->GetFieldDefn(nIField)
    1434         931 :                          ->GetType() == OFTDate)
    1435             :             {
    1436         931 :                 if (!phMiraMonLayer->pMultRecordIndex ||
    1437         931 :                     phMiraMonLayer->pMultRecordIndex[nIElem].nMR == 0)
    1438             :                 {
    1439           0 :                     memset(
    1440           0 :                         phMiraMonLayer->szStringToOperate, 0,
    1441           0 :                         phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField);
    1442           0 :                     continue;
    1443             :                 }
    1444         931 :                 if (phMiraMonLayer->iMultiRecord !=
    1445             :                     MM_MULTIRECORD_NO_MULTIRECORD)
    1446             :                 {
    1447           9 :                     if (phMiraMonLayer->iMultiRecord == MM_MULTIRECORD_LAST)
    1448           3 :                         GoToFieldOfMultipleRecord(
    1449             :                             nIElem,
    1450           3 :                             phMiraMonLayer->pMultRecordIndex[nIElem].nMR - 1,
    1451             :                             nIField);
    1452           6 :                     else if ((MM_EXT_DBF_N_MULTIPLE_RECORDS)
    1453           6 :                                  phMiraMonLayer->iMultiRecord <
    1454           6 :                              phMiraMonLayer->pMultRecordIndex[nIElem].nMR)
    1455           6 :                         GoToFieldOfMultipleRecord(
    1456             :                             nIElem,
    1457           6 :                             (MM_EXT_DBF_N_MULTIPLE_RECORDS)
    1458           6 :                                 phMiraMonLayer->iMultiRecord,
    1459             :                             nIField);
    1460             :                     else
    1461             :                     {
    1462           0 :                         memset(phMiraMonLayer->szStringToOperate, 0,
    1463           0 :                                phMiraMonLayer->pMMBDXP->pField[nIField]
    1464           0 :                                    .BytesPerField);
    1465           0 :                         continue;
    1466             :                     }
    1467             :                 }
    1468             :                 else
    1469         922 :                     GoToFieldOfMultipleRecord(nIElem, 0, nIField);
    1470             : 
    1471         931 :                 memset(phMiraMonLayer->szStringToOperate, 0,
    1472         931 :                        phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField);
    1473         931 :                 fread_function(
    1474             :                     phMiraMonLayer->szStringToOperate,
    1475             :                     phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField, 1,
    1476             :                     phMiraMonLayer->pMMBDXP->pfDataBase);
    1477         931 :                 phMiraMonLayer
    1478         931 :                     ->szStringToOperate[phMiraMonLayer->pMMBDXP->pField[nIField]
    1479         931 :                                             .BytesPerField] = '\0';
    1480             : 
    1481         931 :                 MM_RemoveWhitespacesFromEndOfString(
    1482         931 :                     phMiraMonLayer->szStringToOperate);
    1483         931 :                 if (!MMIsEmptyString(phMiraMonLayer->szStringToOperate))
    1484             :                 {
    1485             :                     char pszDate_5[5];
    1486             :                     char pszDate_3[3];
    1487             :                     int Year, Month, Day;
    1488             : 
    1489         902 :                     CPLStrlcpy(pszDate_5, phMiraMonLayer->szStringToOperate, 5);
    1490         902 :                     pszDate_5[4] = '\0';
    1491         902 :                     Year = atoi(pszDate_5);
    1492             : 
    1493         902 :                     CPLStrlcpy(pszDate_3, phMiraMonLayer->szStringToOperate + 4,
    1494             :                                3);
    1495         902 :                     (pszDate_3)[2] = '\0';
    1496         902 :                     Month = atoi(pszDate_3);
    1497             : 
    1498         902 :                     CPLStrlcpy(pszDate_3, phMiraMonLayer->szStringToOperate + 6,
    1499             :                                3);
    1500         902 :                     (pszDate_3)[2] = '\0';
    1501         902 :                     Day = atoi(pszDate_3);
    1502             : 
    1503         902 :                     poFeature->SetField(nIField, Year, Month, Day);
    1504             :                 }
    1505             :                 else
    1506          29 :                     poFeature->SetField(nIField,
    1507          29 :                                         phMiraMonLayer->szStringToOperate);
    1508             :             }
    1509             :         }
    1510             :     }
    1511             : 
    1512             :     // Even in case of polygons, where the first feature is jumped
    1513             :     // the ID of the first feature has to be 0, the second, 1,...
    1514        1689 :     poFeature->SetFID(nFeatureId);
    1515             : 
    1516        1689 :     m_nFeaturesRead++;
    1517        1689 :     return poFeature.release();
    1518             : }
    1519             : 
    1520             : /****************************************************************************/
    1521             : /*                         GetFeatureCount()                                */
    1522             : /****************************************************************************/
    1523         164 : GIntBig OGRMiraMonLayer::GetFeatureCount(int bForce)
    1524             : {
    1525         164 :     if (!phMiraMonLayer || m_poFilterGeom != nullptr ||
    1526         136 :         m_poAttrQuery != nullptr)
    1527          40 :         return OGRLayer::GetFeatureCount(bForce);
    1528             : 
    1529         124 :     if (phMiraMonLayer->bIsPolygon)
    1530             :     {
    1531         112 :         return std::max((GIntBig)0,
    1532          56 :                         (GIntBig)(phMiraMonLayer->TopHeader.nElemCount - 1));
    1533             :     }
    1534          68 :     return (GIntBig)phMiraMonLayer->TopHeader.nElemCount;
    1535             : }
    1536             : 
    1537             : /****************************************************************************/
    1538             : /*                      MMProcessMultiGeometry()                            */
    1539             : /****************************************************************************/
    1540         173 : OGRErr OGRMiraMonLayer::MMProcessMultiGeometry(OGRGeometryH hGeom,
    1541             :                                                OGRFeature *poFeature)
    1542             : 
    1543             : {
    1544         173 :     OGRErr eErr = OGRERR_NONE;
    1545         173 :     OGRGeometry *poGeom = OGRGeometry::FromHandle(hGeom);
    1546             : 
    1547         173 :     if (poGeom == nullptr)
    1548             :     {
    1549           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1550             :                  "Features without geometry not supported by MiraMon writer.");
    1551           0 :         return OGRERR_FAILURE;
    1552             :     }
    1553             : 
    1554             :     // Multigeometry field processing (just in case of a MG inside a MG)
    1555         173 :     if (wkbFlatten(poGeom->getGeometryType()) == wkbGeometryCollection)
    1556             :     {
    1557           0 :         int nGeom = OGR_G_GetGeometryCount(OGRGeometry::ToHandle(poGeom));
    1558           0 :         for (int iGeom = 0; iGeom < nGeom; iGeom++)
    1559             :         {
    1560             :             OGRGeometryH poSubGeometry =
    1561           0 :                 OGR_G_GetGeometryRef(OGRGeometry::ToHandle(poGeom), iGeom);
    1562           0 :             eErr = MMProcessMultiGeometry(poSubGeometry, poFeature);
    1563           0 :             if (eErr != OGRERR_NONE)
    1564           0 :                 return eErr;
    1565             :         }
    1566           0 :         return eErr;
    1567             :     }
    1568             :     // Converting multilines and multi points to simple ones
    1569         339 :     if (wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString ||
    1570         166 :         wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint)
    1571             :     {
    1572          15 :         int nGeom = OGR_G_GetGeometryCount(OGRGeometry::ToHandle(poGeom));
    1573          33 :         for (int iGeom = 0; iGeom < nGeom; iGeom++)
    1574             :         {
    1575             :             OGRGeometryH poSubGeometry =
    1576          18 :                 OGR_G_GetGeometryRef(OGRGeometry::ToHandle(poGeom), iGeom);
    1577          18 :             eErr = MMProcessGeometry(poSubGeometry, poFeature, (iGeom == 0));
    1578          18 :             if (eErr != OGRERR_NONE)
    1579           0 :                 return eErr;
    1580             :         }
    1581          15 :         return eErr;
    1582             :     }
    1583             : 
    1584             :     // Processing a simple geometry
    1585         158 :     return MMProcessGeometry(OGRGeometry::ToHandle(poGeom), poFeature, TRUE);
    1586             : }
    1587             : 
    1588             : /****************************************************************************/
    1589             : /*                           MMProcessGeometry()                            */
    1590             : /****************************************************************************/
    1591         210 : OGRErr OGRMiraMonLayer::MMProcessGeometry(OGRGeometryH hGeom,
    1592             :                                           OGRFeature *poFeature,
    1593             :                                           MM_BOOLEAN bcalculateRecord)
    1594             : 
    1595             : {
    1596         210 :     OGRErr eErr = OGRERR_NONE;
    1597         210 :     OGRGeometry *poGeom = nullptr;
    1598         210 :     if (hGeom)
    1599             :     {
    1600         176 :         poGeom = OGRGeometry::FromHandle(hGeom);
    1601             : 
    1602             :         // Translating types from GDAL to MiraMon
    1603         176 :         int eLT = poGeom->getGeometryType();
    1604         176 :         switch (wkbFlatten(eLT))
    1605             :         {
    1606          87 :             case wkbPoint:
    1607          87 :                 phMiraMonLayer = &hMiraMonLayerPNT;
    1608          87 :                 if (OGR_G_Is3D(hGeom))
    1609          43 :                     phMiraMonLayer->eLT = MM_LayerType_Point3d;
    1610             :                 else
    1611          44 :                     phMiraMonLayer->eLT = MM_LayerType_Point;
    1612          87 :                 break;
    1613          48 :             case wkbLineString:
    1614          48 :                 phMiraMonLayer = &hMiraMonLayerARC;
    1615          48 :                 if (OGR_G_Is3D(hGeom))
    1616          17 :                     phMiraMonLayer->eLT = MM_LayerType_Arc3d;
    1617             :                 else
    1618          31 :                     phMiraMonLayer->eLT = MM_LayerType_Arc;
    1619          48 :                 break;
    1620          41 :             case wkbPolygon:
    1621             :             case wkbMultiPolygon:
    1622             :             case wkbPolyhedralSurface:
    1623             :             case wkbTIN:
    1624             :             case wkbTriangle:
    1625          41 :                 phMiraMonLayer = &hMiraMonLayerPOL;
    1626          41 :                 if (OGR_G_Is3D(hGeom))
    1627          15 :                     phMiraMonLayer->eLT = MM_LayerType_Pol3d;
    1628             :                 else
    1629          26 :                     phMiraMonLayer->eLT = MM_LayerType_Pol;
    1630          41 :                 break;
    1631           0 :             case wkbUnknown:
    1632             :             default:
    1633             :             {
    1634           0 :                 CPLError(CE_Warning, CPLE_NotSupported,
    1635             :                          "MiraMon "
    1636             :                          "does not support geometry type '%d'",
    1637             :                          eLT);
    1638           0 :                 return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
    1639             :             }
    1640             :         }
    1641             :     }
    1642             :     else
    1643             :     {
    1644             :         // Processing only the table. A DBF will be generated
    1645          34 :         phMiraMonLayer = &hMiraMonLayerReadOrNonGeom;
    1646          34 :         phMiraMonLayer->eLT = MM_LayerType_Unknown;
    1647             :     }
    1648             : 
    1649             :     /* -------------------------------------------------------------------- */
    1650             :     /*      Field translation from GDAL to MiraMon                          */
    1651             :     /* -------------------------------------------------------------------- */
    1652             :     // Reset the object where read coordinates are going to be stored
    1653         210 :     MMResetFeatureGeometry(&hMMFeature);
    1654         210 :     if (bcalculateRecord)
    1655             :     {
    1656         207 :         MMResetFeatureRecord(&hMMFeature);
    1657         207 :         if (!phMiraMonLayer->pLayerDB)
    1658             :         {
    1659         107 :             eErr = TranslateFieldsToMM();
    1660         107 :             if (eErr != OGRERR_NONE)
    1661           0 :                 return eErr;
    1662             :         }
    1663             :         // Content field translation from GDAL to MiraMon
    1664         207 :         eErr = TranslateFieldsValuesToMM(poFeature);
    1665         207 :         if (eErr != OGRERR_NONE)
    1666             :         {
    1667           0 :             CPLDebugOnly("MiraMon", "Error in MMProcessGeometry()");
    1668           0 :             return eErr;
    1669             :         }
    1670             :     }
    1671             : 
    1672             :     /* -------------------------------------------------------------------- */
    1673             :     /*      Write Geometry                                                  */
    1674             :     /* -------------------------------------------------------------------- */
    1675             : 
    1676             :     // Reads objects with coordinates and transform them to MiraMon
    1677         210 :     if (poGeom)
    1678             :     {
    1679         176 :         eErr = MMLoadGeometry(OGRGeometry::ToHandle(poGeom));
    1680             :     }
    1681             :     else
    1682             :     {
    1683          34 :         if (!phMiraMonLayer->bIsBeenInit)
    1684             :         {
    1685          17 :             phMiraMonLayer->bIsDBF = TRUE;
    1686          17 :             if (MMInitLayerByType(phMiraMonLayer))
    1687           0 :                 eErr = OGRERR_FAILURE;
    1688             : 
    1689          17 :             phMiraMonLayer->bIsBeenInit = 1;
    1690             :         }
    1691             :     }
    1692             : 
    1693             :     // Writes coordinates to the disk
    1694         210 :     if (eErr == OGRERR_NONE)
    1695         210 :         return MMWriteGeometry();
    1696           0 :     CPLDebugOnly("MiraMon", "Error in MMProcessGeometry()");
    1697           0 :     return eErr;
    1698             : }
    1699             : 
    1700             : /****************************************************************************/
    1701             : /*                           ICreateFeature()                               */
    1702             : /****************************************************************************/
    1703             : 
    1704         195 : OGRErr OGRMiraMonLayer::ICreateFeature(OGRFeature *poFeature)
    1705             : 
    1706             : {
    1707         195 :     OGRErr eErr = OGRERR_NONE;
    1708             : 
    1709         195 :     if (!m_bUpdate)
    1710             :     {
    1711           0 :         CPLError(CE_Failure, CPLE_NoWriteAccess,
    1712             :                  "Cannot create features on a read-only dataset.");
    1713           0 :         return OGRERR_FAILURE;
    1714             :     }
    1715             : 
    1716             :     /* -------------------------------------------------------------------- */
    1717             :     /*      Write out the feature                                           */
    1718             :     /* -------------------------------------------------------------------- */
    1719         195 :     OGRGeometry *poGeom = poFeature->GetGeometryRef();
    1720             : 
    1721             :     // Processing a feature without geometry.
    1722         195 :     if (poGeom == nullptr)
    1723             :     {
    1724          34 :         eErr = MMProcessGeometry(nullptr, poFeature, TRUE);
    1725          34 :         if (phMiraMonLayer->bIsDBF && phMiraMonLayer->TopHeader.nElemCount > 0)
    1726          34 :             poFeature->SetFID((GIntBig)phMiraMonLayer->TopHeader.nElemCount -
    1727          34 :                               1);
    1728          34 :         return eErr;
    1729             :     }
    1730             : 
    1731             :     // Converting to simple geometries
    1732         161 :     if (wkbFlatten(poGeom->getGeometryType()) == wkbGeometryCollection)
    1733             :     {
    1734           6 :         int nGeom = OGR_G_GetGeometryCount(OGRGeometry::ToHandle(poGeom));
    1735          24 :         for (int iGeom = 0; iGeom < nGeom; iGeom++)
    1736             :         {
    1737             :             OGRGeometryH poSubGeometry =
    1738          18 :                 OGR_G_GetGeometryRef(OGRGeometry::ToHandle(poGeom), iGeom);
    1739          18 :             eErr = MMProcessMultiGeometry(poSubGeometry, poFeature);
    1740          18 :             if (eErr != OGRERR_NONE)
    1741           0 :                 return eErr;
    1742             :         }
    1743             : 
    1744           6 :         return eErr;
    1745             :     }
    1746             : 
    1747             :     // Processing the geometry
    1748         155 :     eErr = MMProcessMultiGeometry(OGRGeometry::ToHandle(poGeom), poFeature);
    1749             : 
    1750             :     // Set the FID from 0 index
    1751         155 :     if (phMiraMonLayer)
    1752             :     {
    1753         155 :         if (phMiraMonLayer->bIsPolygon &&
    1754          35 :             phMiraMonLayer->TopHeader.nElemCount > 1)
    1755          35 :             poFeature->SetFID((GIntBig)phMiraMonLayer->TopHeader.nElemCount -
    1756          35 :                               2);
    1757         120 :         else if (phMiraMonLayer->TopHeader.nElemCount > 0)
    1758         120 :             poFeature->SetFID((GIntBig)phMiraMonLayer->TopHeader.nElemCount -
    1759         120 :                               1);
    1760             :     }
    1761         155 :     return eErr;
    1762             : }
    1763             : 
    1764             : /****************************************************************************/
    1765             : /*                          MMDumpVertices()                                */
    1766             : /****************************************************************************/
    1767             : 
    1768         188 : OGRErr OGRMiraMonLayer::MMDumpVertices(OGRGeometryH hGeom,
    1769             :                                        MM_BOOLEAN bExternalRing,
    1770             :                                        MM_BOOLEAN bUseVFG)
    1771             : {
    1772             :     // If the MiraMonLayer structure has not been init,
    1773             :     // here is the moment to do that.
    1774         188 :     if (!phMiraMonLayer)
    1775           0 :         return OGRERR_FAILURE;
    1776             : 
    1777         188 :     if (!phMiraMonLayer->bIsBeenInit)
    1778             :     {
    1779          90 :         if (MMInitLayerByType(phMiraMonLayer))
    1780           0 :             return OGRERR_FAILURE;
    1781          90 :         phMiraMonLayer->bIsBeenInit = 1;
    1782             :     }
    1783         376 :     if (MMResize_MM_N_VERTICES_TYPE_Pointer(
    1784             :             &hMMFeature.pNCoordRing, &hMMFeature.nMaxpNCoordRing,
    1785         188 :             (MM_N_VERTICES_TYPE)hMMFeature.nNRings + 1, MM_MEAN_NUMBER_OF_RINGS,
    1786         188 :             0))
    1787           0 :         return OGRERR_FAILURE;
    1788             : 
    1789         188 :     if (bUseVFG)
    1790             :     {
    1791         106 :         if (MMResizeVFGPointer(&hMMFeature.flag_VFG, &hMMFeature.nMaxVFG,
    1792          53 :                                (MM_INTERNAL_FID)hMMFeature.nNRings + 1,
    1793          53 :                                MM_MEAN_NUMBER_OF_RINGS, 0))
    1794           0 :             return OGRERR_FAILURE;
    1795             : 
    1796          53 :         hMMFeature.flag_VFG[hMMFeature.nIRing] = MM_END_ARC_IN_RING;
    1797          53 :         if (bExternalRing)
    1798          45 :             hMMFeature.flag_VFG[hMMFeature.nIRing] |= MM_EXTERIOR_ARC_SIDE;
    1799             :         // In MiraMon the external ring is clockwise and the internals are
    1800             :         // coounterclockwise.
    1801          53 :         OGRGeometry *poGeom = OGRGeometry::FromHandle(hGeom);
    1802          61 :         if ((bExternalRing && !poGeom->toLinearRing()->isClockwise()) ||
    1803           8 :             (!bExternalRing && poGeom->toLinearRing()->isClockwise()))
    1804           1 :             hMMFeature.flag_VFG[hMMFeature.nIRing] |= MM_ROTATE_ARC;
    1805             :     }
    1806             : 
    1807         188 :     hMMFeature.pNCoordRing[hMMFeature.nIRing] = OGR_G_GetPointCount(hGeom);
    1808             : 
    1809         376 :     if (MMResizeMM_POINT2DPointer(&hMMFeature.pCoord, &hMMFeature.nMaxpCoord,
    1810         188 :                                   hMMFeature.nICoord +
    1811         188 :                                       hMMFeature.pNCoordRing[hMMFeature.nIRing],
    1812         188 :                                   MM_MEAN_NUMBER_OF_NCOORDS, 0))
    1813           0 :         return OGRERR_FAILURE;
    1814         376 :     if (MMResizeDoublePointer(&hMMFeature.pZCoord, &hMMFeature.nMaxpZCoord,
    1815         188 :                               hMMFeature.nICoord +
    1816         188 :                                   hMMFeature.pNCoordRing[hMMFeature.nIRing],
    1817         188 :                               MM_MEAN_NUMBER_OF_NCOORDS, 0))
    1818           0 :         return OGRERR_FAILURE;
    1819             : 
    1820         188 :     hMMFeature.bAllZHaveSameValue = TRUE;
    1821         188 :     for (int iPoint = 0;
    1822         743 :          (MM_N_VERTICES_TYPE)iPoint < hMMFeature.pNCoordRing[hMMFeature.nIRing];
    1823             :          iPoint++)
    1824             :     {
    1825         555 :         hMMFeature.pCoord[hMMFeature.nICoord].dfX = OGR_G_GetX(hGeom, iPoint);
    1826         555 :         hMMFeature.pCoord[hMMFeature.nICoord].dfY = OGR_G_GetY(hGeom, iPoint);
    1827         555 :         if (OGR_G_GetCoordinateDimension(hGeom) == 2)
    1828         387 :             hMMFeature.pZCoord[hMMFeature.nICoord] =
    1829             :                 MM_NODATA_COORD_Z;  // Possible rare case
    1830             :         else
    1831             :         {
    1832         168 :             hMMFeature.pZCoord[hMMFeature.nICoord] = OGR_G_GetZ(hGeom, iPoint);
    1833         168 :             phMiraMonLayer->bIsReal3d = 1;
    1834             :         }
    1835             : 
    1836             :         // Asking if last Z-coordinate is the same than this one.
    1837             :         // If all Z-coordinates are the same, following MiraMon specification
    1838             :         // only the hMMFeature.pZCoord[0] value will be used and the number of
    1839             :         // vertices will be saved as a negative number on disk
    1840         555 :         if (iPoint > 0 &&
    1841         367 :             !CPLIsEqual(hMMFeature.pZCoord[hMMFeature.nICoord],
    1842             :                         hMMFeature.pZCoord[hMMFeature.nICoord - 1]))
    1843          40 :             hMMFeature.bAllZHaveSameValue = FALSE;
    1844             : 
    1845         555 :         hMMFeature.nICoord++;
    1846             :     }
    1847         188 :     hMMFeature.nIRing++;
    1848         188 :     hMMFeature.nNRings++;
    1849         188 :     return OGRERR_NONE;
    1850             : }
    1851             : 
    1852             : /****************************************************************************/
    1853             : /*                           MMLoadGeometry()                               */
    1854             : /*                                                                          */
    1855             : /*      Loads on a MiraMon object Feature all coordinates from feature      */
    1856             : /*                                                                          */
    1857             : /****************************************************************************/
    1858         190 : OGRErr OGRMiraMonLayer::MMLoadGeometry(OGRGeometryH hGeom)
    1859             : 
    1860             : {
    1861         190 :     OGRErr eErr = OGRERR_NONE;
    1862             :     MM_BOOLEAN bExternalRing;
    1863             : 
    1864             :     /* -------------------------------------------------------------------- */
    1865             :     /*      This is a geometry with sub-geometries.                         */
    1866             :     /* -------------------------------------------------------------------- */
    1867         190 :     int nGeom = OGR_G_GetGeometryCount(hGeom);
    1868             : 
    1869         190 :     int eLT = wkbFlatten(OGR_G_GetGeometryType(hGeom));
    1870             : 
    1871         190 :     if (eLT == wkbMultiPolygon || eLT == wkbPolyhedralSurface || eLT == wkbTIN)
    1872             :     {
    1873          24 :         for (int iGeom = 0; iGeom < nGeom && eErr == OGRERR_NONE; iGeom++)
    1874             :         {
    1875          14 :             OGRGeometryH poSubGeometry = OGR_G_GetGeometryRef(hGeom, iGeom);
    1876             : 
    1877             :             // Reads all coordinates
    1878          14 :             eErr = MMLoadGeometry(poSubGeometry);
    1879          14 :             if (eErr != OGRERR_NONE)
    1880           0 :                 return eErr;
    1881             :         }
    1882             :     }
    1883         190 :     if (eLT == wkbTriangle)
    1884             :     {
    1885           0 :         for (int iGeom = 0; iGeom < nGeom && eErr == OGRERR_NONE; iGeom++)
    1886             :         {
    1887           0 :             OGRGeometryH poSubGeometry = OGR_G_GetGeometryRef(hGeom, iGeom);
    1888             : 
    1889             :             // Reads all coordinates
    1890           0 :             eErr = MMDumpVertices(poSubGeometry, TRUE, TRUE);
    1891           0 :             if (eErr != OGRERR_NONE)
    1892           0 :                 return eErr;
    1893             :         }
    1894             :     }
    1895         190 :     else if (eLT == wkbPolygon)
    1896             :     {
    1897          98 :         for (int iGeom = 0; iGeom < nGeom && eErr == OGRERR_NONE; iGeom++)
    1898             :         {
    1899          53 :             OGRGeometryH poSubGeometry = OGR_G_GetGeometryRef(hGeom, iGeom);
    1900             : 
    1901          53 :             if (iGeom == 0)
    1902          45 :                 bExternalRing = true;
    1903             :             else
    1904           8 :                 bExternalRing = false;
    1905             : 
    1906          53 :             eErr = MMDumpVertices(poSubGeometry, bExternalRing, TRUE);
    1907          53 :             if (eErr != OGRERR_NONE)
    1908           0 :                 return eErr;
    1909             :         }
    1910             :     }
    1911         145 :     else if (eLT == wkbPoint || eLT == wkbLineString)
    1912             :     {
    1913             :         // Reads all coordinates
    1914         135 :         eErr = MMDumpVertices(hGeom, true, FALSE);
    1915             : 
    1916         135 :         if (eErr != OGRERR_NONE)
    1917           0 :             return eErr;
    1918             :     }
    1919          10 :     else if (eLT == wkbGeometryCollection)
    1920             :     {
    1921           0 :         CPLError(
    1922             :             CE_Failure, CPLE_NotSupported,
    1923             :             "MiraMon: wkbGeometryCollection inside a wkbGeometryCollection?");
    1924           0 :         return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
    1925             :     }
    1926             : 
    1927         190 :     return OGRERR_NONE;
    1928             : }
    1929             : 
    1930             : /****************************************************************************/
    1931             : /*                           WriteGeometry()                                */
    1932             : /*                                                                          */
    1933             : /*                    Writes a geometry to the file.                        */
    1934             : /****************************************************************************/
    1935             : 
    1936         210 : OGRErr OGRMiraMonLayer::MMWriteGeometry()
    1937             : 
    1938             : {
    1939         210 :     OGRErr eErr = MMAddFeature(phMiraMonLayer, &hMMFeature);
    1940             : 
    1941         210 :     if (eErr == MM_FATAL_ERROR_WRITING_FEATURES)
    1942             :     {
    1943           0 :         CPLDebugOnly("MiraMon", "Error in MMAddFeature() "
    1944             :                                 "MM_FATAL_ERROR_WRITING_FEATURES");
    1945           0 :         CPLError(CE_Failure, CPLE_FileIO, "MiraMon write failure: %s",
    1946           0 :                  VSIStrerror(errno));
    1947           0 :         return OGRERR_FAILURE;
    1948             :     }
    1949         210 :     if (eErr == MM_STOP_WRITING_FEATURES)
    1950             :     {
    1951           0 :         CPLDebugOnly("MiraMon", "Error in MMAddFeature() "
    1952             :                                 "MM_STOP_WRITING_FEATURES");
    1953           0 :         CPLError(CE_Failure, CPLE_FileIO,
    1954             :                  "MiraMon format limitations. Try V2.0 option (-lco "
    1955             :                  "Version=V2.0). " sprintf_UINT64
    1956             :                  " elements have been written correctly.",
    1957           0 :                  phMiraMonLayer->TopHeader.nElemCount);
    1958           0 :         return OGRERR_FAILURE;
    1959             :     }
    1960             : 
    1961         210 :     return OGRERR_NONE;
    1962             : }
    1963             : 
    1964             : /****************************************************************************/
    1965             : /*                       TranslateFieldsToMM()                              */
    1966             : /*                                                                          */
    1967             : /*      Translase ogr Fields to a structure that MiraMon can understand     */
    1968             : /****************************************************************************/
    1969             : 
    1970         107 : OGRErr OGRMiraMonLayer::TranslateFieldsToMM()
    1971             : 
    1972             : {
    1973         107 :     if (m_poFeatureDefn->GetFieldCount() == 0)
    1974           0 :         return OGRERR_NONE;
    1975             : 
    1976         107 :     CPLDebugOnly("MiraMon", "Translating fields to MiraMon...");
    1977             :     // If the structure is filled we do anything
    1978         107 :     if (phMiraMonLayer->pLayerDB)
    1979           0 :         return OGRERR_NONE;
    1980             : 
    1981         214 :     phMiraMonLayer->pLayerDB = static_cast<struct MiraMonDataBase *>(
    1982         107 :         VSICalloc(sizeof(*phMiraMonLayer->pLayerDB), 1));
    1983         107 :     if (!phMiraMonLayer->pLayerDB)
    1984           0 :         return OGRERR_NOT_ENOUGH_MEMORY;
    1985             : 
    1986         214 :     phMiraMonLayer->pLayerDB->pFields =
    1987             :         static_cast<struct MiraMonDataBaseField *>(
    1988         107 :             VSICalloc(m_poFeatureDefn->GetFieldCount(),
    1989             :                       sizeof(*(phMiraMonLayer->pLayerDB->pFields))));
    1990         107 :     if (!phMiraMonLayer->pLayerDB->pFields)
    1991           0 :         return OGRERR_NOT_ENOUGH_MEMORY;
    1992             : 
    1993         107 :     phMiraMonLayer->pLayerDB->nNFields = 0;
    1994         107 :     if (phMiraMonLayer->pLayerDB->pFields)
    1995             :     {
    1996         107 :         memset(phMiraMonLayer->pLayerDB->pFields, 0,
    1997         107 :                m_poFeatureDefn->GetFieldCount() *
    1998             :                    sizeof(*phMiraMonLayer->pLayerDB->pFields));
    1999         107 :         for (MM_EXT_DBF_N_FIELDS iField = 0;
    2000         682 :              iField < (MM_EXT_DBF_N_FIELDS)m_poFeatureDefn->GetFieldCount();
    2001             :              iField++)
    2002             :         {
    2003         575 :             switch (m_poFeatureDefn->GetFieldDefn(iField)->GetType())
    2004             :             {
    2005         127 :                 case OFTInteger:
    2006             :                 case OFTIntegerList:
    2007         127 :                     if (m_poFeatureDefn->GetFieldDefn(iField)->GetSubType() ==
    2008             :                         OFSTBoolean)
    2009             :                     {
    2010          33 :                         phMiraMonLayer->pLayerDB->pFields[iField].eFieldType =
    2011             :                             MM_Logic;
    2012             :                     }
    2013             :                     else
    2014             :                     {
    2015          94 :                         phMiraMonLayer->pLayerDB->pFields[iField].eFieldType =
    2016             :                             MM_Numeric;
    2017             :                     }
    2018             : 
    2019         127 :                     phMiraMonLayer->pLayerDB->pFields[iField]
    2020         127 :                         .nNumberOfDecimals = 0;
    2021         127 :                     break;
    2022             : 
    2023          79 :                 case OFTInteger64:
    2024             :                 case OFTInteger64List:
    2025          79 :                     phMiraMonLayer->pLayerDB->pFields[iField].bIs64BitInteger =
    2026             :                         TRUE;
    2027          79 :                     phMiraMonLayer->pLayerDB->pFields[iField].eFieldType =
    2028             :                         MM_Numeric;
    2029          79 :                     phMiraMonLayer->pLayerDB->pFields[iField]
    2030          79 :                         .nNumberOfDecimals = 0;
    2031          79 :                     break;
    2032             : 
    2033         109 :                 case OFTReal:
    2034             :                 case OFTRealList:
    2035         109 :                     phMiraMonLayer->pLayerDB->pFields[iField].eFieldType =
    2036             :                         MM_Numeric;
    2037         109 :                     phMiraMonLayer->pLayerDB->pFields[iField]
    2038         109 :                         .nNumberOfDecimals =
    2039         109 :                         m_poFeatureDefn->GetFieldDefn(iField)->GetPrecision();
    2040         109 :                     break;
    2041             : 
    2042           0 :                 case OFTBinary:
    2043           0 :                     phMiraMonLayer->pLayerDB->pFields[iField].eFieldType =
    2044             :                         MM_Character;
    2045           0 :                     break;
    2046             : 
    2047          68 :                 case OFTDate:
    2048          68 :                     phMiraMonLayer->pLayerDB->pFields[iField].eFieldType =
    2049             :                         MM_Data;
    2050          68 :                     break;
    2051             : 
    2052          52 :                 case OFTTime:
    2053             :                 case OFTDateTime:
    2054          52 :                     phMiraMonLayer->pLayerDB->pFields[iField].eFieldType =
    2055             :                         MM_Character;
    2056          52 :                     break;
    2057             : 
    2058         140 :                 case OFTString:
    2059             :                 case OFTStringList:
    2060             :                 default:
    2061         140 :                     phMiraMonLayer->pLayerDB->pFields[iField].eFieldType =
    2062             :                         MM_Character;
    2063         140 :                     break;
    2064             :             }
    2065         575 :             if (m_poFeatureDefn->GetFieldDefn(iField)->GetType() == OFTDate)
    2066          68 :                 phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize = 8;
    2067         507 :             else if ((m_poFeatureDefn->GetFieldDefn(iField)->GetType() ==
    2068         398 :                           OFTInteger ||
    2069         398 :                       m_poFeatureDefn->GetFieldDefn(iField)->GetType() ==
    2070        1014 :                           OFTIntegerList) &&
    2071         127 :                      m_poFeatureDefn->GetFieldDefn(iField)->GetSubType() ==
    2072             :                          OFSTBoolean)
    2073             :             {
    2074          33 :                 phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize = 1;
    2075             :             }
    2076             :             else
    2077             :             {
    2078             :                 // As https://gdal.org/api/ogrfeature_cpp.html indicates that
    2079             :                 // precision (number of digits after decimal point) is optional,
    2080             :                 // and a 0 is probably the default value, in that case we prefer
    2081             :                 // to save all the guaranteed significant figures in a double
    2082             :                 // (needed if a field contains, for instance, coordinates in
    2083             :                 // geodetic degrees and a 1:1000 map precision applies).
    2084         474 :                 if (m_poFeatureDefn->GetFieldDefn(iField)->GetPrecision() == 0)
    2085             :                 {
    2086         450 :                     if (m_poFeatureDefn->GetFieldDefn(iField)->GetType() ==
    2087         831 :                             OFTReal ||
    2088         381 :                         m_poFeatureDefn->GetFieldDefn(iField)->GetType() ==
    2089             :                             OFTRealList)
    2090             :                     {
    2091          85 :                         phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize =
    2092             :                             20;
    2093          85 :                         phMiraMonLayer->pLayerDB->pFields[iField]
    2094          85 :                             .nNumberOfDecimals = MAX_RELIABLE_SF_DOUBLE;
    2095             :                     }
    2096             :                     else
    2097             :                     {
    2098         365 :                         phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize =
    2099         365 :                             m_poFeatureDefn->GetFieldDefn(iField)->GetWidth();
    2100         365 :                         if (phMiraMonLayer->pLayerDB->pFields[iField]
    2101         365 :                                 .nFieldSize == 0)
    2102         270 :                             phMiraMonLayer->pLayerDB->pFields[iField]
    2103         270 :                                 .nFieldSize = 3;
    2104             :                     }
    2105             : 
    2106             :                     // Some exceptions for some fields:
    2107         450 :                     if (EQUAL(
    2108             :                             m_poFeatureDefn->GetFieldDefn(iField)->GetNameRef(),
    2109             :                             "fontsize"))
    2110             :                     {
    2111           0 :                         phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize =
    2112             :                             11;
    2113           0 :                         phMiraMonLayer->pLayerDB->pFields[iField]
    2114           0 :                             .nNumberOfDecimals = 3;
    2115             :                     }
    2116         450 :                     else if (EQUAL(m_poFeatureDefn->GetFieldDefn(iField)
    2117             :                                        ->GetNameRef(),
    2118         450 :                                    "leading") ||
    2119         450 :                              EQUAL(m_poFeatureDefn->GetFieldDefn(iField)
    2120             :                                        ->GetNameRef(),
    2121         900 :                                    "chrwidth") ||
    2122         450 :                              EQUAL(m_poFeatureDefn->GetFieldDefn(iField)
    2123             :                                        ->GetNameRef(),
    2124             :                                    "chrspacing"))
    2125             :                     {
    2126           0 :                         phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize =
    2127             :                             8;
    2128           0 :                         phMiraMonLayer->pLayerDB->pFields[iField]
    2129           0 :                             .nNumberOfDecimals = 3;
    2130             :                     }
    2131         450 :                     else if (EQUAL(m_poFeatureDefn->GetFieldDefn(iField)
    2132             :                                        ->GetNameRef(),
    2133             :                                    "orientacio"))
    2134             :                     {
    2135           0 :                         phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize =
    2136             :                             7;
    2137           0 :                         phMiraMonLayer->pLayerDB->pFields[iField]
    2138           0 :                             .nNumberOfDecimals = 2;
    2139             :                     }
    2140             :                 }
    2141             :                 else
    2142             :                 {
    2143             :                     // One more space for the "."
    2144          24 :                     phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize =
    2145          48 :                         (unsigned int)(m_poFeatureDefn->GetFieldDefn(iField)
    2146          24 :                                            ->GetWidth() +
    2147             :                                        1);
    2148             :                 }
    2149             :             }
    2150             : 
    2151             :             // Recode from UTF-8 if necessary
    2152         575 :             if (phMiraMonLayer->nCharSet != MM_JOC_CARAC_UTF8_DBF)
    2153             :             {
    2154         565 :                 char *pszString = CPLRecode(
    2155         565 :                     m_poFeatureDefn->GetFieldDefn(iField)->GetNameRef(),
    2156             :                     CPL_ENC_UTF8, CPL_ENC_ISO8859_1);
    2157         565 :                 CPLStrlcpy(
    2158         565 :                     phMiraMonLayer->pLayerDB->pFields[iField].pszFieldName,
    2159             :                     pszString, MM_MAX_LON_FIELD_NAME_DBF);
    2160         565 :                 CPLFree(pszString);
    2161             :             }
    2162             :             else
    2163             :             {
    2164          10 :                 CPLStrlcpy(
    2165          10 :                     phMiraMonLayer->pLayerDB->pFields[iField].pszFieldName,
    2166          10 :                     m_poFeatureDefn->GetFieldDefn(iField)->GetNameRef(),
    2167             :                     MM_MAX_LON_FIELD_NAME_DBF);
    2168             :             }
    2169             : 
    2170         575 :             if (m_poFeatureDefn->GetFieldDefn(iField)->GetAlternativeNameRef())
    2171             :             {
    2172         575 :                 if (phMiraMonLayer->nCharSet != MM_JOC_CARAC_UTF8_DBF)
    2173             :                 {
    2174             :                     char *pszString =
    2175         565 :                         CPLRecode(m_poFeatureDefn->GetFieldDefn(iField)
    2176             :                                       ->GetAlternativeNameRef(),
    2177             :                                   CPL_ENC_UTF8, CPL_ENC_ISO8859_1);
    2178         565 :                     CPLStrlcpy(phMiraMonLayer->pLayerDB->pFields[iField]
    2179         565 :                                    .pszFieldDescription,
    2180             :                                pszString, MM_MAX_BYTES_FIELD_DESC);
    2181         565 :                     CPLFree(pszString);
    2182             :                 }
    2183             :                 else
    2184             :                 {
    2185          10 :                     CPLStrlcpy(phMiraMonLayer->pLayerDB->pFields[iField]
    2186          10 :                                    .pszFieldDescription,
    2187          10 :                                m_poFeatureDefn->GetFieldDefn(iField)
    2188             :                                    ->GetAlternativeNameRef(),
    2189             :                                MM_MAX_BYTES_FIELD_DESC);
    2190             :                 }
    2191             :             }
    2192         575 :             phMiraMonLayer->pLayerDB->nNFields++;
    2193             :         }
    2194             :     }
    2195             : 
    2196         107 :     CPLDebugOnly("MiraMon", "Fields to MiraMon translated.");
    2197         107 :     return OGRERR_NONE;
    2198             : }
    2199             : 
    2200             : /****************************************************************************/
    2201             : /*                       TranslateFieldsValuesToMM()                        */
    2202             : /*                                                                          */
    2203             : /*      Translate ogr Fields to a structure that MiraMon can understand     */
    2204             : /****************************************************************************/
    2205             : 
    2206         207 : OGRErr OGRMiraMonLayer::TranslateFieldsValuesToMM(OGRFeature *poFeature)
    2207             : 
    2208             : {
    2209         207 :     if (m_poFeatureDefn->GetFieldCount() == 0)
    2210             :     {
    2211             :         // MiraMon have private DataBase records
    2212           0 :         hMMFeature.nNumMRecords = 1;
    2213           0 :         return OGRERR_NONE;
    2214             :     }
    2215             : 
    2216             :     MM_EXT_DBF_N_MULTIPLE_RECORDS nIRecord;
    2217         207 :     MM_EXT_DBF_N_FIELDS nNumFields = m_poFeatureDefn->GetFieldCount();
    2218             :     MM_EXT_DBF_N_MULTIPLE_RECORDS nNumRecords, nRealNumRecords;
    2219         207 :     hMMFeature.nNumMRecords = 0;
    2220             : #define MAX_SIZE_OF_FIELD_NUMBER_WITH_MINUS 22
    2221             : 
    2222        1548 :     for (MM_EXT_DBF_N_FIELDS iField = 0; iField < nNumFields; iField++)
    2223             :     {
    2224        1341 :         OGRFieldType eFType = m_poFeatureDefn->GetFieldDefn(iField)->GetType();
    2225             :         OGRFieldSubType eFSType =
    2226        1341 :             m_poFeatureDefn->GetFieldDefn(iField)->GetSubType();
    2227        1341 :         const char *pszRawValue = poFeature->GetFieldAsString(iField);
    2228             : 
    2229        1341 :         if (eFType == OFTStringList)
    2230             :         {
    2231          20 :             char **papszValues = poFeature->GetFieldAsStringList(iField);
    2232          20 :             nRealNumRecords = nNumRecords = CSLCount(papszValues);
    2233          20 :             if (nNumRecords == 0)
    2234           0 :                 nNumRecords++;
    2235          20 :             hMMFeature.nNumMRecords =
    2236          20 :                 max_function(hMMFeature.nNumMRecords, nNumRecords);
    2237          20 :             if (MMResizeMiraMonRecord(
    2238             :                     &hMMFeature.pRecords, &hMMFeature.nMaxMRecords,
    2239             :                     hMMFeature.nNumMRecords, MM_INC_NUMBER_OF_RECORDS,
    2240          20 :                     hMMFeature.nNumMRecords))
    2241           0 :                 return OGRERR_NOT_ENOUGH_MEMORY;
    2242             : 
    2243          59 :             for (nIRecord = 0; nIRecord < nRealNumRecords; nIRecord++)
    2244             :             {
    2245          39 :                 hMMFeature.pRecords[nIRecord].nNumField =
    2246          39 :                     m_poFeatureDefn->GetFieldCount();
    2247             : 
    2248          20 :                 if (MMResizeMiraMonFieldValue(
    2249          39 :                         &(hMMFeature.pRecords[nIRecord].pField),
    2250          39 :                         &hMMFeature.pRecords[nIRecord].nMaxField,
    2251          39 :                         hMMFeature.pRecords[nIRecord].nNumField,
    2252             :                         (nIRecord == 0)
    2253             :                             ? MM_INC_NUMBER_OF_FIELDS
    2254          19 :                             : hMMFeature.pRecords[nIRecord - 1].nMaxField,
    2255          78 :                         hMMFeature.pRecords[nIRecord].nNumField))
    2256           0 :                     return OGRERR_NOT_ENOUGH_MEMORY;
    2257             : 
    2258          39 :                 if (nIRecord > 0)
    2259             :                 {
    2260             :                     // The number of fields of this new record is the same as the
    2261             :                     // last one
    2262          19 :                     hMMFeature.pRecords[nIRecord].nNumField =
    2263          19 :                         hMMFeature.pRecords[nIRecord - 1].nNumField;
    2264             :                 }
    2265             : 
    2266          39 :                 if (phMiraMonLayer->nCharSet != MM_JOC_CARAC_UTF8_DBF)
    2267             :                 {
    2268             :                     // MiraMon encoding is ISO 8859-1 (Latin1) -> Recode from UTF-8
    2269          70 :                     char *pszString = CPLRecode(
    2270          35 :                         papszValues[nIRecord], CPL_ENC_UTF8, CPL_ENC_ISO8859_1);
    2271          70 :                     if (MM_SecureCopyStringFieldValue(
    2272          35 :                             &hMMFeature.pRecords[nIRecord]
    2273          35 :                                  .pField[iField]
    2274             :                                  .pDinValue,
    2275             :                             pszString,
    2276          35 :                             &hMMFeature.pRecords[nIRecord]
    2277          35 :                                  .pField[iField]
    2278          35 :                                  .nNumDinValue))
    2279             :                     {
    2280           0 :                         CPLFree(pszString);
    2281           0 :                         return OGRERR_NOT_ENOUGH_MEMORY;
    2282             :                     }
    2283          35 :                     CPLFree(pszString);
    2284             :                 }
    2285             :                 else
    2286             :                 {
    2287           8 :                     if (MM_SecureCopyStringFieldValue(
    2288           4 :                             &hMMFeature.pRecords[nIRecord]
    2289           4 :                                  .pField[iField]
    2290             :                                  .pDinValue,
    2291           4 :                             papszValues[nIRecord],
    2292           4 :                             &hMMFeature.pRecords[nIRecord]
    2293           4 :                                  .pField[iField]
    2294           4 :                                  .nNumDinValue))
    2295           0 :                         return OGRERR_NOT_ENOUGH_MEMORY;
    2296             :                 }
    2297          39 :                 hMMFeature.pRecords[nIRecord].pField[iField].bIsValid = 1;
    2298             :             }
    2299             :         }
    2300        1321 :         else if (eFType == OFTIntegerList)
    2301             :         {
    2302          21 :             int nCount = 0;
    2303             :             const int *panValues =
    2304          21 :                 poFeature->GetFieldAsIntegerList(iField, &nCount);
    2305             : 
    2306          21 :             nRealNumRecords = nNumRecords = nCount;
    2307          21 :             if (nNumRecords == 0)
    2308           0 :                 nNumRecords++;
    2309          21 :             hMMFeature.nNumMRecords =
    2310          21 :                 max_function(hMMFeature.nNumMRecords, nNumRecords);
    2311          21 :             if (MMResizeMiraMonRecord(
    2312             :                     &hMMFeature.pRecords, &hMMFeature.nMaxMRecords,
    2313             :                     hMMFeature.nNumMRecords, MM_INC_NUMBER_OF_RECORDS,
    2314          21 :                     hMMFeature.nNumMRecords))
    2315           0 :                 return OGRERR_NOT_ENOUGH_MEMORY;
    2316             : 
    2317             :             // It will contains the i-th element of the list.
    2318          45 :             for (nIRecord = 0; nIRecord < nRealNumRecords; nIRecord++)
    2319             :             {
    2320          21 :                 if (MMResizeMiraMonFieldValue(
    2321          24 :                         &(hMMFeature.pRecords[nIRecord].pField),
    2322          24 :                         &hMMFeature.pRecords[nIRecord].nMaxField,
    2323          24 :                         hMMFeature.pRecords[nIRecord].nNumField,
    2324             :                         (nIRecord == 0)
    2325             :                             ? MM_INC_NUMBER_OF_FIELDS
    2326           3 :                             : hMMFeature.pRecords[nIRecord - 1].nMaxField,
    2327          48 :                         hMMFeature.pRecords[nIRecord].nNumField))
    2328           0 :                     return OGRERR_NOT_ENOUGH_MEMORY;
    2329             : 
    2330          24 :                 if (nIRecord > 0)
    2331             :                 {
    2332             :                     // The number of fields of this new record is the same as the
    2333             :                     // last one
    2334           3 :                     hMMFeature.pRecords[nIRecord].nNumField =
    2335           3 :                         hMMFeature.pRecords[nIRecord - 1].nNumField;
    2336             :                 }
    2337             : 
    2338          24 :                 if (eFSType == OFSTBoolean)
    2339             :                 {
    2340           2 :                     if (panValues[nIRecord] == 1)
    2341             :                     {
    2342           4 :                         if (MM_SecureCopyStringFieldValue(
    2343           2 :                                 &hMMFeature.pRecords[nIRecord]
    2344           2 :                                      .pField[iField]
    2345             :                                      .pDinValue,
    2346             :                                 "T",
    2347           2 :                                 &hMMFeature.pRecords[nIRecord]
    2348           2 :                                      .pField[iField]
    2349           2 :                                      .nNumDinValue))
    2350           0 :                             return OGRERR_NOT_ENOUGH_MEMORY;
    2351             :                     }
    2352             :                     else
    2353             :                     {
    2354           0 :                         if (MM_SecureCopyStringFieldValue(
    2355           0 :                                 &hMMFeature.pRecords[nIRecord]
    2356           0 :                                      .pField[iField]
    2357             :                                      .pDinValue,
    2358             :                                 "F",
    2359           0 :                                 &hMMFeature.pRecords[nIRecord]
    2360           0 :                                      .pField[iField]
    2361           0 :                                      .nNumDinValue))
    2362           0 :                             return OGRERR_NOT_ENOUGH_MEMORY;
    2363             :                     }
    2364             :                 }
    2365             :                 else
    2366             :                 {
    2367          66 :                     if (MM_SecureCopyStringFieldValue(
    2368          22 :                             &hMMFeature.pRecords[nIRecord]
    2369          22 :                                  .pField[iField]
    2370             :                                  .pDinValue,
    2371          22 :                             CPLSPrintf("%d", panValues[nIRecord]),
    2372          22 :                             &hMMFeature.pRecords[nIRecord]
    2373          22 :                                  .pField[iField]
    2374          22 :                                  .nNumDinValue))
    2375           0 :                         return OGRERR_NOT_ENOUGH_MEMORY;
    2376             :                 }
    2377             : 
    2378          24 :                 hMMFeature.pRecords[nIRecord].pField[iField].bIsValid = 1;
    2379             :             }
    2380             :         }
    2381        1300 :         else if (eFType == OFTInteger64List)
    2382             :         {
    2383          23 :             int nCount = 0;
    2384             :             const GIntBig *panValues =
    2385          23 :                 poFeature->GetFieldAsInteger64List(iField, &nCount);
    2386             : 
    2387          23 :             nRealNumRecords = nNumRecords = nCount;
    2388          23 :             if (nNumRecords == 0)
    2389           0 :                 nNumRecords++;
    2390          23 :             hMMFeature.nNumMRecords =
    2391          23 :                 max_function(hMMFeature.nNumMRecords, nNumRecords);
    2392          23 :             if (MMResizeMiraMonRecord(
    2393             :                     &hMMFeature.pRecords, &hMMFeature.nMaxMRecords,
    2394             :                     hMMFeature.nNumMRecords, MM_INC_NUMBER_OF_RECORDS,
    2395          23 :                     hMMFeature.nNumMRecords))
    2396           0 :                 return OGRERR_NOT_ENOUGH_MEMORY;
    2397             : 
    2398             :             // It will contains the i-th element of the list.
    2399          51 :             for (nIRecord = 0; nIRecord < nRealNumRecords; nIRecord++)
    2400             :             {
    2401          23 :                 if (MMResizeMiraMonFieldValue(
    2402          28 :                         &(hMMFeature.pRecords[nIRecord].pField),
    2403          28 :                         &hMMFeature.pRecords[nIRecord].nMaxField,
    2404          28 :                         hMMFeature.pRecords[nIRecord].nNumField,
    2405             :                         (nIRecord == 0)
    2406             :                             ? MM_INC_NUMBER_OF_FIELDS
    2407           5 :                             : hMMFeature.pRecords[nIRecord - 1].nMaxField,
    2408          56 :                         hMMFeature.pRecords[nIRecord].nNumField))
    2409           0 :                     return OGRERR_NOT_ENOUGH_MEMORY;
    2410             : 
    2411          28 :                 if (nIRecord > 0)
    2412             :                 {
    2413             :                     // The number of fields of this new record is the same as the
    2414             :                     // last one
    2415           5 :                     hMMFeature.pRecords[nIRecord].nNumField =
    2416           5 :                         hMMFeature.pRecords[nIRecord - 1].nNumField;
    2417             :                 }
    2418             : 
    2419          28 :                 hMMFeature.pRecords[nIRecord].pField[iField].iValue =
    2420          28 :                     panValues[nIRecord];
    2421             : 
    2422          84 :                 if (MM_SecureCopyStringFieldValue(
    2423          28 :                         &hMMFeature.pRecords[nIRecord].pField[iField].pDinValue,
    2424             :                         CPLSPrintf("%" CPL_FRMT_GB_WITHOUT_PREFIX "d",
    2425          28 :                                    panValues[nIRecord]),
    2426          28 :                         &hMMFeature.pRecords[nIRecord]
    2427          28 :                              .pField[iField]
    2428          28 :                              .nNumDinValue))
    2429           0 :                     return OGRERR_NOT_ENOUGH_MEMORY;
    2430          28 :                 hMMFeature.pRecords[nIRecord].pField[iField].bIsValid = 1;
    2431             :             }
    2432             :         }
    2433        1277 :         else if (eFType == OFTRealList)
    2434             :         {
    2435          24 :             int nCount = 0;
    2436             :             const double *padfRLValues =
    2437          24 :                 poFeature->GetFieldAsDoubleList(iField, &nCount);
    2438             :             //char format[23];
    2439             : 
    2440          24 :             nRealNumRecords = nNumRecords = nCount;
    2441          24 :             if (nNumRecords == 0)
    2442           0 :                 nNumRecords++;
    2443          24 :             hMMFeature.nNumMRecords =
    2444          24 :                 max_function(hMMFeature.nNumMRecords, nNumRecords);
    2445          24 :             if (MMResizeMiraMonRecord(
    2446             :                     &hMMFeature.pRecords, &hMMFeature.nMaxMRecords,
    2447             :                     hMMFeature.nNumMRecords, MM_INC_NUMBER_OF_RECORDS,
    2448          24 :                     hMMFeature.nNumMRecords))
    2449           0 :                 return OGRERR_NOT_ENOUGH_MEMORY;
    2450             : 
    2451             :             // It will contains the i-th element of the list.
    2452          76 :             for (nIRecord = 0; nIRecord < nRealNumRecords; nIRecord++)
    2453             :             {
    2454          24 :                 if (MMResizeMiraMonFieldValue(
    2455          52 :                         &(hMMFeature.pRecords[nIRecord].pField),
    2456          52 :                         &hMMFeature.pRecords[nIRecord].nMaxField,
    2457          52 :                         hMMFeature.pRecords[nIRecord].nNumField,
    2458             :                         (nIRecord == 0)
    2459             :                             ? MM_INC_NUMBER_OF_FIELDS
    2460          28 :                             : hMMFeature.pRecords[nIRecord - 1].nMaxField,
    2461         104 :                         hMMFeature.pRecords[nIRecord].nNumField))
    2462           0 :                     return OGRERR_NOT_ENOUGH_MEMORY;
    2463             : 
    2464          52 :                 if (nIRecord > 0)
    2465             :                 {
    2466             :                     // The number of fields of this new record is the same as the
    2467             :                     // last one
    2468          28 :                     hMMFeature.pRecords[nIRecord].nNumField =
    2469          28 :                         hMMFeature.pRecords[nIRecord - 1].nNumField;
    2470             :                 }
    2471             : 
    2472             :                 char szChain[MAX_SIZE_OF_FIELD_NUMBER_WITH_MINUS];
    2473          52 :                 MM_SprintfDoubleSignifFigures(
    2474             :                     szChain, sizeof(szChain),
    2475          52 :                     phMiraMonLayer->pLayerDB->pFields[iField].nNumberOfDecimals,
    2476          52 :                     padfRLValues[nIRecord]);
    2477             : 
    2478         104 :                 if (MM_SecureCopyStringFieldValue(
    2479          52 :                         &hMMFeature.pRecords[nIRecord].pField[iField].pDinValue,
    2480             :                         szChain,
    2481          52 :                         &hMMFeature.pRecords[nIRecord]
    2482          52 :                              .pField[iField]
    2483          52 :                              .nNumDinValue))
    2484           0 :                     return OGRERR_NOT_ENOUGH_MEMORY;
    2485          52 :                 hMMFeature.pRecords[nIRecord].pField[iField].bIsValid = 1;
    2486             :             }
    2487             :         }
    2488        1253 :         else if (eFType == OFTString)
    2489             :         {
    2490         281 :             hMMFeature.nNumMRecords = max_function(hMMFeature.nNumMRecords, 1);
    2491         281 :             hMMFeature.pRecords[0].nNumField = nNumFields;
    2492         562 :             if (MMResizeMiraMonFieldValue(&(hMMFeature.pRecords[0].pField),
    2493         281 :                                           &hMMFeature.pRecords[0].nMaxField,
    2494         281 :                                           hMMFeature.pRecords[0].nNumField,
    2495             :                                           MM_INC_NUMBER_OF_FIELDS,
    2496         281 :                                           hMMFeature.pRecords[0].nNumField))
    2497           0 :                 return OGRERR_NOT_ENOUGH_MEMORY;
    2498             : 
    2499         281 :             if (MMIsEmptyString(pszRawValue))
    2500          54 :                 hMMFeature.pRecords[0].pField[iField].bIsValid = 0;
    2501             :             {
    2502         281 :                 if (phMiraMonLayer->nCharSet != MM_JOC_CARAC_UTF8_DBF)
    2503             :                 {
    2504             :                     // MiraMon encoding is ISO 8859-1 (Latin1) -> Recode from UTF-8
    2505             :                     char *pszString =
    2506         279 :                         CPLRecode(pszRawValue, CPL_ENC_UTF8, CPL_ENC_ISO8859_1);
    2507         558 :                     if (MM_SecureCopyStringFieldValue(
    2508         279 :                             &hMMFeature.pRecords[0].pField[iField].pDinValue,
    2509             :                             pszString,
    2510         279 :                             &hMMFeature.pRecords[0]
    2511         279 :                                  .pField[iField]
    2512         279 :                                  .nNumDinValue))
    2513             :                     {
    2514           0 :                         CPLFree(pszString);
    2515           0 :                         return OGRERR_NOT_ENOUGH_MEMORY;
    2516             :                     }
    2517         279 :                     CPLFree(pszString);
    2518             :                 }
    2519             :                 else
    2520             :                 {
    2521           4 :                     if (MM_SecureCopyStringFieldValue(
    2522           2 :                             &hMMFeature.pRecords[0].pField[iField].pDinValue,
    2523             :                             pszRawValue,
    2524           2 :                             &hMMFeature.pRecords[0]
    2525           2 :                                  .pField[iField]
    2526           2 :                                  .nNumDinValue))
    2527             :                     {
    2528           0 :                         return OGRERR_NOT_ENOUGH_MEMORY;
    2529             :                     }
    2530             :                 }
    2531             :             }
    2532         281 :             hMMFeature.pRecords[0].pField[iField].bIsValid = 1;
    2533             :         }
    2534         972 :         else if (eFType == OFTDate)
    2535             :         {
    2536             :             char szDate[15];
    2537             : 
    2538         123 :             hMMFeature.nNumMRecords = max_function(hMMFeature.nNumMRecords, 1);
    2539         123 :             hMMFeature.pRecords[0].nNumField = nNumFields;
    2540         246 :             if (MMResizeMiraMonFieldValue(&(hMMFeature.pRecords[0].pField),
    2541         123 :                                           &hMMFeature.pRecords[0].nMaxField,
    2542         123 :                                           hMMFeature.pRecords[0].nNumField,
    2543             :                                           MM_INC_NUMBER_OF_FIELDS,
    2544         123 :                                           hMMFeature.pRecords[0].nNumField))
    2545           0 :                 return OGRERR_NOT_ENOUGH_MEMORY;
    2546             : 
    2547         123 :             if (MMIsEmptyString(pszRawValue))
    2548          17 :                 hMMFeature.pRecords[0].pField[iField].bIsValid = 0;
    2549             :             else
    2550             :             {
    2551         106 :                 const OGRField *poField = poFeature->GetRawFieldRef(iField);
    2552         106 :                 if (poField->Date.Year >= 0)
    2553         106 :                     snprintf(szDate, sizeof(szDate), "%04d%02d%02d",
    2554         106 :                              poField->Date.Year, poField->Date.Month,
    2555         106 :                              poField->Date.Day);
    2556             :                 else
    2557           0 :                     snprintf(szDate, sizeof(szDate), "%04d%02d%02d", 0, 0, 0);
    2558             : 
    2559         212 :                 if (MM_SecureCopyStringFieldValue(
    2560         106 :                         &hMMFeature.pRecords[0].pField[iField].pDinValue,
    2561             :                         szDate,
    2562         106 :                         &hMMFeature.pRecords[0].pField[iField].nNumDinValue))
    2563           0 :                     return OGRERR_NOT_ENOUGH_MEMORY;
    2564         106 :                 hMMFeature.pRecords[0].pField[iField].bIsValid = 1;
    2565             :             }
    2566             :         }
    2567         849 :         else if (eFType == OFTTime || eFType == OFTDateTime)
    2568             :         {
    2569          73 :             hMMFeature.nNumMRecords = max_function(hMMFeature.nNumMRecords, 1);
    2570          73 :             hMMFeature.pRecords[0].nNumField = nNumFields;
    2571         146 :             if (MMResizeMiraMonFieldValue(&(hMMFeature.pRecords[0].pField),
    2572          73 :                                           &hMMFeature.pRecords[0].nMaxField,
    2573          73 :                                           hMMFeature.pRecords[0].nNumField,
    2574             :                                           MM_INC_NUMBER_OF_FIELDS,
    2575          73 :                                           hMMFeature.pRecords[0].nNumField))
    2576           0 :                 return OGRERR_NOT_ENOUGH_MEMORY;
    2577             : 
    2578          73 :             if (MMIsEmptyString(pszRawValue))
    2579          16 :                 hMMFeature.pRecords[0].pField[iField].bIsValid = 0;
    2580             :             else
    2581             :             {
    2582             :                 // MiraMon encoding is ISO 8859-1 (Latin1) -> Recode from UTF-8
    2583         114 :                 if (MM_SecureCopyStringFieldValue(
    2584          57 :                         &hMMFeature.pRecords[0].pField[iField].pDinValue,
    2585             :                         pszRawValue,
    2586          57 :                         &hMMFeature.pRecords[0].pField[iField].nNumDinValue))
    2587           0 :                     return OGRERR_NOT_ENOUGH_MEMORY;
    2588             : 
    2589          57 :                 hMMFeature.pRecords[0].pField[iField].bIsValid = 1;
    2590             :             }
    2591             :         }
    2592         776 :         else if (eFType == OFTInteger)
    2593             :         {
    2594         401 :             hMMFeature.nNumMRecords = max_function(hMMFeature.nNumMRecords, 1);
    2595         401 :             hMMFeature.pRecords[0].nNumField = nNumFields;
    2596         802 :             if (MMResizeMiraMonFieldValue(&(hMMFeature.pRecords[0].pField),
    2597         401 :                                           &hMMFeature.pRecords[0].nMaxField,
    2598         401 :                                           hMMFeature.pRecords[0].nNumField,
    2599             :                                           MM_INC_NUMBER_OF_FIELDS,
    2600         401 :                                           hMMFeature.pRecords[0].nNumField))
    2601           0 :                 return OGRERR_NOT_ENOUGH_MEMORY;
    2602             : 
    2603         401 :             if (MMIsEmptyString(pszRawValue))
    2604          16 :                 hMMFeature.pRecords[0].pField[iField].bIsValid = 0;
    2605             :             else
    2606             :             {
    2607         385 :                 if (eFSType == OFSTBoolean)
    2608             :                 {
    2609          98 :                     if (!strcmp(pszRawValue, "1"))
    2610             :                     {
    2611          84 :                         if (MM_SecureCopyStringFieldValue(
    2612          42 :                                 &hMMFeature.pRecords[0]
    2613          42 :                                      .pField[iField]
    2614             :                                      .pDinValue,
    2615             :                                 "T",
    2616          42 :                                 &hMMFeature.pRecords[0]
    2617          42 :                                      .pField[iField]
    2618          42 :                                      .nNumDinValue))
    2619           0 :                             return OGRERR_NOT_ENOUGH_MEMORY;
    2620             :                     }
    2621             :                     else
    2622             :                     {
    2623         112 :                         if (MM_SecureCopyStringFieldValue(
    2624          56 :                                 &hMMFeature.pRecords[0]
    2625          56 :                                      .pField[iField]
    2626             :                                      .pDinValue,
    2627             :                                 "F",
    2628          56 :                                 &hMMFeature.pRecords[0]
    2629          56 :                                      .pField[iField]
    2630          56 :                                      .nNumDinValue))
    2631           0 :                             return OGRERR_NOT_ENOUGH_MEMORY;
    2632             :                     }
    2633             :                 }
    2634             :                 else
    2635             :                 {
    2636         574 :                     if (MM_SecureCopyStringFieldValue(
    2637         287 :                             &hMMFeature.pRecords[0].pField[iField].pDinValue,
    2638             :                             pszRawValue,
    2639         287 :                             &hMMFeature.pRecords[0]
    2640         287 :                                  .pField[iField]
    2641         287 :                                  .nNumDinValue))
    2642           0 :                         return OGRERR_NOT_ENOUGH_MEMORY;
    2643             :                 }
    2644         385 :                 hMMFeature.pRecords[0].pField[iField].bIsValid = 1;
    2645             :             }
    2646             :         }
    2647         375 :         else if (eFType == OFTInteger64)
    2648             :         {
    2649         178 :             hMMFeature.nNumMRecords = max_function(hMMFeature.nNumMRecords, 1);
    2650         178 :             hMMFeature.pRecords[0].nNumField = nNumFields;
    2651         356 :             if (MMResizeMiraMonFieldValue(&(hMMFeature.pRecords[0].pField),
    2652         178 :                                           &hMMFeature.pRecords[0].nMaxField,
    2653         178 :                                           hMMFeature.pRecords[0].nNumField,
    2654             :                                           MM_INC_NUMBER_OF_FIELDS,
    2655         178 :                                           hMMFeature.pRecords[0].nNumField))
    2656           0 :                 return OGRERR_NOT_ENOUGH_MEMORY;
    2657             : 
    2658         178 :             if (MMIsEmptyString(pszRawValue))
    2659           0 :                 hMMFeature.pRecords[0].pField[iField].bIsValid = 0;
    2660             :             else
    2661             :             {
    2662         356 :                 hMMFeature.pRecords[0].pField[iField].iValue =
    2663         178 :                     poFeature->GetFieldAsInteger64(iField);
    2664             : 
    2665         356 :                 if (MM_SecureCopyStringFieldValue(
    2666         178 :                         &hMMFeature.pRecords[0].pField[iField].pDinValue,
    2667             :                         pszRawValue,
    2668         178 :                         &hMMFeature.pRecords[0].pField[iField].nNumDinValue))
    2669           0 :                     return OGRERR_NOT_ENOUGH_MEMORY;
    2670         178 :                 hMMFeature.pRecords[0].pField[iField].bIsValid = 1;
    2671             :             }
    2672             :         }
    2673         197 :         else if (eFType == OFTReal)
    2674             :         {
    2675         197 :             hMMFeature.nNumMRecords = max_function(hMMFeature.nNumMRecords, 1);
    2676         197 :             hMMFeature.pRecords[0].nNumField = nNumFields;
    2677         394 :             if (MMResizeMiraMonFieldValue(&(hMMFeature.pRecords[0].pField),
    2678         197 :                                           &hMMFeature.pRecords[0].nMaxField,
    2679         197 :                                           hMMFeature.pRecords[0].nNumField,
    2680             :                                           MM_INC_NUMBER_OF_FIELDS,
    2681         197 :                                           hMMFeature.pRecords[0].nNumField))
    2682           0 :                 return OGRERR_NOT_ENOUGH_MEMORY;
    2683             : 
    2684         197 :             if (MMIsEmptyString(pszRawValue))
    2685          16 :                 hMMFeature.pRecords[0].pField[iField].bIsValid = 0;
    2686             :             else
    2687             :             {
    2688             :                 char szChain[MAX_SIZE_OF_FIELD_NUMBER_WITH_MINUS];
    2689         181 :                 MM_SprintfDoubleSignifFigures(
    2690             :                     szChain, sizeof(szChain),
    2691         181 :                     phMiraMonLayer->pLayerDB->pFields[iField].nNumberOfDecimals,
    2692             :                     poFeature->GetFieldAsDouble(iField));
    2693             : 
    2694         362 :                 if (MM_SecureCopyStringFieldValue(
    2695         181 :                         &hMMFeature.pRecords[0].pField[iField].pDinValue,
    2696             :                         szChain,
    2697         181 :                         &hMMFeature.pRecords[0].pField[iField].nNumDinValue))
    2698           0 :                     return OGRERR_NOT_ENOUGH_MEMORY;
    2699         181 :                 hMMFeature.pRecords[0].pField[iField].bIsValid = 1;
    2700             :             }
    2701             :         }
    2702             :         else
    2703             :         {
    2704           0 :             CPLError(CE_Warning, CPLE_NotSupported,
    2705             :                      "MiraMon: Field type %d not processed by MiraMon\n",
    2706             :                      eFType);
    2707           0 :             hMMFeature.pRecords[0].pField[iField].bIsValid = 0;
    2708             :         }
    2709             :     }
    2710             : 
    2711         207 :     return OGRERR_NONE;
    2712             : }
    2713             : 
    2714             : /****************************************************************************/
    2715             : /*                             GetLayerDefn()                               */
    2716             : /*                                                                          */
    2717             : /****************************************************************************/
    2718        3765 : OGRFeatureDefn *OGRMiraMonLayer::GetLayerDefn()
    2719             : {
    2720        3765 :     return m_poFeatureDefn;
    2721             : }
    2722             : 
    2723             : /****************************************************************************/
    2724             : /*                             GetExtent()                                  */
    2725             : /*                                                                          */
    2726             : /*      Fetch extent of the data currently stored in the dataset.           */
    2727             : /*      The bForce flag has no effect on SHO files since that value         */
    2728             : /*      is always in the header.                                            */
    2729             : /****************************************************************************/
    2730             : 
    2731          33 : OGRErr OGRMiraMonLayer::GetExtent(OGREnvelope *psExtent, int bForce)
    2732             : 
    2733             : {
    2734          33 :     if (phMiraMonLayer)
    2735             :     {
    2736          33 :         if (phMiraMonLayer->bIsDBF)
    2737           0 :             return OGRERR_FAILURE;
    2738             : 
    2739             :         // For polygons we need another polygon apart from the universal one
    2740             :         // to have a valid extension
    2741          33 :         if (phMiraMonLayer->bIsPolygon &&
    2742          13 :             phMiraMonLayer->TopHeader.nElemCount < 1)
    2743           0 :             return OGRERR_FAILURE;
    2744             : 
    2745          33 :         if (phMiraMonLayer->TopHeader.nElemCount < 1)
    2746           4 :             return OGRERR_FAILURE;
    2747             : 
    2748          29 :         psExtent->MinX = phMiraMonLayer->TopHeader.hBB.dfMinX;
    2749          29 :         psExtent->MaxX = phMiraMonLayer->TopHeader.hBB.dfMaxX;
    2750          29 :         psExtent->MinY = phMiraMonLayer->TopHeader.hBB.dfMinY;
    2751          29 :         psExtent->MaxY = phMiraMonLayer->TopHeader.hBB.dfMaxY;
    2752             :     }
    2753             :     else
    2754             :     {
    2755           0 :         if (!bForce)
    2756           0 :             return OGRERR_FAILURE;
    2757             :     }
    2758             : 
    2759          29 :     return OGRERR_NONE;
    2760             : }
    2761             : 
    2762             : /****************************************************************************/
    2763             : /*                           TestCapability()                               */
    2764             : /****************************************************************************/
    2765             : 
    2766         520 : int OGRMiraMonLayer::TestCapability(const char *pszCap)
    2767             : 
    2768             : {
    2769         520 :     if (EQUAL(pszCap, OLCRandomRead))
    2770           0 :         return TRUE;
    2771             : 
    2772         520 :     if (EQUAL(pszCap, OLCSequentialWrite))
    2773          26 :         return m_bUpdate;
    2774             : 
    2775         494 :     if (EQUAL(pszCap, OLCFastFeatureCount))
    2776           0 :         return !m_poFilterGeom && !m_poAttrQuery;
    2777             : 
    2778         494 :     if (EQUAL(pszCap, OLCFastGetExtent))
    2779          13 :         return TRUE;
    2780             : 
    2781         481 :     if (EQUAL(pszCap, OLCCreateField))
    2782          36 :         return m_bUpdate;
    2783             : 
    2784         445 :     if (EQUAL(pszCap, OLCZGeometries))
    2785          30 :         return TRUE;
    2786             : 
    2787         415 :     if (EQUAL(pszCap, OLCStringsAsUTF8))
    2788          98 :         return TRUE;
    2789             : 
    2790         317 :     return FALSE;
    2791             : }
    2792             : 
    2793             : /****************************************************************************/
    2794             : /*                            CreateField()                                 */
    2795             : /****************************************************************************/
    2796             : 
    2797         377 : OGRErr OGRMiraMonLayer::CreateField(const OGRFieldDefn *poField, int bApproxOK)
    2798             : 
    2799             : {
    2800         377 :     if (!m_bUpdate)
    2801             :     {
    2802           0 :         CPLError(CE_Failure, CPLE_NoWriteAccess,
    2803             :                  "Cannot create fields on a read-only dataset.");
    2804           0 :         return OGRERR_FAILURE;
    2805             :     }
    2806             : 
    2807         377 :     if (phMiraMonLayer && phMiraMonLayer->TopHeader.nElemCount > 0)
    2808             :     {
    2809           1 :         CPLError(CE_Failure, CPLE_NoWriteAccess,
    2810             :                  "Cannot create fields to a layer with "
    2811             :                  "already existing features in it.");
    2812           1 :         return OGRERR_FAILURE;
    2813             :     }
    2814             : 
    2815         376 :     switch (poField->GetType())
    2816             :     {
    2817         359 :         case OFTInteger:
    2818             :         case OFTIntegerList:
    2819             :         case OFTInteger64:
    2820             :         case OFTInteger64List:
    2821             :         case OFTReal:
    2822             :         case OFTRealList:
    2823             :         case OFTString:
    2824             :         case OFTStringList:
    2825             :         case OFTDate:
    2826         359 :             m_poFeatureDefn->AddFieldDefn(poField);
    2827         359 :             return OGRERR_NONE;
    2828          17 :         default:
    2829          17 :             if (!bApproxOK)
    2830             :             {
    2831           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    2832             :                          "Field %s is of an unsupported type: %s.",
    2833             :                          poField->GetNameRef(),
    2834             :                          poField->GetFieldTypeName(poField->GetType()));
    2835           0 :                 return OGRERR_FAILURE;
    2836             :             }
    2837             :             else
    2838             :             {
    2839          17 :                 OGRFieldDefn oModDef(poField);
    2840          17 :                 oModDef.SetType(OFTString);
    2841          17 :                 m_poFeatureDefn->AddFieldDefn(poField);
    2842          17 :                 return OGRERR_NONE;
    2843             :             }
    2844             :     }
    2845             : }
    2846             : 
    2847             : /************************************************************************/
    2848             : /*                            AddToFileList()                           */
    2849             : /************************************************************************/
    2850             : 
    2851          10 : void OGRMiraMonLayer::AddToFileList(CPLStringList &oFileList)
    2852             : {
    2853          10 :     if (!phMiraMonLayer)
    2854           0 :         return;
    2855             : 
    2856             :     char szAuxFile[MM_CPL_PATH_BUF_SIZE];
    2857             : 
    2858             :     oFileList.AddStringDirectly(
    2859          10 :         VSIGetCanonicalFilename(phMiraMonLayer->pszSrcLayerName));
    2860             :     char *pszMMExt =
    2861          10 :         CPLStrdup(CPLGetExtension(phMiraMonLayer->pszSrcLayerName));
    2862             : 
    2863          10 :     if (phMiraMonLayer->bIsPoint)
    2864             :     {
    2865             :         // As it's explicit on documentation a point has also two more files:
    2866             : 
    2867             :         // FILE_NAME_WITHOUT_EXTENSION.pnt --> FILE_NAME_WITHOUT_EXTENSION + T.rel
    2868           3 :         CPLStrlcpy(szAuxFile, CPLGetBasename(phMiraMonLayer->pszSrcLayerName),
    2869             :                    MM_CPL_PATH_BUF_SIZE);
    2870           3 :         CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "T.rel" : "T.REL",
    2871             :                    MM_CPL_PATH_BUF_SIZE);
    2872             :         oFileList.AddStringDirectly(VSIGetCanonicalFilename(
    2873           3 :             CPLFormFilename(CPLGetDirname(phMiraMonLayer->pszSrcLayerName),
    2874           3 :                             szAuxFile, nullptr)));
    2875             : 
    2876             :         // FILE_NAME_WITHOUT_EXTENSION.pnt --> FILE_NAME_WITHOUT_EXTENSION + T.dbf
    2877           3 :         CPLStrlcpy(szAuxFile, CPLGetBasename(phMiraMonLayer->pszSrcLayerName),
    2878             :                    MM_CPL_PATH_BUF_SIZE);
    2879           3 :         CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "T.dbf" : "T.DBF",
    2880             :                    MM_CPL_PATH_BUF_SIZE);
    2881             :         oFileList.AddStringDirectly(VSIGetCanonicalFilename(
    2882           3 :             CPLFormFilename(CPLGetDirname(phMiraMonLayer->pszSrcLayerName),
    2883           3 :                             szAuxFile, nullptr)));
    2884             :     }
    2885           7 :     else if (phMiraMonLayer->bIsArc && !phMiraMonLayer->bIsPolygon)
    2886             :     {
    2887             :         // As it's explicit on documentation a point has also five more files:
    2888             : 
    2889             :         // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + A.rel
    2890           3 :         CPLStrlcpy(szAuxFile, CPLGetBasename(phMiraMonLayer->pszSrcLayerName),
    2891             :                    MM_CPL_PATH_BUF_SIZE);
    2892           3 :         CPLStrlcat(szAuxFile, (pszMMExt[0] == 'a') ? "A.rel" : "A.REL",
    2893             :                    MM_CPL_PATH_BUF_SIZE);
    2894             :         oFileList.AddStringDirectly(VSIGetCanonicalFilename(
    2895           3 :             CPLFormFilename(CPLGetDirname(phMiraMonLayer->pszSrcLayerName),
    2896           3 :                             szAuxFile, nullptr)));
    2897             : 
    2898             :         // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + A.dbf
    2899           3 :         CPLStrlcpy(szAuxFile, CPLGetBasename(phMiraMonLayer->pszSrcLayerName),
    2900             :                    MM_CPL_PATH_BUF_SIZE);
    2901           3 :         CPLStrlcat(szAuxFile, (pszMMExt[0] == 'a') ? "A.dbf" : "A.DBF",
    2902             :                    MM_CPL_PATH_BUF_SIZE);
    2903             :         oFileList.AddStringDirectly(VSIGetCanonicalFilename(
    2904           3 :             CPLFormFilename(CPLGetDirname(phMiraMonLayer->pszSrcLayerName),
    2905           3 :                             szAuxFile, nullptr)));
    2906             : 
    2907             :         // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + .nod
    2908           3 :         CPLStrlcpy(szAuxFile, CPLGetBasename(phMiraMonLayer->pszSrcLayerName),
    2909             :                    MM_CPL_PATH_BUF_SIZE);
    2910           3 :         CPLStrlcat(szAuxFile, (pszMMExt[0] == 'a') ? ".nod" : ".NOD",
    2911             :                    MM_CPL_PATH_BUF_SIZE);
    2912             :         oFileList.AddStringDirectly(VSIGetCanonicalFilename(
    2913           3 :             CPLFormFilename(CPLGetDirname(phMiraMonLayer->pszSrcLayerName),
    2914           3 :                             szAuxFile, nullptr)));
    2915             : 
    2916             :         // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + N.rel
    2917           3 :         CPLStrlcpy(szAuxFile, CPLGetBasename(phMiraMonLayer->pszSrcLayerName),
    2918             :                    MM_CPL_PATH_BUF_SIZE);
    2919           3 :         CPLStrlcat(szAuxFile, (pszMMExt[0] == 'a') ? "N.rel" : "N.REL",
    2920             :                    MM_CPL_PATH_BUF_SIZE);
    2921             :         oFileList.AddStringDirectly(VSIGetCanonicalFilename(
    2922           3 :             CPLFormFilename(CPLGetDirname(phMiraMonLayer->pszSrcLayerName),
    2923           3 :                             szAuxFile, nullptr)));
    2924             : 
    2925             :         // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + N.dbf
    2926           3 :         CPLStrlcpy(szAuxFile, CPLGetBasename(phMiraMonLayer->pszSrcLayerName),
    2927             :                    MM_CPL_PATH_BUF_SIZE);
    2928           3 :         CPLStrlcat(szAuxFile, (pszMMExt[0] == 'a') ? "N.dbf" : "N.DBF",
    2929             :                    MM_CPL_PATH_BUF_SIZE);
    2930           3 :         oFileList.AddStringDirectly(VSIGetCanonicalFilename(
    2931           3 :             CPLFormFilename(CPLGetDirname(phMiraMonLayer->pszSrcLayerName),
    2932           3 :                             szAuxFile, nullptr)));
    2933             :     }
    2934           4 :     else if (phMiraMonLayer->bIsPolygon)
    2935             :     {
    2936             :         // As it's explicit on documentation a point has also eight more files:
    2937             :         const char *szCompleteArcFileName;
    2938             :         char szArcFileName[MM_CPL_PATH_BUF_SIZE];
    2939             : 
    2940             :         // FILE_NAME_WITHOUT_EXTENSION.pol --> FILE_NAME_WITHOUT_EXTENSION + P.rel
    2941           4 :         CPLStrlcpy(szAuxFile, CPLGetBasename(phMiraMonLayer->pszSrcLayerName),
    2942             :                    MM_CPL_PATH_BUF_SIZE);
    2943           4 :         CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "P.rel" : "P.REL",
    2944             :                    MM_CPL_PATH_BUF_SIZE);
    2945             :         oFileList.AddStringDirectly(VSIGetCanonicalFilename(
    2946           4 :             CPLFormFilename(CPLGetDirname(phMiraMonLayer->pszSrcLayerName),
    2947           4 :                             szAuxFile, nullptr)));
    2948             : 
    2949             :         // The name of the arc is in THIS metadata file
    2950           4 :         char *pszArcLayerName = MMReturnValueFromSectionINIFile(
    2951           4 :             CPLFormFilename(CPLGetDirname(phMiraMonLayer->pszSrcLayerName),
    2952             :                             szAuxFile, nullptr),
    2953             :             SECTION_OVVW_ASPECTES_TECNICS, KEY_ArcSource);
    2954           4 :         if (!pszArcLayerName)
    2955             :         {
    2956           0 :             CPLFree(pszMMExt);
    2957           0 :             return;  //Some files are missing
    2958             :         }
    2959           4 :         CPLStrlcpy(szArcFileName, pszArcLayerName, MM_CPL_PATH_BUF_SIZE);
    2960             : 
    2961           4 :         MM_RemoveInitial_and_FinalQuotationMarks(szArcFileName);
    2962             : 
    2963             :         // If extension is not specified ".arc" will be used
    2964           4 :         if (MMIsEmptyString(CPLGetExtension(pszArcLayerName)))
    2965           0 :             CPLStrlcat(szArcFileName, (pszMMExt[0] == 'p') ? ".arc" : ".ARC",
    2966             :                        MM_CPL_PATH_BUF_SIZE);
    2967             : 
    2968           4 :         CPLFree(pszArcLayerName);
    2969             : 
    2970             :         szCompleteArcFileName =
    2971           4 :             CPLFormFilename(CPLGetDirname(phMiraMonLayer->pszSrcLayerName),
    2972             :                             szArcFileName, nullptr);
    2973             : 
    2974             :         // The arc that has the coordinates of the polygon
    2975             :         oFileList.AddStringDirectly(
    2976           4 :             VSIGetCanonicalFilename(szCompleteArcFileName));
    2977             : 
    2978             :         // FILE_NAME_WITHOUT_EXTENSION.pol --> FILE_NAME_WITHOUT_EXTENSION + P.dbf
    2979           4 :         CPLStrlcpy(szAuxFile, CPLGetBasename(phMiraMonLayer->pszSrcLayerName),
    2980             :                    MM_CPL_PATH_BUF_SIZE);
    2981           4 :         CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "P.dbf" : "P.DBF",
    2982             :                    MM_CPL_PATH_BUF_SIZE);
    2983             :         oFileList.AddStringDirectly(VSIGetCanonicalFilename(
    2984           4 :             CPLFormFilename(CPLGetDirname(phMiraMonLayer->pszSrcLayerName),
    2985           4 :                             szAuxFile, nullptr)));
    2986             : 
    2987             :         // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + A.rel
    2988           4 :         const char *pszBaseArcName = CPLGetBasename(szCompleteArcFileName);
    2989           4 :         CPLStrlcpy(szAuxFile, pszBaseArcName, MM_CPL_PATH_BUF_SIZE);
    2990           4 :         CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "A.rel" : "A.REL",
    2991             :                    MM_CPL_PATH_BUF_SIZE);
    2992             :         oFileList.AddStringDirectly(VSIGetCanonicalFilename(CPLFormFilename(
    2993           4 :             CPLGetDirname(szCompleteArcFileName), szAuxFile, nullptr)));
    2994             : 
    2995             :         // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + A.dbf
    2996           4 :         CPLStrlcpy(szAuxFile, pszBaseArcName, MM_CPL_PATH_BUF_SIZE);
    2997           4 :         CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "A.dbf" : "A.DBF",
    2998             :                    MM_CPL_PATH_BUF_SIZE);
    2999             :         oFileList.AddStringDirectly(VSIGetCanonicalFilename(CPLFormFilename(
    3000           4 :             CPLGetDirname(szCompleteArcFileName), szAuxFile, nullptr)));
    3001             : 
    3002             :         // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + .nod
    3003           4 :         CPLStrlcpy(szAuxFile, pszBaseArcName, MM_CPL_PATH_BUF_SIZE);
    3004           4 :         CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? ".nod" : ".NOD",
    3005             :                    MM_CPL_PATH_BUF_SIZE);
    3006             :         oFileList.AddStringDirectly(VSIGetCanonicalFilename(CPLFormFilename(
    3007           4 :             CPLGetDirname(szCompleteArcFileName), szAuxFile, nullptr)));
    3008             : 
    3009             :         // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + N.rel
    3010           4 :         CPLStrlcpy(szAuxFile, pszBaseArcName, MM_CPL_PATH_BUF_SIZE);
    3011           4 :         CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "N.rel" : "N.REL",
    3012             :                    MM_CPL_PATH_BUF_SIZE);
    3013             :         oFileList.AddStringDirectly(VSIGetCanonicalFilename(CPLFormFilename(
    3014           4 :             CPLGetDirname(szCompleteArcFileName), szAuxFile, nullptr)));
    3015             : 
    3016             :         // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + N.dbf
    3017           4 :         CPLStrlcpy(szAuxFile, pszBaseArcName, MM_CPL_PATH_BUF_SIZE);
    3018           4 :         CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "N.dbf" : "N.DBF",
    3019             :                    MM_CPL_PATH_BUF_SIZE);
    3020             :         oFileList.AddStringDirectly(VSIGetCanonicalFilename(CPLFormFilename(
    3021           4 :             CPLGetDirname(szCompleteArcFileName), szAuxFile, nullptr)));
    3022             :     }
    3023          10 :     CPLFree(pszMMExt);
    3024             : }

Generated by: LCOV version 1.14