LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/miramon - ogrmiramonlayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1402 1635 85.7 %
Date: 2025-09-10 17:48:50 Functions: 22 23 95.7 %

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

Generated by: LCOV version 1.14