LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/miramon - ogrmiramonlayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1369 1597 85.7 %
Date: 2025-07-02 23:05:47 Functions: 21 22 95.5 %

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

Generated by: LCOV version 1.14