LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/miramon - ogrmiramonlayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1333 1561 85.4 %
Date: 2025-03-28 11:40:40 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         201 : OGRMiraMonLayer::OGRMiraMonLayer(GDALDataset *poDS, const char *pszFilename,
      23             :                                  VSILFILE *fp, const OGRSpatialReference *poSRS,
      24             :                                  int bUpdateIn, CSLConstList papszOpenOptions,
      25         201 :                                  struct MiraMonVectMapInfo *MMMap)
      26             :     : m_poDS(poDS), m_poSRS(nullptr), m_poFeatureDefn(nullptr), m_iNextFID(0),
      27             :       phMiraMonLayer(nullptr), hMiraMonLayerPNT(), hMiraMonLayerARC(),
      28             :       hMiraMonLayerPOL(), hMiraMonLayerReadOrNonGeom(), hMMFeature(),
      29         201 :       m_bUpdate(CPL_TO_BOOL(bUpdateIn)),
      30         201 :       m_fp(fp ? fp : VSIFOpenL(pszFilename, (bUpdateIn ? "r+" : "r"))),
      31         201 :       padfValues(nullptr), pnInt64Values(nullptr), bValidFile(false)
      32             : {
      33             : 
      34         201 :     CPLDebugOnly("MiraMon", "Creating/Opening MiraMon layer...");
      35             :     /* -------------------------------------------------------------------- */
      36             :     /*      Create the feature definition                                   */
      37             :     /* -------------------------------------------------------------------- */
      38         201 :     m_poFeatureDefn =
      39         201 :         new OGRFeatureDefn(CPLGetBasenameSafe(pszFilename).c_str());
      40         201 :     SetDescription(m_poFeatureDefn->GetName());
      41         201 :     m_poFeatureDefn->Reference();
      42             : 
      43         201 :     if (m_bUpdate)
      44             :     {
      45             :         /* ---------------------------------------------------------------- */
      46             :         /*      Establish the version to use                                */
      47             :         /* ---------------------------------------------------------------- */
      48          82 :         const char *pszVersion = CSLFetchNameValue(papszOpenOptions, "Version");
      49             :         int nMMVersion;
      50             : 
      51          82 :         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          72 :             nMMVersion = MM_32BITS_VERSION;  // Default
      63             : 
      64             :         /* ---------------------------------------------------------------- */
      65             :         /*      Establish the charset of the .dbf files                     */
      66             :         /* ---------------------------------------------------------------- */
      67             :         const char *pszdbfEncoding =
      68          82 :             CSLFetchNameValue(papszOpenOptions, "DBFEncoding");
      69             :         char nMMRecode;
      70             : 
      71          82 :         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          80 :             nMMRecode = MM_RECODE_ANSI;  // Default
      80             : 
      81             :         /* ----------------------------------------------------------------- */
      82             :         /*   Establish the descriptors language when                         */
      83             :         /*   creating .rel files                                             */
      84             :         /* ----------------------------------------------------------------- */
      85             :         const char *pszLanguage =
      86          82 :             CSLFetchNameValue(papszOpenOptions, "CreationLanguage");
      87             :         char nMMLanguage;
      88             : 
      89          82 :         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          79 :             nMMLanguage = MM_DEF_LANGUAGE;  // Default
     100             : 
     101             :         /* ---------------------------------------------------------------- */
     102             :         /*      Preparing to write the layer                                */
     103             :         /* ---------------------------------------------------------------- */
     104             :         // Init the feature (memory, num,...)
     105          82 :         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          82 :         CPLDebugOnly("MiraMon", "Initializing MiraMon points layer...");
     114          82 :         if (MMInitLayer(&hMiraMonLayerPNT, pszFilename, nMMVersion, nMMRecode,
     115          82 :                         nMMLanguage, nullptr, MM_WRITING_MODE, MMMap))
     116             :         {
     117           0 :             bValidFile = false;
     118           0 :             return;
     119             :         }
     120          82 :         hMiraMonLayerPNT.bIsBeenInit = 0;
     121             : 
     122          82 :         CPLDebugOnly("MiraMon", "Initializing MiraMon arcs layer...");
     123          82 :         if (MMInitLayer(&hMiraMonLayerARC, pszFilename, nMMVersion, nMMRecode,
     124          82 :                         nMMLanguage, nullptr, MM_WRITING_MODE, MMMap))
     125             :         {
     126           0 :             bValidFile = false;
     127           0 :             return;
     128             :         }
     129          82 :         hMiraMonLayerARC.bIsBeenInit = 0;
     130             : 
     131          82 :         CPLDebugOnly("MiraMon", "Initializing MiraMon polygons layer...");
     132          82 :         if (MMInitLayer(&hMiraMonLayerPOL, pszFilename, nMMVersion, nMMRecode,
     133          82 :                         nMMLanguage, nullptr, MM_WRITING_MODE, MMMap))
     134             :         {
     135           0 :             bValidFile = false;
     136           0 :             return;
     137             :         }
     138          82 :         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          82 :         CPLDebugOnly("MiraMon", "Initializing MiraMon only-ext-DBF layer...");
     143          82 :         if (MMInitLayer(&hMiraMonLayerReadOrNonGeom, pszFilename, nMMVersion,
     144             :                         nMMRecode, nMMLanguage, nullptr, MM_WRITING_MODE,
     145          82 :                         nullptr))
     146             :         {
     147           0 :             bValidFile = false;
     148           0 :             return;
     149             :         }
     150          82 :         hMiraMonLayerPOL.bIsBeenInit = 0;
     151             : 
     152             :         // This helps the map to be created
     153             :         //GetLayerDefn()->SetName(hMiraMonLayerPNT.pszSrcLayerName);
     154          82 :         m_poFeatureDefn->SetName(hMiraMonLayerPNT.pszSrcLayerName);
     155             : 
     156             :         // Saving the HRS in the layer structure
     157          82 :         if (poSRS)
     158             :         {
     159          18 :             const char *pszTargetKey = nullptr;
     160          18 :             const char *pszAuthorityName = nullptr;
     161          18 :             const char *pszAuthorityCode = nullptr;
     162             : 
     163             :             // Reading Z units (in case of 3D vector file)
     164          18 :             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          18 :             if (poSRS->IsProjected())
     190          15 :                 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          18 :             if (!poSRS->IsLocal())
     199             :             {
     200          18 :                 pszAuthorityName = poSRS->GetAuthorityName(pszTargetKey);
     201          18 :                 pszAuthorityCode = poSRS->GetAuthorityCode(pszTargetKey);
     202             :             }
     203             : 
     204          18 :             if (pszAuthorityName && pszAuthorityCode &&
     205          18 :                 EQUAL(pszAuthorityName, "EPSG"))
     206             :             {
     207          18 :                 CPLDebugOnly("MiraMon", "Setting EPSG code %s",
     208             :                              pszAuthorityCode);
     209          18 :                 hMiraMonLayerPNT.pSRS = CPLStrdup(pszAuthorityCode);
     210          18 :                 hMiraMonLayerARC.pSRS = CPLStrdup(pszAuthorityCode);
     211          18 :                 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          18 :             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          15 :                 hMiraMonLayerPNT.nSRSType = hMiraMonLayerARC.nSRSType =
     224          15 :                     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         119 :         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         119 :         if (MMInitLayerToRead(&hMiraMonLayerReadOrNonGeom, m_fp, pszFilename))
     247             :         {
     248           8 :             phMiraMonLayer = &hMiraMonLayerReadOrNonGeom;
     249           8 :             bValidFile = false;
     250           8 :             return;
     251             :         }
     252         111 :         phMiraMonLayer = &hMiraMonLayerReadOrNonGeom;
     253             : 
     254         111 :         nMMLayerVersion = MMGetVectorVersion(&phMiraMonLayer->TopHeader);
     255         111 :         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         111 :         if (phMiraMonLayer->bIsPoint)
     263             :         {
     264          39 :             if (phMiraMonLayer->TopHeader.bIs3d)
     265          12 :                 m_poFeatureDefn->SetGeomType(wkbPoint25D);
     266             :             else
     267          27 :                 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         111 :         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         111 :             CSLFetchNameValue(papszOpenOptions, "OpenLanguage");
     325             : 
     326         111 :         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         105 :             phMiraMonLayer->nMMLanguage = MM_DEF_LANGUAGE;  // Default
     337             : 
     338         111 :         if (phMiraMonLayer->nSRS_EPSG != 0)
     339             :         {
     340          60 :             m_poSRS = new OGRSpatialReference();
     341          60 :             m_poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     342          60 :             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          60 :                 m_poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(m_poSRS);
     350             :         }
     351             : 
     352             :         // If there is associated information
     353         111 :         if (phMiraMonLayer->pMMBDXP)
     354             :         {
     355         111 :             if (!phMiraMonLayer->pMMBDXP->pfDataBase)
     356             :             {
     357         111 :                 if ((phMiraMonLayer->pMMBDXP->pfDataBase = fopen_function(
     358         111 :                          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         111 :                 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         222 :                 phMiraMonLayer->pMultRecordIndex = MMCreateExtendedDBFIndex(
     380         111 :                     phMiraMonLayer->pMMBDXP->pfDataBase,
     381         111 :                     phMiraMonLayer->pMMBDXP->nRecords,
     382         111 :                     phMiraMonLayer->pMMBDXP->FirstRecordOffset,
     383         111 :                     phMiraMonLayer->pMMBDXP->BytesPerRecord,
     384         111 :                     phMiraMonLayer->pMMBDXP
     385         111 :                         ->pField[phMiraMonLayer->pMMBDXP->IdGraficField]
     386             :                         .AccumulatedBytes,
     387         111 :                     phMiraMonLayer->pMMBDXP
     388         111 :                         ->pField[phMiraMonLayer->pMMBDXP->IdGraficField]
     389             :                         .BytesPerField,
     390         111 :                     &phMiraMonLayer->isListField, &phMiraMonLayer->nMaxN);
     391             : 
     392             :                 // Creation of maximum number needed for processing
     393             :                 // multiple records
     394         111 :                 if (phMiraMonLayer->pMultRecordIndex)
     395             :                 {
     396         204 :                     padfValues = static_cast<double *>(CPLCalloc(
     397         102 :                         (size_t)phMiraMonLayer->nMaxN, sizeof(*padfValues)));
     398             : 
     399         102 :                     pnInt64Values = static_cast<GInt64 *>(CPLCalloc(
     400         102 :                         (size_t)phMiraMonLayer->nMaxN, sizeof(*pnInt64Values)));
     401             :                 }
     402             : 
     403         111 :                 phMiraMonLayer->iMultiRecord =
     404             :                     MM_MULTIRECORD_NO_MULTIRECORD;  // No option iMultiRecord
     405             :                 const char *szMultiRecord =
     406         111 :                     CSLFetchNameValue(papszOpenOptions, "MultiRecordIndex");
     407         111 :                 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        1161 :             for (MM_EXT_DBF_N_FIELDS nIField = 0;
     419        1161 :                  nIField < phMiraMonLayer->pMMBDXP->nFields; nIField++)
     420             :             {
     421        2100 :                 OGRFieldDefn oField("", OFTString);
     422        1050 :                 oField.SetName(
     423        1050 :                     phMiraMonLayer->pMMBDXP->pField[nIField].FieldName);
     424             : 
     425        1050 :                 oField.SetAlternativeName(
     426        1050 :                     phMiraMonLayer->pMMBDXP->pField[nIField]
     427        1050 :                         .FieldDescription[phMiraMonLayer->nMMLanguage <
     428             :                                                   MM_NUM_IDIOMES_MD_MULTIDIOMA
     429        1050 :                                               ? phMiraMonLayer->nMMLanguage
     430        1050 :                                               : 0]);
     431             : 
     432        1050 :                 if (phMiraMonLayer->pMMBDXP->pField[nIField].FieldType == 'C' ||
     433         880 :                     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         796 :                 else if (phMiraMonLayer->pMMBDXP->pField[nIField].FieldType ==
     468             :                          'N')
     469             :                 {
     470             :                     // It's a list?
     471         756 :                     if (phMiraMonLayer->iMultiRecord ==
     472             :                         MM_MULTIRECORD_NO_MULTIRECORD)
     473             :                     {
     474         624 :                         if (phMiraMonLayer->pMMBDXP->pField[nIField]
     475         624 :                                 .DecimalsIfFloat)
     476         182 :                             oField.SetType(phMiraMonLayer->isListField
     477             :                                                ? OFTRealList
     478             :                                                : OFTReal);
     479             :                         else
     480             :                         {
     481         442 :                             if (phMiraMonLayer->pMMBDXP->pField[nIField]
     482         442 :                                     .BytesPerField < 10)
     483             :                             {
     484         202 :                                 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        1050 :                 oField.SetWidth(
     525        1050 :                     phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField);
     526        1050 :                 oField.SetPrecision(
     527        1050 :                     phMiraMonLayer->pMMBDXP->pField[nIField].DecimalsIfFloat);
     528             : 
     529        1050 :                 m_poFeatureDefn->AddFieldDefn(&oField);
     530             :             }
     531             :         }
     532             :     }
     533             : 
     534         193 :     bValidFile = true;
     535             : }
     536             : 
     537             : /****************************************************************************/
     538             : /*                           ~OGRMiraMonLayer()                             */
     539             : /****************************************************************************/
     540             : 
     541         402 : OGRMiraMonLayer::~OGRMiraMonLayer()
     542             : 
     543             : {
     544         201 :     if (m_nFeaturesRead > 0 && m_poFeatureDefn != nullptr)
     545             :     {
     546          82 :         CPLDebugOnly("MiraMon", "%d features read on layer '%s'.",
     547             :                      static_cast<int>(m_nFeaturesRead),
     548             :                      m_poFeatureDefn->GetName());
     549             :     }
     550             : 
     551         201 :     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         174 :     else if (hMiraMonLayerPOL.ReadOrWrite == MM_WRITING_MODE)
     571             :     {
     572          55 :         CPLDebugOnly("MiraMon", "No MiraMon polygons layer created.");
     573             :     }
     574             : 
     575         201 :     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         171 :     else if (hMiraMonLayerARC.ReadOrWrite == MM_WRITING_MODE)
     596             :     {
     597          52 :         CPLDebugOnly("MiraMon", "No MiraMon arcs layer created.");
     598             :     }
     599             : 
     600         201 :     if (hMiraMonLayerPNT.bIsPoint)
     601             :     {
     602          33 :         CPLDebugOnly("MiraMon", "Closing MiraMon points layer...");
     603          33 :         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          33 :         if (hMiraMonLayerPNT.TopHeader.nElemCount)
     611             :         {
     612          33 :             CPLDebugOnly("MiraMon",
     613             :                          sprintf_UINT64 " point(s) written in file %s.pnt",
     614             :                          hMiraMonLayerPNT.TopHeader.nElemCount,
     615             :                          hMiraMonLayerPNT.pszSrcLayerName);
     616             :         }
     617          33 :         CPLDebugOnly("MiraMon", "MiraMon points layer closed");
     618             :     }
     619         168 :     else if (hMiraMonLayerPNT.ReadOrWrite == MM_WRITING_MODE)
     620             :     {
     621          49 :         CPLDebugOnly("MiraMon", "No MiraMon points layer created.");
     622             :     }
     623             : 
     624         201 :     if (hMiraMonLayerARC.ReadOrWrite == MM_WRITING_MODE)
     625             :     {
     626          82 :         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          65 :         else if (hMiraMonLayerReadOrNonGeom.ReadOrWrite == MM_WRITING_MODE)
     643             :         {
     644          65 :             CPLDebugOnly("MiraMon", "No MiraMon DBF table created.");
     645             :         }
     646             :     }
     647             :     else
     648             :     {
     649         119 :         if (hMiraMonLayerReadOrNonGeom.ReadOrWrite == MM_WRITING_MODE)
     650             :         {
     651           0 :             CPLDebugOnly("MiraMon", "Closing MiraMon layer ...");
     652             :         }
     653         119 :         if (MMCloseLayer(&hMiraMonLayerReadOrNonGeom))
     654             :         {
     655             :             // In case of closing we need to destroy memory
     656           0 :             MMDestroyLayer(&hMiraMonLayerReadOrNonGeom);
     657             :         }
     658         119 :         if (hMiraMonLayerReadOrNonGeom.ReadOrWrite == MM_WRITING_MODE)
     659             :         {
     660           0 :             CPLDebugOnly("MiraMon", "MiraMon layer closed");
     661             :         }
     662             :     }
     663             : 
     664         201 :     if (hMiraMonLayerPOL.ReadOrWrite == MM_WRITING_MODE)
     665             :     {
     666          82 :         MMCPLDebug("MiraMon", "Destroying MiraMon polygons layer memory");
     667             :     }
     668         201 :     MMDestroyLayer(&hMiraMonLayerPOL);
     669         201 :     if (hMiraMonLayerPOL.ReadOrWrite == MM_WRITING_MODE)
     670             :     {
     671          82 :         MMCPLDebug("MiraMon", "MiraMon polygons layer memory destroyed");
     672             :     }
     673             : 
     674         201 :     if (hMiraMonLayerARC.ReadOrWrite == MM_WRITING_MODE)
     675             :     {
     676          82 :         MMCPLDebug("MiraMon", "Destroying MiraMon arcs layer memory");
     677             :     }
     678         201 :     MMDestroyLayer(&hMiraMonLayerARC);
     679         201 :     if (hMiraMonLayerARC.ReadOrWrite == MM_WRITING_MODE)
     680             :     {
     681          82 :         MMCPLDebug("MiraMon", "MiraMon arcs layer memory destroyed");
     682             :     }
     683             : 
     684         201 :     if (hMiraMonLayerPNT.ReadOrWrite == MM_WRITING_MODE)
     685             :     {
     686          82 :         MMCPLDebug("MiraMon", "Destroying MiraMon points layer memory");
     687             :     }
     688         201 :     MMDestroyLayer(&hMiraMonLayerPNT);
     689         201 :     if (hMiraMonLayerPNT.ReadOrWrite == MM_WRITING_MODE)
     690             :     {
     691          82 :         MMCPLDebug("MiraMon", "MiraMon points layer memory destroyed");
     692             :     }
     693             : 
     694         201 :     if (hMiraMonLayerReadOrNonGeom.ReadOrWrite == MM_WRITING_MODE)
     695             :     {
     696          82 :         MMCPLDebug("MiraMon", "Destroying MiraMon DBF table layer memory");
     697             :     }
     698             :     else
     699             :     {
     700         119 :         MMCPLDebug("MiraMon", "Destroying MiraMon layer memory");
     701             :     }
     702             : 
     703         201 :     MMDestroyLayer(&hMiraMonLayerReadOrNonGeom);
     704         201 :     if (hMiraMonLayerReadOrNonGeom.ReadOrWrite == MM_WRITING_MODE)
     705             :     {
     706          82 :         MMCPLDebug("MiraMon", "MiraMon DBF table layer memory destroyed");
     707             :     }
     708             :     else
     709             :     {
     710         119 :         MMCPLDebug("MiraMon", "MiraMon layer memory destroyed");
     711             :     }
     712             : 
     713         201 :     memset(&hMiraMonLayerReadOrNonGeom, 0, sizeof(hMiraMonLayerReadOrNonGeom));
     714         201 :     memset(&hMiraMonLayerPNT, 0, sizeof(hMiraMonLayerPNT));
     715         201 :     memset(&hMiraMonLayerARC, 0, sizeof(hMiraMonLayerARC));
     716         201 :     memset(&hMiraMonLayerPOL, 0, sizeof(hMiraMonLayerPOL));
     717             : 
     718         201 :     MMCPLDebug("MiraMon", "Destroying MiraMon temporary feature memory");
     719         201 :     MMDestroyFeature(&hMMFeature);
     720         201 :     MMCPLDebug("MiraMon", "MiraMon temporary feature memory");
     721         201 :     memset(&hMMFeature, 0, sizeof(hMMFeature));
     722             : 
     723             :     /* -------------------------------------------------------------------- */
     724             :     /*      Clean up.                                                       */
     725             :     /* -------------------------------------------------------------------- */
     726             : 
     727         201 :     if (m_poFeatureDefn)
     728         201 :         m_poFeatureDefn->Release();
     729             : 
     730         201 :     if (m_poSRS)
     731          60 :         m_poSRS->Release();
     732             : 
     733         201 :     if (m_fp != nullptr)
     734         119 :         VSIFCloseL(m_fp);
     735             : 
     736         201 :     if (padfValues != nullptr)
     737         102 :         CPLFree(padfValues);
     738             : 
     739         201 :     if (pnInt64Values != nullptr)
     740         102 :         CPLFree(pnInt64Values);
     741         402 : }
     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       16542 : 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       16542 :     if (!phMiraMonLayer->pMultRecordIndex)
     788           0 :         return;
     789             : 
     790       16542 :     fseek_function(
     791             :         phMiraMonLayer->pMMBDXP->pfDataBase,
     792             :         phMiraMonLayer->pMultRecordIndex[iFID].offset +
     793             :             (MM_FILE_OFFSET)nIRecord * phMiraMonLayer->pMMBDXP->BytesPerRecord +
     794             :             phMiraMonLayer->pMMBDXP->pField[nIField].AccumulatedBytes,
     795             :         SEEK_SET);
     796             : }
     797             : 
     798             : /****************************************************************************/
     799             : /*                         GetNextRawFeature()                              */
     800             : /****************************************************************************/
     801             : 
     802        1923 : OGRFeature *OGRMiraMonLayer::GetNextRawFeature()
     803             : {
     804        1923 :     if (!phMiraMonLayer)
     805           0 :         return nullptr;
     806             : 
     807        1923 :     if (m_iNextFID >= (GUInt64)phMiraMonLayer->TopHeader.nElemCount)
     808         154 :         return nullptr;
     809             : 
     810        1769 :     OGRFeature *poFeature = GetFeature(m_iNextFID);
     811             : 
     812        1769 :     if (!poFeature)
     813         115 :         return nullptr;
     814             : 
     815        1654 :     m_iNextFID++;
     816        1654 :     return poFeature;
     817             : }
     818             : 
     819             : /****************************************************************************/
     820             : /*                         GetFeature()                                     */
     821             : /****************************************************************************/
     822             : 
     823        1834 : OGRFeature *OGRMiraMonLayer::GetFeature(GIntBig nFeatureId)
     824             : 
     825             : {
     826        1834 :     OGRGeometry *poGeom = nullptr;
     827        1834 :     OGRPoint *poPoint = nullptr;
     828        1834 :     OGRLineString *poLS = nullptr;
     829             :     MM_INTERNAL_FID nIElem;
     830        1834 :     MM_EXT_DBF_N_MULTIPLE_RECORDS nIRecord = 0;
     831             : 
     832        1834 :     if (!phMiraMonLayer)
     833           0 :         return nullptr;
     834             : 
     835        1834 :     if (nFeatureId < 0)
     836          10 :         return nullptr;
     837             : 
     838        1824 :     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        1381 :         nIElem = (MM_INTERNAL_FID)nFeatureId;
     847             : 
     848        1824 :     if (nIElem >= phMiraMonLayer->TopHeader.nElemCount)
     849         115 :         return nullptr;
     850             : 
     851             :     /* -------------------------------------------------------------------- */
     852             :     /*      Read nFeatureId feature directly from the file.                 */
     853             :     /* -------------------------------------------------------------------- */
     854        1709 :     switch (phMiraMonLayer->eLT)
     855             :     {
     856        1015 :         case MM_LayerType_Point:
     857             :         case MM_LayerType_Point3d:
     858             :             // Read point
     859        1015 :             poGeom = new OGRPoint();
     860        1015 :             poPoint = poGeom->toPoint();
     861             : 
     862             :             // Get X,Y (z). MiraMon has no multipoints
     863        1015 :             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        1010 :             poPoint->setX(phMiraMonLayer->ReadFeature.pCoord[0].dfX);
     871        1010 :             poPoint->setY(phMiraMonLayer->ReadFeature.pCoord[0].dfY);
     872        1010 :             if (phMiraMonLayer->TopHeader.bIs3d)
     873         874 :                 poPoint->setZ(phMiraMonLayer->ReadFeature.pZCoord[0]);
     874        1689 :             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        1689 :     if (poGeom == nullptr)
    1051           0 :         return nullptr;
    1052             : 
    1053             :     /* -------------------------------------------------------------------- */
    1054             :     /*      Create feature.                                                 */
    1055             :     /* -------------------------------------------------------------------- */
    1056        3378 :     auto poFeature = std::make_unique<OGRFeature>(m_poFeatureDefn);
    1057        1689 :     poGeom->assignSpatialReference(m_poSRS);
    1058        1689 :     poFeature->SetGeometryDirectly(poGeom);
    1059             : 
    1060             :     /* -------------------------------------------------------------------- */
    1061             :     /*      Process field values if its possible.                           */
    1062             :     /* -------------------------------------------------------------------- */
    1063        1689 :     if (phMiraMonLayer->pMMBDXP &&
    1064        1689 :         (MM_EXT_DBF_N_RECORDS)nIElem < phMiraMonLayer->pMMBDXP->nRecords)
    1065             :     {
    1066             :         MM_EXT_DBF_N_FIELDS nIField;
    1067             : 
    1068       17461 :         for (nIField = 0; nIField < phMiraMonLayer->pMMBDXP->nFields; nIField++)
    1069             :         {
    1070       31544 :             if (MMResizeStringToOperateIfNeeded(
    1071             :                     phMiraMonLayer,
    1072       15772 :                     phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField + 1))
    1073             :             {
    1074           0 :                 return nullptr;
    1075             :             }
    1076             : 
    1077       15772 :             if (poFeature->GetDefnRef()->GetFieldDefn(nIField)->GetType() ==
    1078       34062 :                     OFTStringList ||
    1079       15698 :                 (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 :                         fread_function(phMiraMonLayer->szStringToOperate,
    1114             :                                        phMiraMonLayer->pMMBDXP->pField[nIField]
    1115             :                                            .BytesPerField,
    1116             :                                        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 :                         fread_function(phMiraMonLayer->szStringToOperate,
    1177             :                                        phMiraMonLayer->pMMBDXP->pField[nIField]
    1178             :                                            .BytesPerField,
    1179             :                                        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       15656 :             else if (poFeature->GetDefnRef()
    1216       15656 :                          ->GetFieldDefn(nIField)
    1217       15656 :                          ->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 :                 fread_function(
    1257             :                     phMiraMonLayer->szStringToOperate,
    1258             :                     phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField, 1,
    1259             :                     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       13106 :             else if (poFeature->GetDefnRef()
    1285       13106 :                              ->GetFieldDefn(nIField)
    1286       26034 :                              ->GetType() == OFTIntegerList ||
    1287       12928 :                      poFeature->GetDefnRef()
    1288       12928 :                              ->GetFieldDefn(nIField)
    1289       12928 :                              ->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 :                     fread_function(
    1309             :                         phMiraMonLayer->szStringToOperate,
    1310             :                         phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField,
    1311             :                         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       12713 :             else if (poFeature->GetDefnRef()
    1345       12713 :                          ->GetFieldDefn(nIField)
    1346       12713 :                          ->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 :                     fread_function(
    1366             :                         phMiraMonLayer->szStringToOperate,
    1367             :                         phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField,
    1368             :                         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       12520 :             else if (poFeature->GetDefnRef()
    1385       12520 :                              ->GetFieldDefn(nIField)
    1386       17811 :                              ->GetType() == OFTInteger ||
    1387        5291 :                      poFeature->GetDefnRef()
    1388        5291 :                              ->GetFieldDefn(nIField)
    1389       23102 :                              ->GetType() == OFTInteger64 ||
    1390        3330 :                      poFeature->GetDefnRef()
    1391        3330 :                              ->GetFieldDefn(nIField)
    1392        3330 :                              ->GetType() == OFTReal)
    1393             :             {
    1394       11589 :                 if (!phMiraMonLayer->pMultRecordIndex ||
    1395       11589 :                     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       11589 :                 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       11490 :                     GoToFieldOfMultipleRecord(nIElem, 0, nIField);
    1432             : 
    1433       11589 :                 memset(phMiraMonLayer->szStringToOperate, 0,
    1434       11589 :                        phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField);
    1435       11589 :                 fread_function(
    1436             :                     phMiraMonLayer->szStringToOperate,
    1437             :                     phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField, 1,
    1438             :                     phMiraMonLayer->pMMBDXP->pfDataBase);
    1439       11589 :                 phMiraMonLayer
    1440       11589 :                     ->szStringToOperate[phMiraMonLayer->pMMBDXP->pField[nIField]
    1441       11589 :                                             .BytesPerField] = '\0';
    1442       11589 :                 MM_RemoveWhitespacesFromEndOfString(
    1443       11589 :                     phMiraMonLayer->szStringToOperate);
    1444             : 
    1445       11589 :                 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        9628 :                     if (poFeature->GetDefnRef()
    1455        9628 :                                 ->GetFieldDefn(nIField)
    1456       16857 :                                 ->GetType() == OFTInteger &&
    1457        7229 :                         poFeature->GetDefnRef()
    1458        7229 :                                 ->GetFieldDefn(nIField)
    1459        7229 :                                 ->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        8498 :                         poFeature->SetField(
    1471        8498 :                             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 :                 fread_function(
    1517             :                     phMiraMonLayer->szStringToOperate,
    1518             :                     phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField, 1,
    1519             :                     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        1689 :     poFeature->SetFID(nFeatureId);
    1558             : 
    1559        1689 :     m_nFeaturesRead++;
    1560        1689 :     return poFeature.release();
    1561             : }
    1562             : 
    1563             : /****************************************************************************/
    1564             : /*                         GetFeatureCount()                                */
    1565             : /****************************************************************************/
    1566         164 : GIntBig OGRMiraMonLayer::GetFeatureCount(int bForce)
    1567             : {
    1568         164 :     if (!phMiraMonLayer || m_poFilterGeom != nullptr ||
    1569         136 :         m_poAttrQuery != nullptr)
    1570          40 :         return OGRLayer::GetFeatureCount(bForce);
    1571             : 
    1572         124 :     if (phMiraMonLayer->bIsPolygon)
    1573             :     {
    1574         112 :         return std::max((GIntBig)0,
    1575          56 :                         (GIntBig)(phMiraMonLayer->TopHeader.nElemCount - 1));
    1576             :     }
    1577          68 :     return (GIntBig)phMiraMonLayer->TopHeader.nElemCount;
    1578             : }
    1579             : 
    1580             : /****************************************************************************/
    1581             : /*                      MMProcessMultiGeometry()                            */
    1582             : /****************************************************************************/
    1583         173 : OGRErr OGRMiraMonLayer::MMProcessMultiGeometry(OGRGeometryH hGeom,
    1584             :                                                OGRFeature *poFeature)
    1585             : 
    1586             : {
    1587         173 :     OGRErr eErr = OGRERR_NONE;
    1588         173 :     OGRGeometry *poGeom = OGRGeometry::FromHandle(hGeom);
    1589             : 
    1590         173 :     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         173 :     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         339 :     if (wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString ||
    1613         166 :         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         158 :     return MMProcessGeometry(OGRGeometry::ToHandle(poGeom), poFeature, TRUE);
    1629             : }
    1630             : 
    1631             : /****************************************************************************/
    1632             : /*                           MMProcessGeometry()                            */
    1633             : /****************************************************************************/
    1634         210 : OGRErr OGRMiraMonLayer::MMProcessGeometry(OGRGeometryH hGeom,
    1635             :                                           OGRFeature *poFeature,
    1636             :                                           MM_BOOLEAN bcalculateRecord)
    1637             : 
    1638             : {
    1639         210 :     OGRErr eErr = OGRERR_NONE;
    1640         210 :     OGRGeometry *poGeom = nullptr;
    1641         210 :     if (hGeom)
    1642             :     {
    1643         176 :         poGeom = OGRGeometry::FromHandle(hGeom);
    1644             : 
    1645             :         // Translating types from GDAL to MiraMon
    1646         176 :         int eLT = poGeom->getGeometryType();
    1647         176 :         switch (wkbFlatten(eLT))
    1648             :         {
    1649          87 :             case wkbPoint:
    1650          87 :                 phMiraMonLayer = &hMiraMonLayerPNT;
    1651          87 :                 if (OGR_G_Is3D(hGeom))
    1652          43 :                     phMiraMonLayer->eLT = MM_LayerType_Point3d;
    1653             :                 else
    1654          44 :                     phMiraMonLayer->eLT = MM_LayerType_Point;
    1655          87 :                 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         210 :     MMResetFeatureGeometry(&hMMFeature);
    1697         210 :     if (bcalculateRecord)
    1698             :     {
    1699         207 :         MMResetFeatureRecord(&hMMFeature);
    1700         207 :         if (!phMiraMonLayer->pLayerDB)
    1701             :         {
    1702         107 :             eErr = TranslateFieldsToMM();
    1703         107 :             if (eErr != OGRERR_NONE)
    1704           0 :                 return eErr;
    1705             :         }
    1706             :         // Content field translation from GDAL to MiraMon
    1707         207 :         eErr = TranslateFieldsValuesToMM(poFeature);
    1708         207 :         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         210 :     if (poGeom)
    1721             :     {
    1722         176 :         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         210 :     if (eErr == OGRERR_NONE)
    1738         210 :         return MMWriteGeometry();
    1739           0 :     CPLDebugOnly("MiraMon", "Error in MMProcessGeometry()");
    1740           0 :     return eErr;
    1741             : }
    1742             : 
    1743             : /****************************************************************************/
    1744             : /*                           ICreateFeature()                               */
    1745             : /****************************************************************************/
    1746             : 
    1747         195 : OGRErr OGRMiraMonLayer::ICreateFeature(OGRFeature *poFeature)
    1748             : 
    1749             : {
    1750         195 :     OGRErr eErr = OGRERR_NONE;
    1751             : 
    1752         195 :     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         195 :     OGRGeometry *poGeom = poFeature->GetGeometryRef();
    1763             : 
    1764             :     // Processing a feature without geometry.
    1765         195 :     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         161 :     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         155 :     eErr = MMProcessMultiGeometry(OGRGeometry::ToHandle(poGeom), poFeature);
    1792             : 
    1793             :     // Set the FID from 0 index
    1794         155 :     if (phMiraMonLayer)
    1795             :     {
    1796         155 :         if (phMiraMonLayer->bIsPolygon &&
    1797          35 :             phMiraMonLayer->TopHeader.nElemCount > 1)
    1798          35 :             poFeature->SetFID((GIntBig)phMiraMonLayer->TopHeader.nElemCount -
    1799          35 :                               2);
    1800         120 :         else if (phMiraMonLayer->TopHeader.nElemCount > 0)
    1801         120 :             poFeature->SetFID((GIntBig)phMiraMonLayer->TopHeader.nElemCount -
    1802         120 :                               1);
    1803             :     }
    1804         155 :     return eErr;
    1805             : }
    1806             : 
    1807             : /****************************************************************************/
    1808             : /*                          MMDumpVertices()                                */
    1809             : /****************************************************************************/
    1810             : 
    1811         188 : 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         188 :     if (!phMiraMonLayer)
    1818           0 :         return OGRERR_FAILURE;
    1819             : 
    1820         188 :     if (!phMiraMonLayer->bIsBeenInit)
    1821             :     {
    1822          90 :         if (MMInitLayerByType(phMiraMonLayer))
    1823           0 :             return OGRERR_FAILURE;
    1824          90 :         phMiraMonLayer->bIsBeenInit = 1;
    1825             :     }
    1826         376 :     if (MMResize_MM_N_VERTICES_TYPE_Pointer(
    1827             :             &hMMFeature.pNCoordRing, &hMMFeature.nMaxpNCoordRing,
    1828         188 :             (MM_N_VERTICES_TYPE)hMMFeature.nNRings + 1, MM_MEAN_NUMBER_OF_RINGS,
    1829         188 :             0))
    1830           0 :         return OGRERR_FAILURE;
    1831             : 
    1832         188 :     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         188 :     hMMFeature.pNCoordRing[hMMFeature.nIRing] = OGR_G_GetPointCount(hGeom);
    1851             : 
    1852         376 :     if (MMResizeMM_POINT2DPointer(&hMMFeature.pCoord, &hMMFeature.nMaxpCoord,
    1853         188 :                                   hMMFeature.nICoord +
    1854         188 :                                       hMMFeature.pNCoordRing[hMMFeature.nIRing],
    1855         188 :                                   MM_MEAN_NUMBER_OF_NCOORDS, 0))
    1856           0 :         return OGRERR_FAILURE;
    1857         376 :     if (MMResizeDoublePointer(&hMMFeature.pZCoord, &hMMFeature.nMaxpZCoord,
    1858         188 :                               hMMFeature.nICoord +
    1859         188 :                                   hMMFeature.pNCoordRing[hMMFeature.nIRing],
    1860         188 :                               MM_MEAN_NUMBER_OF_NCOORDS, 0))
    1861           0 :         return OGRERR_FAILURE;
    1862             : 
    1863         188 :     hMMFeature.bAllZHaveSameValue = TRUE;
    1864         188 :     for (int iPoint = 0;
    1865         743 :          (MM_N_VERTICES_TYPE)iPoint < hMMFeature.pNCoordRing[hMMFeature.nIRing];
    1866             :          iPoint++)
    1867             :     {
    1868         555 :         hMMFeature.pCoord[hMMFeature.nICoord].dfX = OGR_G_GetX(hGeom, iPoint);
    1869         555 :         hMMFeature.pCoord[hMMFeature.nICoord].dfY = OGR_G_GetY(hGeom, iPoint);
    1870         555 :         if (OGR_G_GetCoordinateDimension(hGeom) == 2)
    1871         387 :             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         555 :         if (iPoint > 0 &&
    1884         367 :             !CPLIsEqual(hMMFeature.pZCoord[hMMFeature.nICoord],
    1885             :                         hMMFeature.pZCoord[hMMFeature.nICoord - 1]))
    1886          40 :             hMMFeature.bAllZHaveSameValue = FALSE;
    1887             : 
    1888         555 :         hMMFeature.nICoord++;
    1889             :     }
    1890         188 :     hMMFeature.nIRing++;
    1891         188 :     hMMFeature.nNRings++;
    1892         188 :     return OGRERR_NONE;
    1893             : }
    1894             : 
    1895             : /****************************************************************************/
    1896             : /*                           MMLoadGeometry()                               */
    1897             : /*                                                                          */
    1898             : /*      Loads on a MiraMon object Feature all coordinates from feature      */
    1899             : /*                                                                          */
    1900             : /****************************************************************************/
    1901         190 : OGRErr OGRMiraMonLayer::MMLoadGeometry(OGRGeometryH hGeom)
    1902             : 
    1903             : {
    1904         190 :     OGRErr eErr = OGRERR_NONE;
    1905             :     MM_BOOLEAN bExternalRing;
    1906             : 
    1907             :     /* -------------------------------------------------------------------- */
    1908             :     /*      This is a geometry with sub-geometries.                         */
    1909             :     /* -------------------------------------------------------------------- */
    1910         190 :     int nGeom = OGR_G_GetGeometryCount(hGeom);
    1911             : 
    1912         190 :     int eLT = wkbFlatten(OGR_G_GetGeometryType(hGeom));
    1913             : 
    1914         190 :     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         190 :     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         190 :     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         145 :     else if (eLT == wkbPoint || eLT == wkbLineString)
    1955             :     {
    1956             :         // Reads all coordinates
    1957         135 :         eErr = MMDumpVertices(hGeom, true, FALSE);
    1958             : 
    1959         135 :         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         190 :     return OGRERR_NONE;
    1971             : }
    1972             : 
    1973             : /****************************************************************************/
    1974             : /*                           WriteGeometry()                                */
    1975             : /*                                                                          */
    1976             : /*                    Writes a geometry to the file.                        */
    1977             : /****************************************************************************/
    1978             : 
    1979         210 : OGRErr OGRMiraMonLayer::MMWriteGeometry()
    1980             : 
    1981             : {
    1982         210 :     OGRErr eErr = MMAddFeature(phMiraMonLayer, &hMMFeature);
    1983             : 
    1984         210 :     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         210 :     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         210 :     return OGRERR_NONE;
    2005             : }
    2006             : 
    2007             : /****************************************************************************/
    2008             : /*                       TranslateFieldsToMM()                              */
    2009             : /*                                                                          */
    2010             : /*      Translase ogr Fields to a structure that MiraMon can understand     */
    2011             : /****************************************************************************/
    2012             : 
    2013         107 : OGRErr OGRMiraMonLayer::TranslateFieldsToMM()
    2014             : 
    2015             : {
    2016         107 :     if (m_poFeatureDefn->GetFieldCount() == 0)
    2017           0 :         return OGRERR_NONE;
    2018             : 
    2019         107 :     CPLDebugOnly("MiraMon", "Translating fields to MiraMon...");
    2020             :     // If the structure is filled we do anything
    2021         107 :     if (phMiraMonLayer->pLayerDB)
    2022           0 :         return OGRERR_NONE;
    2023             : 
    2024         214 :     phMiraMonLayer->pLayerDB = static_cast<struct MiraMonDataBase *>(
    2025         107 :         VSICalloc(sizeof(*phMiraMonLayer->pLayerDB), 1));
    2026         107 :     if (!phMiraMonLayer->pLayerDB)
    2027           0 :         return OGRERR_NOT_ENOUGH_MEMORY;
    2028             : 
    2029         214 :     phMiraMonLayer->pLayerDB->pFields =
    2030             :         static_cast<struct MiraMonDataBaseField *>(
    2031         107 :             VSICalloc(m_poFeatureDefn->GetFieldCount(),
    2032             :                       sizeof(*(phMiraMonLayer->pLayerDB->pFields))));
    2033         107 :     if (!phMiraMonLayer->pLayerDB->pFields)
    2034           0 :         return OGRERR_NOT_ENOUGH_MEMORY;
    2035             : 
    2036         107 :     phMiraMonLayer->pLayerDB->nNFields = 0;
    2037         107 :     if (phMiraMonLayer->pLayerDB->pFields)
    2038             :     {
    2039         107 :         memset(phMiraMonLayer->pLayerDB->pFields, 0,
    2040         107 :                m_poFeatureDefn->GetFieldCount() *
    2041             :                    sizeof(*phMiraMonLayer->pLayerDB->pFields));
    2042         107 :         for (MM_EXT_DBF_N_FIELDS iField = 0;
    2043         682 :              iField < (MM_EXT_DBF_N_FIELDS)m_poFeatureDefn->GetFieldCount();
    2044             :              iField++)
    2045             :         {
    2046         575 :             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         109 :                 case OFTReal:
    2077             :                 case OFTRealList:
    2078         109 :                     phMiraMonLayer->pLayerDB->pFields[iField].eFieldType =
    2079             :                         MM_Numeric;
    2080         109 :                     phMiraMonLayer->pLayerDB->pFields[iField]
    2081         109 :                         .nNumberOfDecimals =
    2082         109 :                         m_poFeatureDefn->GetFieldDefn(iField)->GetPrecision();
    2083         109 :                     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         575 :             if (m_poFeatureDefn->GetFieldDefn(iField)->GetType() == OFTDate)
    2109          68 :                 phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize = 8;
    2110         507 :             else if ((m_poFeatureDefn->GetFieldDefn(iField)->GetType() ==
    2111         398 :                           OFTInteger ||
    2112         398 :                       m_poFeatureDefn->GetFieldDefn(iField)->GetType() ==
    2113        1014 :                           OFTIntegerList) &&
    2114         127 :                      m_poFeatureDefn->GetFieldDefn(iField)->GetSubType() ==
    2115             :                          OFSTBoolean)
    2116             :             {
    2117          33 :                 phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize = 1;
    2118             :             }
    2119             :             else
    2120             :             {
    2121             :                 // As https://gdal.org/api/ogrfeature_cpp.html indicates that
    2122             :                 // precision (number of digits after decimal point) is optional,
    2123             :                 // and a 0 is probably the default value, in that case we prefer
    2124             :                 // to save all the guaranteed significant figures in a double
    2125             :                 // (needed if a field contains, for instance, coordinates in
    2126             :                 // geodetic degrees and a 1:1000 map precision applies).
    2127         474 :                 if (m_poFeatureDefn->GetFieldDefn(iField)->GetPrecision() == 0)
    2128             :                 {
    2129         450 :                     if (m_poFeatureDefn->GetFieldDefn(iField)->GetType() ==
    2130         831 :                             OFTReal ||
    2131         381 :                         m_poFeatureDefn->GetFieldDefn(iField)->GetType() ==
    2132             :                             OFTRealList)
    2133             :                     {
    2134          85 :                         phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize =
    2135             :                             20;
    2136          85 :                         phMiraMonLayer->pLayerDB->pFields[iField]
    2137          85 :                             .nNumberOfDecimals = MAX_RELIABLE_SF_DOUBLE;
    2138             :                     }
    2139             :                     else
    2140             :                     {
    2141         365 :                         phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize =
    2142         365 :                             m_poFeatureDefn->GetFieldDefn(iField)->GetWidth();
    2143         365 :                         if (phMiraMonLayer->pLayerDB->pFields[iField]
    2144         365 :                                 .nFieldSize == 0)
    2145         270 :                             phMiraMonLayer->pLayerDB->pFields[iField]
    2146         270 :                                 .nFieldSize = 3;
    2147             :                     }
    2148             : 
    2149             :                     // Some exceptions for some fields:
    2150         450 :                     if (EQUAL(
    2151             :                             m_poFeatureDefn->GetFieldDefn(iField)->GetNameRef(),
    2152             :                             "fontsize"))
    2153             :                     {
    2154           0 :                         phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize =
    2155             :                             11;
    2156           0 :                         phMiraMonLayer->pLayerDB->pFields[iField]
    2157           0 :                             .nNumberOfDecimals = 3;
    2158             :                     }
    2159         450 :                     else if (EQUAL(m_poFeatureDefn->GetFieldDefn(iField)
    2160             :                                        ->GetNameRef(),
    2161         450 :                                    "leading") ||
    2162         450 :                              EQUAL(m_poFeatureDefn->GetFieldDefn(iField)
    2163             :                                        ->GetNameRef(),
    2164         900 :                                    "chrwidth") ||
    2165         450 :                              EQUAL(m_poFeatureDefn->GetFieldDefn(iField)
    2166             :                                        ->GetNameRef(),
    2167             :                                    "chrspacing"))
    2168             :                     {
    2169           0 :                         phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize =
    2170             :                             8;
    2171           0 :                         phMiraMonLayer->pLayerDB->pFields[iField]
    2172           0 :                             .nNumberOfDecimals = 3;
    2173             :                     }
    2174         450 :                     else if (EQUAL(m_poFeatureDefn->GetFieldDefn(iField)
    2175             :                                        ->GetNameRef(),
    2176             :                                    "orientacio"))
    2177             :                     {
    2178           0 :                         phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize =
    2179             :                             7;
    2180           0 :                         phMiraMonLayer->pLayerDB->pFields[iField]
    2181           0 :                             .nNumberOfDecimals = 2;
    2182             :                     }
    2183             :                 }
    2184             :                 else
    2185             :                 {
    2186             :                     // One more space for the "."
    2187          24 :                     phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize =
    2188          48 :                         (unsigned int)(m_poFeatureDefn->GetFieldDefn(iField)
    2189          24 :                                            ->GetWidth() +
    2190             :                                        1);
    2191             :                 }
    2192             :             }
    2193             : 
    2194             :             // Recode from UTF-8 if necessary
    2195         575 :             if (phMiraMonLayer->nCharSet != MM_JOC_CARAC_UTF8_DBF)
    2196             :             {
    2197         565 :                 char *pszString = CPLRecode(
    2198         565 :                     m_poFeatureDefn->GetFieldDefn(iField)->GetNameRef(),
    2199             :                     CPL_ENC_UTF8, CPL_ENC_ISO8859_1);
    2200         565 :                 CPLStrlcpy(
    2201         565 :                     phMiraMonLayer->pLayerDB->pFields[iField].pszFieldName,
    2202             :                     pszString, MM_MAX_LON_FIELD_NAME_DBF);
    2203         565 :                 CPLFree(pszString);
    2204             :             }
    2205             :             else
    2206             :             {
    2207          10 :                 CPLStrlcpy(
    2208          10 :                     phMiraMonLayer->pLayerDB->pFields[iField].pszFieldName,
    2209          10 :                     m_poFeatureDefn->GetFieldDefn(iField)->GetNameRef(),
    2210             :                     MM_MAX_LON_FIELD_NAME_DBF);
    2211             :             }
    2212             : 
    2213         575 :             if (m_poFeatureDefn->GetFieldDefn(iField)->GetAlternativeNameRef())
    2214             :             {
    2215         575 :                 if (phMiraMonLayer->nCharSet != MM_JOC_CARAC_UTF8_DBF)
    2216             :                 {
    2217             :                     char *pszString =
    2218         565 :                         CPLRecode(m_poFeatureDefn->GetFieldDefn(iField)
    2219             :                                       ->GetAlternativeNameRef(),
    2220             :                                   CPL_ENC_UTF8, CPL_ENC_ISO8859_1);
    2221         565 :                     CPLStrlcpy(phMiraMonLayer->pLayerDB->pFields[iField]
    2222         565 :                                    .pszFieldDescription,
    2223             :                                pszString, MM_MAX_BYTES_FIELD_DESC);
    2224         565 :                     CPLFree(pszString);
    2225             :                 }
    2226             :                 else
    2227             :                 {
    2228          10 :                     CPLStrlcpy(phMiraMonLayer->pLayerDB->pFields[iField]
    2229          10 :                                    .pszFieldDescription,
    2230          10 :                                m_poFeatureDefn->GetFieldDefn(iField)
    2231             :                                    ->GetAlternativeNameRef(),
    2232             :                                MM_MAX_BYTES_FIELD_DESC);
    2233             :                 }
    2234             :             }
    2235         575 :             phMiraMonLayer->pLayerDB->nNFields++;
    2236             :         }
    2237             :     }
    2238             : 
    2239         107 :     CPLDebugOnly("MiraMon", "Fields to MiraMon translated.");
    2240         107 :     return OGRERR_NONE;
    2241             : }
    2242             : 
    2243             : /****************************************************************************/
    2244             : /*                       TranslateFieldsValuesToMM()                        */
    2245             : /*                                                                          */
    2246             : /*      Translate ogr Fields to a structure that MiraMon can understand     */
    2247             : /****************************************************************************/
    2248             : 
    2249         207 : OGRErr OGRMiraMonLayer::TranslateFieldsValuesToMM(OGRFeature *poFeature)
    2250             : 
    2251             : {
    2252         207 :     if (m_poFeatureDefn->GetFieldCount() == 0)
    2253             :     {
    2254             :         // MiraMon have private DataBase records
    2255           0 :         hMMFeature.nNumMRecords = 1;
    2256           0 :         return OGRERR_NONE;
    2257             :     }
    2258             : 
    2259             :     MM_EXT_DBF_N_MULTIPLE_RECORDS nIRecord;
    2260         207 :     MM_EXT_DBF_N_FIELDS nNumFields = m_poFeatureDefn->GetFieldCount();
    2261             :     MM_EXT_DBF_N_MULTIPLE_RECORDS nNumRecords, nRealNumRecords;
    2262         207 :     hMMFeature.nNumMRecords = 0;
    2263             : #define MAX_SIZE_OF_FIELD_NUMBER_WITH_MINUS 22
    2264             : 
    2265        1548 :     for (MM_EXT_DBF_N_FIELDS iField = 0; iField < nNumFields; iField++)
    2266             :     {
    2267        1341 :         OGRFieldType eFType = m_poFeatureDefn->GetFieldDefn(iField)->GetType();
    2268             :         OGRFieldSubType eFSType =
    2269        1341 :             m_poFeatureDefn->GetFieldDefn(iField)->GetSubType();
    2270        1341 :         const char *pszRawValue = poFeature->GetFieldAsString(iField);
    2271             : 
    2272        1341 :         if (eFType == OFTStringList)
    2273             :         {
    2274          20 :             char **papszValues = poFeature->GetFieldAsStringList(iField);
    2275          20 :             nRealNumRecords = nNumRecords = CSLCount(papszValues);
    2276          20 :             if (nNumRecords == 0)
    2277           0 :                 nNumRecords++;
    2278          20 :             hMMFeature.nNumMRecords =
    2279          20 :                 max_function(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        1321 :         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 =
    2353          21 :                 max_function(hMMFeature.nNumMRecords, nNumRecords);
    2354          21 :             if (MMResizeMiraMonRecord(
    2355             :                     &hMMFeature.pRecords, &hMMFeature.nMaxMRecords,
    2356             :                     hMMFeature.nNumMRecords, MM_INC_NUMBER_OF_RECORDS,
    2357          21 :                     hMMFeature.nNumMRecords))
    2358           0 :                 return OGRERR_NOT_ENOUGH_MEMORY;
    2359             : 
    2360             :             // It will contains the i-th element of the list.
    2361          45 :             for (nIRecord = 0; nIRecord < nRealNumRecords; nIRecord++)
    2362             :             {
    2363          21 :                 if (MMResizeMiraMonFieldValue(
    2364          24 :                         &(hMMFeature.pRecords[nIRecord].pField),
    2365          24 :                         &hMMFeature.pRecords[nIRecord].nMaxField,
    2366          24 :                         hMMFeature.pRecords[nIRecord].nNumField,
    2367             :                         (nIRecord == 0)
    2368             :                             ? MM_INC_NUMBER_OF_FIELDS
    2369           3 :                             : hMMFeature.pRecords[nIRecord - 1].nMaxField,
    2370          48 :                         hMMFeature.pRecords[nIRecord].nNumField))
    2371           0 :                     return OGRERR_NOT_ENOUGH_MEMORY;
    2372             : 
    2373          24 :                 if (nIRecord > 0)
    2374             :                 {
    2375             :                     // The number of fields of this new record is the same as the
    2376             :                     // last one
    2377           3 :                     hMMFeature.pRecords[nIRecord].nNumField =
    2378           3 :                         hMMFeature.pRecords[nIRecord - 1].nNumField;
    2379             :                 }
    2380             : 
    2381          24 :                 if (eFSType == OFSTBoolean)
    2382             :                 {
    2383           2 :                     if (panValues[nIRecord] == 1)
    2384             :                     {
    2385           4 :                         if (MM_SecureCopyStringFieldValue(
    2386           2 :                                 &hMMFeature.pRecords[nIRecord]
    2387           2 :                                      .pField[iField]
    2388             :                                      .pDinValue,
    2389             :                                 "T",
    2390           2 :                                 &hMMFeature.pRecords[nIRecord]
    2391           2 :                                      .pField[iField]
    2392           2 :                                      .nNumDinValue))
    2393           0 :                             return OGRERR_NOT_ENOUGH_MEMORY;
    2394             :                     }
    2395             :                     else
    2396             :                     {
    2397           0 :                         if (MM_SecureCopyStringFieldValue(
    2398           0 :                                 &hMMFeature.pRecords[nIRecord]
    2399           0 :                                      .pField[iField]
    2400             :                                      .pDinValue,
    2401             :                                 "F",
    2402           0 :                                 &hMMFeature.pRecords[nIRecord]
    2403           0 :                                      .pField[iField]
    2404           0 :                                      .nNumDinValue))
    2405           0 :                             return OGRERR_NOT_ENOUGH_MEMORY;
    2406             :                     }
    2407             :                 }
    2408             :                 else
    2409             :                 {
    2410          66 :                     if (MM_SecureCopyStringFieldValue(
    2411          22 :                             &hMMFeature.pRecords[nIRecord]
    2412          22 :                                  .pField[iField]
    2413             :                                  .pDinValue,
    2414          22 :                             CPLSPrintf("%d", panValues[nIRecord]),
    2415          22 :                             &hMMFeature.pRecords[nIRecord]
    2416          22 :                                  .pField[iField]
    2417          22 :                                  .nNumDinValue))
    2418           0 :                         return OGRERR_NOT_ENOUGH_MEMORY;
    2419             :                 }
    2420             : 
    2421          24 :                 hMMFeature.pRecords[nIRecord].pField[iField].bIsValid = 1;
    2422             :             }
    2423             :         }
    2424        1300 :         else if (eFType == OFTInteger64List)
    2425             :         {
    2426          23 :             int nCount = 0;
    2427             :             const GIntBig *panValues =
    2428          23 :                 poFeature->GetFieldAsInteger64List(iField, &nCount);
    2429             : 
    2430          23 :             nRealNumRecords = nNumRecords = nCount;
    2431          23 :             if (nNumRecords == 0)
    2432           0 :                 nNumRecords++;
    2433          23 :             hMMFeature.nNumMRecords =
    2434          23 :                 max_function(hMMFeature.nNumMRecords, nNumRecords);
    2435          23 :             if (MMResizeMiraMonRecord(
    2436             :                     &hMMFeature.pRecords, &hMMFeature.nMaxMRecords,
    2437             :                     hMMFeature.nNumMRecords, MM_INC_NUMBER_OF_RECORDS,
    2438          23 :                     hMMFeature.nNumMRecords))
    2439           0 :                 return OGRERR_NOT_ENOUGH_MEMORY;
    2440             : 
    2441             :             // It will contains the i-th element of the list.
    2442          51 :             for (nIRecord = 0; nIRecord < nRealNumRecords; nIRecord++)
    2443             :             {
    2444          23 :                 if (MMResizeMiraMonFieldValue(
    2445          28 :                         &(hMMFeature.pRecords[nIRecord].pField),
    2446          28 :                         &hMMFeature.pRecords[nIRecord].nMaxField,
    2447          28 :                         hMMFeature.pRecords[nIRecord].nNumField,
    2448             :                         (nIRecord == 0)
    2449             :                             ? MM_INC_NUMBER_OF_FIELDS
    2450           5 :                             : hMMFeature.pRecords[nIRecord - 1].nMaxField,
    2451          56 :                         hMMFeature.pRecords[nIRecord].nNumField))
    2452           0 :                     return OGRERR_NOT_ENOUGH_MEMORY;
    2453             : 
    2454          28 :                 if (nIRecord > 0)
    2455             :                 {
    2456             :                     // The number of fields of this new record is the same as the
    2457             :                     // last one
    2458           5 :                     hMMFeature.pRecords[nIRecord].nNumField =
    2459           5 :                         hMMFeature.pRecords[nIRecord - 1].nNumField;
    2460             :                 }
    2461             : 
    2462          28 :                 hMMFeature.pRecords[nIRecord].pField[iField].iValue =
    2463          28 :                     panValues[nIRecord];
    2464             : 
    2465          84 :                 if (MM_SecureCopyStringFieldValue(
    2466          28 :                         &hMMFeature.pRecords[nIRecord].pField[iField].pDinValue,
    2467             :                         CPLSPrintf("%" CPL_FRMT_GB_WITHOUT_PREFIX "d",
    2468          28 :                                    panValues[nIRecord]),
    2469          28 :                         &hMMFeature.pRecords[nIRecord]
    2470          28 :                              .pField[iField]
    2471          28 :                              .nNumDinValue))
    2472           0 :                     return OGRERR_NOT_ENOUGH_MEMORY;
    2473          28 :                 hMMFeature.pRecords[nIRecord].pField[iField].bIsValid = 1;
    2474             :             }
    2475             :         }
    2476        1277 :         else if (eFType == OFTRealList)
    2477             :         {
    2478          24 :             int nCount = 0;
    2479             :             const double *padfRLValues =
    2480          24 :                 poFeature->GetFieldAsDoubleList(iField, &nCount);
    2481             :             //char format[23];
    2482             : 
    2483          24 :             nRealNumRecords = nNumRecords = nCount;
    2484          24 :             if (nNumRecords == 0)
    2485           0 :                 nNumRecords++;
    2486          24 :             hMMFeature.nNumMRecords =
    2487          24 :                 max_function(hMMFeature.nNumMRecords, nNumRecords);
    2488          24 :             if (MMResizeMiraMonRecord(
    2489             :                     &hMMFeature.pRecords, &hMMFeature.nMaxMRecords,
    2490             :                     hMMFeature.nNumMRecords, MM_INC_NUMBER_OF_RECORDS,
    2491          24 :                     hMMFeature.nNumMRecords))
    2492           0 :                 return OGRERR_NOT_ENOUGH_MEMORY;
    2493             : 
    2494             :             // It will contains the i-th element of the list.
    2495          76 :             for (nIRecord = 0; nIRecord < nRealNumRecords; nIRecord++)
    2496             :             {
    2497          24 :                 if (MMResizeMiraMonFieldValue(
    2498          52 :                         &(hMMFeature.pRecords[nIRecord].pField),
    2499          52 :                         &hMMFeature.pRecords[nIRecord].nMaxField,
    2500          52 :                         hMMFeature.pRecords[nIRecord].nNumField,
    2501             :                         (nIRecord == 0)
    2502             :                             ? MM_INC_NUMBER_OF_FIELDS
    2503          28 :                             : hMMFeature.pRecords[nIRecord - 1].nMaxField,
    2504         104 :                         hMMFeature.pRecords[nIRecord].nNumField))
    2505           0 :                     return OGRERR_NOT_ENOUGH_MEMORY;
    2506             : 
    2507          52 :                 if (nIRecord > 0)
    2508             :                 {
    2509             :                     // The number of fields of this new record is the same as the
    2510             :                     // last one
    2511          28 :                     hMMFeature.pRecords[nIRecord].nNumField =
    2512          28 :                         hMMFeature.pRecords[nIRecord - 1].nNumField;
    2513             :                 }
    2514             : 
    2515             :                 char szChain[MAX_SIZE_OF_FIELD_NUMBER_WITH_MINUS];
    2516          52 :                 MM_SprintfDoubleSignifFigures(
    2517             :                     szChain, sizeof(szChain),
    2518          52 :                     phMiraMonLayer->pLayerDB->pFields[iField].nNumberOfDecimals,
    2519          52 :                     padfRLValues[nIRecord]);
    2520             : 
    2521         104 :                 if (MM_SecureCopyStringFieldValue(
    2522          52 :                         &hMMFeature.pRecords[nIRecord].pField[iField].pDinValue,
    2523             :                         szChain,
    2524          52 :                         &hMMFeature.pRecords[nIRecord]
    2525          52 :                              .pField[iField]
    2526          52 :                              .nNumDinValue))
    2527           0 :                     return OGRERR_NOT_ENOUGH_MEMORY;
    2528          52 :                 hMMFeature.pRecords[nIRecord].pField[iField].bIsValid = 1;
    2529             :             }
    2530             :         }
    2531        1253 :         else if (eFType == OFTString)
    2532             :         {
    2533         281 :             hMMFeature.nNumMRecords = max_function(hMMFeature.nNumMRecords, 1);
    2534         281 :             hMMFeature.pRecords[0].nNumField = nNumFields;
    2535         562 :             if (MMResizeMiraMonFieldValue(&(hMMFeature.pRecords[0].pField),
    2536         281 :                                           &hMMFeature.pRecords[0].nMaxField,
    2537         281 :                                           hMMFeature.pRecords[0].nNumField,
    2538             :                                           MM_INC_NUMBER_OF_FIELDS,
    2539         281 :                                           hMMFeature.pRecords[0].nNumField))
    2540           0 :                 return OGRERR_NOT_ENOUGH_MEMORY;
    2541             : 
    2542         281 :             if (MMIsEmptyString(pszRawValue))
    2543          54 :                 hMMFeature.pRecords[0].pField[iField].bIsValid = 0;
    2544             :             {
    2545         281 :                 if (phMiraMonLayer->nCharSet != MM_JOC_CARAC_UTF8_DBF)
    2546             :                 {
    2547             :                     // MiraMon encoding is ISO 8859-1 (Latin1) -> Recode from UTF-8
    2548             :                     char *pszString =
    2549         279 :                         CPLRecode(pszRawValue, CPL_ENC_UTF8, CPL_ENC_ISO8859_1);
    2550         558 :                     if (MM_SecureCopyStringFieldValue(
    2551         279 :                             &hMMFeature.pRecords[0].pField[iField].pDinValue,
    2552             :                             pszString,
    2553         279 :                             &hMMFeature.pRecords[0]
    2554         279 :                                  .pField[iField]
    2555         279 :                                  .nNumDinValue))
    2556             :                     {
    2557           0 :                         CPLFree(pszString);
    2558           0 :                         return OGRERR_NOT_ENOUGH_MEMORY;
    2559             :                     }
    2560         279 :                     CPLFree(pszString);
    2561             :                 }
    2562             :                 else
    2563             :                 {
    2564           4 :                     if (MM_SecureCopyStringFieldValue(
    2565           2 :                             &hMMFeature.pRecords[0].pField[iField].pDinValue,
    2566             :                             pszRawValue,
    2567           2 :                             &hMMFeature.pRecords[0]
    2568           2 :                                  .pField[iField]
    2569           2 :                                  .nNumDinValue))
    2570             :                     {
    2571           0 :                         return OGRERR_NOT_ENOUGH_MEMORY;
    2572             :                     }
    2573             :                 }
    2574             :             }
    2575         281 :             hMMFeature.pRecords[0].pField[iField].bIsValid = 1;
    2576             :         }
    2577         972 :         else if (eFType == OFTDate)
    2578             :         {
    2579             :             char szDate[15];
    2580             : 
    2581         123 :             hMMFeature.nNumMRecords = max_function(hMMFeature.nNumMRecords, 1);
    2582         123 :             hMMFeature.pRecords[0].nNumField = nNumFields;
    2583         246 :             if (MMResizeMiraMonFieldValue(&(hMMFeature.pRecords[0].pField),
    2584         123 :                                           &hMMFeature.pRecords[0].nMaxField,
    2585         123 :                                           hMMFeature.pRecords[0].nNumField,
    2586             :                                           MM_INC_NUMBER_OF_FIELDS,
    2587         123 :                                           hMMFeature.pRecords[0].nNumField))
    2588           0 :                 return OGRERR_NOT_ENOUGH_MEMORY;
    2589             : 
    2590         123 :             if (MMIsEmptyString(pszRawValue))
    2591          17 :                 hMMFeature.pRecords[0].pField[iField].bIsValid = 0;
    2592             :             else
    2593             :             {
    2594         106 :                 const OGRField *poField = poFeature->GetRawFieldRef(iField);
    2595         106 :                 if (poField->Date.Year >= 0)
    2596         106 :                     snprintf(szDate, sizeof(szDate), "%04d%02d%02d",
    2597         106 :                              poField->Date.Year, poField->Date.Month,
    2598         106 :                              poField->Date.Day);
    2599             :                 else
    2600           0 :                     snprintf(szDate, sizeof(szDate), "%04d%02d%02d", 0, 0, 0);
    2601             : 
    2602         212 :                 if (MM_SecureCopyStringFieldValue(
    2603         106 :                         &hMMFeature.pRecords[0].pField[iField].pDinValue,
    2604             :                         szDate,
    2605         106 :                         &hMMFeature.pRecords[0].pField[iField].nNumDinValue))
    2606           0 :                     return OGRERR_NOT_ENOUGH_MEMORY;
    2607         106 :                 hMMFeature.pRecords[0].pField[iField].bIsValid = 1;
    2608             :             }
    2609             :         }
    2610         849 :         else if (eFType == OFTTime || eFType == OFTDateTime)
    2611             :         {
    2612          73 :             hMMFeature.nNumMRecords = max_function(hMMFeature.nNumMRecords, 1);
    2613          73 :             hMMFeature.pRecords[0].nNumField = nNumFields;
    2614         146 :             if (MMResizeMiraMonFieldValue(&(hMMFeature.pRecords[0].pField),
    2615          73 :                                           &hMMFeature.pRecords[0].nMaxField,
    2616          73 :                                           hMMFeature.pRecords[0].nNumField,
    2617             :                                           MM_INC_NUMBER_OF_FIELDS,
    2618          73 :                                           hMMFeature.pRecords[0].nNumField))
    2619           0 :                 return OGRERR_NOT_ENOUGH_MEMORY;
    2620             : 
    2621          73 :             if (MMIsEmptyString(pszRawValue))
    2622          16 :                 hMMFeature.pRecords[0].pField[iField].bIsValid = 0;
    2623             :             else
    2624             :             {
    2625             :                 // MiraMon encoding is ISO 8859-1 (Latin1) -> Recode from UTF-8
    2626         114 :                 if (MM_SecureCopyStringFieldValue(
    2627          57 :                         &hMMFeature.pRecords[0].pField[iField].pDinValue,
    2628             :                         pszRawValue,
    2629          57 :                         &hMMFeature.pRecords[0].pField[iField].nNumDinValue))
    2630           0 :                     return OGRERR_NOT_ENOUGH_MEMORY;
    2631             : 
    2632          57 :                 hMMFeature.pRecords[0].pField[iField].bIsValid = 1;
    2633             :             }
    2634             :         }
    2635         776 :         else if (eFType == OFTInteger)
    2636             :         {
    2637         401 :             hMMFeature.nNumMRecords = max_function(hMMFeature.nNumMRecords, 1);
    2638         401 :             hMMFeature.pRecords[0].nNumField = nNumFields;
    2639         802 :             if (MMResizeMiraMonFieldValue(&(hMMFeature.pRecords[0].pField),
    2640         401 :                                           &hMMFeature.pRecords[0].nMaxField,
    2641         401 :                                           hMMFeature.pRecords[0].nNumField,
    2642             :                                           MM_INC_NUMBER_OF_FIELDS,
    2643         401 :                                           hMMFeature.pRecords[0].nNumField))
    2644           0 :                 return OGRERR_NOT_ENOUGH_MEMORY;
    2645             : 
    2646         401 :             if (MMIsEmptyString(pszRawValue))
    2647          16 :                 hMMFeature.pRecords[0].pField[iField].bIsValid = 0;
    2648             :             else
    2649             :             {
    2650         385 :                 if (eFSType == OFSTBoolean)
    2651             :                 {
    2652          98 :                     if (!strcmp(pszRawValue, "1"))
    2653             :                     {
    2654          84 :                         if (MM_SecureCopyStringFieldValue(
    2655          42 :                                 &hMMFeature.pRecords[0]
    2656          42 :                                      .pField[iField]
    2657             :                                      .pDinValue,
    2658             :                                 "T",
    2659          42 :                                 &hMMFeature.pRecords[0]
    2660          42 :                                      .pField[iField]
    2661          42 :                                      .nNumDinValue))
    2662           0 :                             return OGRERR_NOT_ENOUGH_MEMORY;
    2663             :                     }
    2664             :                     else
    2665             :                     {
    2666         112 :                         if (MM_SecureCopyStringFieldValue(
    2667          56 :                                 &hMMFeature.pRecords[0]
    2668          56 :                                      .pField[iField]
    2669             :                                      .pDinValue,
    2670             :                                 "F",
    2671          56 :                                 &hMMFeature.pRecords[0]
    2672          56 :                                      .pField[iField]
    2673          56 :                                      .nNumDinValue))
    2674           0 :                             return OGRERR_NOT_ENOUGH_MEMORY;
    2675             :                     }
    2676             :                 }
    2677             :                 else
    2678             :                 {
    2679         574 :                     if (MM_SecureCopyStringFieldValue(
    2680         287 :                             &hMMFeature.pRecords[0].pField[iField].pDinValue,
    2681             :                             pszRawValue,
    2682         287 :                             &hMMFeature.pRecords[0]
    2683         287 :                                  .pField[iField]
    2684         287 :                                  .nNumDinValue))
    2685           0 :                         return OGRERR_NOT_ENOUGH_MEMORY;
    2686             :                 }
    2687         385 :                 hMMFeature.pRecords[0].pField[iField].bIsValid = 1;
    2688             :             }
    2689             :         }
    2690         375 :         else if (eFType == OFTInteger64)
    2691             :         {
    2692         178 :             hMMFeature.nNumMRecords = max_function(hMMFeature.nNumMRecords, 1);
    2693         178 :             hMMFeature.pRecords[0].nNumField = nNumFields;
    2694         356 :             if (MMResizeMiraMonFieldValue(&(hMMFeature.pRecords[0].pField),
    2695         178 :                                           &hMMFeature.pRecords[0].nMaxField,
    2696         178 :                                           hMMFeature.pRecords[0].nNumField,
    2697             :                                           MM_INC_NUMBER_OF_FIELDS,
    2698         178 :                                           hMMFeature.pRecords[0].nNumField))
    2699           0 :                 return OGRERR_NOT_ENOUGH_MEMORY;
    2700             : 
    2701         178 :             if (MMIsEmptyString(pszRawValue))
    2702           0 :                 hMMFeature.pRecords[0].pField[iField].bIsValid = 0;
    2703             :             else
    2704             :             {
    2705         356 :                 hMMFeature.pRecords[0].pField[iField].iValue =
    2706         178 :                     poFeature->GetFieldAsInteger64(iField);
    2707             : 
    2708         356 :                 if (MM_SecureCopyStringFieldValue(
    2709         178 :                         &hMMFeature.pRecords[0].pField[iField].pDinValue,
    2710             :                         pszRawValue,
    2711         178 :                         &hMMFeature.pRecords[0].pField[iField].nNumDinValue))
    2712           0 :                     return OGRERR_NOT_ENOUGH_MEMORY;
    2713         178 :                 hMMFeature.pRecords[0].pField[iField].bIsValid = 1;
    2714             :             }
    2715             :         }
    2716         197 :         else if (eFType == OFTReal)
    2717             :         {
    2718         197 :             hMMFeature.nNumMRecords = max_function(hMMFeature.nNumMRecords, 1);
    2719         197 :             hMMFeature.pRecords[0].nNumField = nNumFields;
    2720         394 :             if (MMResizeMiraMonFieldValue(&(hMMFeature.pRecords[0].pField),
    2721         197 :                                           &hMMFeature.pRecords[0].nMaxField,
    2722         197 :                                           hMMFeature.pRecords[0].nNumField,
    2723             :                                           MM_INC_NUMBER_OF_FIELDS,
    2724         197 :                                           hMMFeature.pRecords[0].nNumField))
    2725           0 :                 return OGRERR_NOT_ENOUGH_MEMORY;
    2726             : 
    2727         197 :             if (MMIsEmptyString(pszRawValue))
    2728          16 :                 hMMFeature.pRecords[0].pField[iField].bIsValid = 0;
    2729             :             else
    2730             :             {
    2731             :                 char szChain[MAX_SIZE_OF_FIELD_NUMBER_WITH_MINUS];
    2732         181 :                 MM_SprintfDoubleSignifFigures(
    2733             :                     szChain, sizeof(szChain),
    2734         181 :                     phMiraMonLayer->pLayerDB->pFields[iField].nNumberOfDecimals,
    2735             :                     poFeature->GetFieldAsDouble(iField));
    2736             : 
    2737         362 :                 if (MM_SecureCopyStringFieldValue(
    2738         181 :                         &hMMFeature.pRecords[0].pField[iField].pDinValue,
    2739             :                         szChain,
    2740         181 :                         &hMMFeature.pRecords[0].pField[iField].nNumDinValue))
    2741           0 :                     return OGRERR_NOT_ENOUGH_MEMORY;
    2742         181 :                 hMMFeature.pRecords[0].pField[iField].bIsValid = 1;
    2743             :             }
    2744             :         }
    2745             :         else
    2746             :         {
    2747           0 :             CPLError(CE_Warning, CPLE_NotSupported,
    2748             :                      "MiraMon: Field type %d not processed by MiraMon\n",
    2749             :                      eFType);
    2750           0 :             hMMFeature.pRecords[0].pField[iField].bIsValid = 0;
    2751             :         }
    2752             :     }
    2753             : 
    2754         207 :     return OGRERR_NONE;
    2755             : }
    2756             : 
    2757             : /****************************************************************************/
    2758             : /*                             GetLayerDefn()                               */
    2759             : /*                                                                          */
    2760             : /****************************************************************************/
    2761        3783 : OGRFeatureDefn *OGRMiraMonLayer::GetLayerDefn()
    2762             : {
    2763        3783 :     return m_poFeatureDefn;
    2764             : }
    2765             : 
    2766             : /****************************************************************************/
    2767             : /*                            IGetExtent()                                  */
    2768             : /*                                                                          */
    2769             : /*      Fetch extent of the data currently stored in the dataset.           */
    2770             : /*      The bForce flag has no effect on SHO files since that value         */
    2771             : /*      is always in the header.                                            */
    2772             : /****************************************************************************/
    2773             : 
    2774          33 : OGRErr OGRMiraMonLayer::IGetExtent(int /* iGeomField*/, OGREnvelope *psExtent,
    2775             :                                    bool bForce)
    2776             : 
    2777             : {
    2778          33 :     if (phMiraMonLayer)
    2779             :     {
    2780          33 :         if (phMiraMonLayer->bIsDBF)
    2781           0 :             return OGRERR_FAILURE;
    2782             : 
    2783             :         // For polygons we need another polygon apart from the universal one
    2784             :         // to have a valid extension
    2785          33 :         if (phMiraMonLayer->bIsPolygon &&
    2786          13 :             phMiraMonLayer->TopHeader.nElemCount < 1)
    2787           0 :             return OGRERR_FAILURE;
    2788             : 
    2789          33 :         if (phMiraMonLayer->TopHeader.nElemCount < 1)
    2790           4 :             return OGRERR_FAILURE;
    2791             : 
    2792          29 :         psExtent->MinX = phMiraMonLayer->TopHeader.hBB.dfMinX;
    2793          29 :         psExtent->MaxX = phMiraMonLayer->TopHeader.hBB.dfMaxX;
    2794          29 :         psExtent->MinY = phMiraMonLayer->TopHeader.hBB.dfMinY;
    2795          29 :         psExtent->MaxY = phMiraMonLayer->TopHeader.hBB.dfMaxY;
    2796             :     }
    2797             :     else
    2798             :     {
    2799           0 :         if (!bForce)
    2800           0 :             return OGRERR_FAILURE;
    2801             :     }
    2802             : 
    2803          29 :     return OGRERR_NONE;
    2804             : }
    2805             : 
    2806             : /****************************************************************************/
    2807             : /*                           TestCapability()                               */
    2808             : /****************************************************************************/
    2809             : 
    2810         520 : int OGRMiraMonLayer::TestCapability(const char *pszCap)
    2811             : 
    2812             : {
    2813         520 :     if (EQUAL(pszCap, OLCRandomRead))
    2814           0 :         return TRUE;
    2815             : 
    2816         520 :     if (EQUAL(pszCap, OLCSequentialWrite))
    2817          26 :         return m_bUpdate;
    2818             : 
    2819         494 :     if (EQUAL(pszCap, OLCFastFeatureCount))
    2820           0 :         return !m_poFilterGeom && !m_poAttrQuery;
    2821             : 
    2822         494 :     if (EQUAL(pszCap, OLCFastGetExtent))
    2823          13 :         return TRUE;
    2824             : 
    2825         481 :     if (EQUAL(pszCap, OLCCreateField))
    2826          36 :         return m_bUpdate;
    2827             : 
    2828         445 :     if (EQUAL(pszCap, OLCZGeometries))
    2829          30 :         return TRUE;
    2830             : 
    2831         415 :     if (EQUAL(pszCap, OLCStringsAsUTF8))
    2832          98 :         return TRUE;
    2833             : 
    2834         317 :     return FALSE;
    2835             : }
    2836             : 
    2837             : /****************************************************************************/
    2838             : /*                            CreateField()                                 */
    2839             : /****************************************************************************/
    2840             : 
    2841         377 : OGRErr OGRMiraMonLayer::CreateField(const OGRFieldDefn *poField, int bApproxOK)
    2842             : 
    2843             : {
    2844         377 :     if (!m_bUpdate)
    2845             :     {
    2846           0 :         CPLError(CE_Failure, CPLE_NoWriteAccess,
    2847             :                  "Cannot create fields on a read-only dataset.");
    2848           0 :         return OGRERR_FAILURE;
    2849             :     }
    2850             : 
    2851         377 :     if (phMiraMonLayer && phMiraMonLayer->TopHeader.nElemCount > 0)
    2852             :     {
    2853           1 :         CPLError(CE_Failure, CPLE_NoWriteAccess,
    2854             :                  "Cannot create fields to a layer with "
    2855             :                  "already existing features in it.");
    2856           1 :         return OGRERR_FAILURE;
    2857             :     }
    2858             : 
    2859         376 :     switch (poField->GetType())
    2860             :     {
    2861         359 :         case OFTInteger:
    2862             :         case OFTIntegerList:
    2863             :         case OFTInteger64:
    2864             :         case OFTInteger64List:
    2865             :         case OFTReal:
    2866             :         case OFTRealList:
    2867             :         case OFTString:
    2868             :         case OFTStringList:
    2869             :         case OFTDate:
    2870         359 :             m_poFeatureDefn->AddFieldDefn(poField);
    2871         359 :             return OGRERR_NONE;
    2872          17 :         default:
    2873          17 :             if (!bApproxOK)
    2874             :             {
    2875           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    2876             :                          "Field %s is of an unsupported type: %s.",
    2877             :                          poField->GetNameRef(),
    2878             :                          poField->GetFieldTypeName(poField->GetType()));
    2879           0 :                 return OGRERR_FAILURE;
    2880             :             }
    2881             :             else
    2882             :             {
    2883          17 :                 OGRFieldDefn oModDef(poField);
    2884          17 :                 oModDef.SetType(OFTString);
    2885          17 :                 m_poFeatureDefn->AddFieldDefn(poField);
    2886          17 :                 return OGRERR_NONE;
    2887             :             }
    2888             :     }
    2889             : }
    2890             : 
    2891             : /************************************************************************/
    2892             : /*                            AddToFileList()                           */
    2893             : /************************************************************************/
    2894             : 
    2895          10 : void OGRMiraMonLayer::AddToFileList(CPLStringList &oFileList)
    2896             : {
    2897          10 :     if (!phMiraMonLayer)
    2898           0 :         return;
    2899             : 
    2900             :     char szAuxFile[MM_CPL_PATH_BUF_SIZE];
    2901             : 
    2902             :     oFileList.AddStringDirectly(
    2903          10 :         VSIGetCanonicalFilename(phMiraMonLayer->pszSrcLayerName));
    2904             :     char *pszMMExt =
    2905          10 :         CPLStrdup(CPLGetExtensionSafe(phMiraMonLayer->pszSrcLayerName).c_str());
    2906             : 
    2907          10 :     if (phMiraMonLayer->bIsPoint)
    2908             :     {
    2909             :         // As it's explicit on documentation a point has also two more files:
    2910             : 
    2911             :         // FILE_NAME_WITHOUT_EXTENSION.pnt --> FILE_NAME_WITHOUT_EXTENSION + T.rel
    2912           3 :         CPLStrlcpy(szAuxFile,
    2913           6 :                    CPLGetBasenameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
    2914             :                    MM_CPL_PATH_BUF_SIZE);
    2915           3 :         CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "T.rel" : "T.REL",
    2916             :                    MM_CPL_PATH_BUF_SIZE);
    2917             :         oFileList.AddStringDirectly(VSIGetCanonicalFilename(
    2918           6 :             CPLFormFilenameSafe(
    2919           6 :                 CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
    2920             :                 szAuxFile, nullptr)
    2921           3 :                 .c_str()));
    2922             : 
    2923             :         // FILE_NAME_WITHOUT_EXTENSION.pnt --> FILE_NAME_WITHOUT_EXTENSION + T.dbf
    2924           3 :         CPLStrlcpy(szAuxFile,
    2925           6 :                    CPLGetBasenameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
    2926             :                    MM_CPL_PATH_BUF_SIZE);
    2927           3 :         CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "T.dbf" : "T.DBF",
    2928             :                    MM_CPL_PATH_BUF_SIZE);
    2929             :         oFileList.AddStringDirectly(VSIGetCanonicalFilename(
    2930           6 :             CPLFormFilenameSafe(
    2931           6 :                 CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
    2932             :                 szAuxFile, nullptr)
    2933           3 :                 .c_str()));
    2934             :     }
    2935           7 :     else if (phMiraMonLayer->bIsArc && !phMiraMonLayer->bIsPolygon)
    2936             :     {
    2937             :         // As it's explicit on documentation a point has also five more files:
    2938             : 
    2939             :         // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + A.rel
    2940           3 :         CPLStrlcpy(szAuxFile,
    2941           6 :                    CPLGetBasenameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
    2942             :                    MM_CPL_PATH_BUF_SIZE);
    2943           3 :         CPLStrlcat(szAuxFile, (pszMMExt[0] == 'a') ? "A.rel" : "A.REL",
    2944             :                    MM_CPL_PATH_BUF_SIZE);
    2945             :         oFileList.AddStringDirectly(VSIGetCanonicalFilename(
    2946           6 :             CPLFormFilenameSafe(
    2947           6 :                 CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
    2948             :                 szAuxFile, nullptr)
    2949           3 :                 .c_str()));
    2950             : 
    2951             :         // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + A.dbf
    2952           3 :         CPLStrlcpy(szAuxFile,
    2953           6 :                    CPLGetBasenameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
    2954             :                    MM_CPL_PATH_BUF_SIZE);
    2955           3 :         CPLStrlcat(szAuxFile, (pszMMExt[0] == 'a') ? "A.dbf" : "A.DBF",
    2956             :                    MM_CPL_PATH_BUF_SIZE);
    2957             :         oFileList.AddStringDirectly(VSIGetCanonicalFilename(
    2958           6 :             CPLFormFilenameSafe(
    2959           6 :                 CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
    2960             :                 szAuxFile, nullptr)
    2961           3 :                 .c_str()));
    2962             : 
    2963             :         // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + .nod
    2964           3 :         CPLStrlcpy(szAuxFile,
    2965           6 :                    CPLGetBasenameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
    2966             :                    MM_CPL_PATH_BUF_SIZE);
    2967           3 :         CPLStrlcat(szAuxFile, (pszMMExt[0] == 'a') ? ".nod" : ".NOD",
    2968             :                    MM_CPL_PATH_BUF_SIZE);
    2969             :         oFileList.AddStringDirectly(VSIGetCanonicalFilename(
    2970           6 :             CPLFormFilenameSafe(
    2971           6 :                 CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
    2972             :                 szAuxFile, nullptr)
    2973           3 :                 .c_str()));
    2974             : 
    2975             :         // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + N.rel
    2976           3 :         CPLStrlcpy(szAuxFile,
    2977           6 :                    CPLGetBasenameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
    2978             :                    MM_CPL_PATH_BUF_SIZE);
    2979           3 :         CPLStrlcat(szAuxFile, (pszMMExt[0] == 'a') ? "N.rel" : "N.REL",
    2980             :                    MM_CPL_PATH_BUF_SIZE);
    2981             :         oFileList.AddStringDirectly(VSIGetCanonicalFilename(
    2982           6 :             CPLFormFilenameSafe(
    2983           6 :                 CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
    2984             :                 szAuxFile, nullptr)
    2985           3 :                 .c_str()));
    2986             : 
    2987             :         // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + N.dbf
    2988           3 :         CPLStrlcpy(szAuxFile,
    2989           6 :                    CPLGetBasenameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
    2990             :                    MM_CPL_PATH_BUF_SIZE);
    2991           3 :         CPLStrlcat(szAuxFile, (pszMMExt[0] == 'a') ? "N.dbf" : "N.DBF",
    2992             :                    MM_CPL_PATH_BUF_SIZE);
    2993           3 :         oFileList.AddStringDirectly(VSIGetCanonicalFilename(
    2994           6 :             CPLFormFilenameSafe(
    2995           6 :                 CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
    2996             :                 szAuxFile, nullptr)
    2997           3 :                 .c_str()));
    2998             :     }
    2999           4 :     else if (phMiraMonLayer->bIsPolygon)
    3000             :     {
    3001             :         // As it's explicit on documentation a point has also eight more files:
    3002             :         char szArcFileName[MM_CPL_PATH_BUF_SIZE];
    3003             : 
    3004             :         // FILE_NAME_WITHOUT_EXTENSION.pol --> FILE_NAME_WITHOUT_EXTENSION + P.rel
    3005           4 :         CPLStrlcpy(szAuxFile,
    3006           8 :                    CPLGetBasenameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
    3007             :                    MM_CPL_PATH_BUF_SIZE);
    3008           4 :         CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "P.rel" : "P.REL",
    3009             :                    MM_CPL_PATH_BUF_SIZE);
    3010             :         oFileList.AddStringDirectly(VSIGetCanonicalFilename(
    3011           8 :             CPLFormFilenameSafe(
    3012           8 :                 CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
    3013             :                 szAuxFile, nullptr)
    3014           4 :                 .c_str()));
    3015             : 
    3016             :         // The name of the arc is in THIS metadata file
    3017           4 :         char *pszArcLayerName = MMReturnValueFromSectionINIFile(
    3018           8 :             CPLFormFilenameSafe(
    3019           8 :                 CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
    3020             :                 szAuxFile, nullptr)
    3021             :                 .c_str(),
    3022             :             SECTION_OVVW_ASPECTES_TECNICS, KEY_ArcSource);
    3023           4 :         if (!pszArcLayerName)
    3024             :         {
    3025           0 :             CPLFree(pszMMExt);
    3026           0 :             return;  //Some files are missing
    3027             :         }
    3028           4 :         CPLStrlcpy(szArcFileName, pszArcLayerName, MM_CPL_PATH_BUF_SIZE);
    3029             : 
    3030           4 :         MM_RemoveInitial_and_FinalQuotationMarks(szArcFileName);
    3031             : 
    3032             :         // If extension is not specified ".arc" will be used
    3033           4 :         if (MMIsEmptyString(CPLGetExtensionSafe(pszArcLayerName).c_str()))
    3034           0 :             CPLStrlcat(szArcFileName, (pszMMExt[0] == 'p') ? ".arc" : ".ARC",
    3035             :                        MM_CPL_PATH_BUF_SIZE);
    3036             : 
    3037           4 :         CPLFree(pszArcLayerName);
    3038             : 
    3039             :         const std::string osCompleteArcFileName = CPLFormFilenameSafe(
    3040           4 :             CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
    3041           8 :             szArcFileName, nullptr);
    3042             : 
    3043             :         // The arc that has the coordinates of the polygon
    3044             :         oFileList.AddStringDirectly(
    3045           4 :             VSIGetCanonicalFilename(osCompleteArcFileName.c_str()));
    3046             : 
    3047             :         // FILE_NAME_WITHOUT_EXTENSION.pol --> FILE_NAME_WITHOUT_EXTENSION + P.dbf
    3048           4 :         CPLStrlcpy(szAuxFile,
    3049           8 :                    CPLGetBasenameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
    3050             :                    MM_CPL_PATH_BUF_SIZE);
    3051           4 :         CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "P.dbf" : "P.DBF",
    3052             :                    MM_CPL_PATH_BUF_SIZE);
    3053             :         oFileList.AddStringDirectly(VSIGetCanonicalFilename(
    3054           8 :             CPLFormFilenameSafe(
    3055           8 :                 CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
    3056             :                 szAuxFile, nullptr)
    3057           4 :                 .c_str()));
    3058             : 
    3059             :         // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + A.rel
    3060             :         const std::string osBaseArcName =
    3061           4 :             CPLGetBasenameSafe(osCompleteArcFileName.c_str());
    3062           4 :         CPLStrlcpy(szAuxFile, osBaseArcName.c_str(), MM_CPL_PATH_BUF_SIZE);
    3063           4 :         CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "A.rel" : "A.REL",
    3064             :                    MM_CPL_PATH_BUF_SIZE);
    3065             :         oFileList.AddStringDirectly(VSIGetCanonicalFilename(
    3066           8 :             CPLFormFilenameSafe(
    3067           8 :                 CPLGetDirnameSafe(osCompleteArcFileName.c_str()).c_str(),
    3068             :                 szAuxFile, nullptr)
    3069           4 :                 .c_str()));
    3070             : 
    3071             :         // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + A.dbf
    3072           4 :         CPLStrlcpy(szAuxFile, osBaseArcName.c_str(), MM_CPL_PATH_BUF_SIZE);
    3073           4 :         CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "A.dbf" : "A.DBF",
    3074             :                    MM_CPL_PATH_BUF_SIZE);
    3075             :         oFileList.AddStringDirectly(VSIGetCanonicalFilename(
    3076           8 :             CPLFormFilenameSafe(
    3077           8 :                 CPLGetDirnameSafe(osCompleteArcFileName.c_str()).c_str(),
    3078             :                 szAuxFile, nullptr)
    3079           4 :                 .c_str()));
    3080             : 
    3081             :         // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + .nod
    3082           4 :         CPLStrlcpy(szAuxFile, osBaseArcName.c_str(), MM_CPL_PATH_BUF_SIZE);
    3083           4 :         CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? ".nod" : ".NOD",
    3084             :                    MM_CPL_PATH_BUF_SIZE);
    3085             :         oFileList.AddStringDirectly(VSIGetCanonicalFilename(
    3086           8 :             CPLFormFilenameSafe(
    3087           8 :                 CPLGetDirnameSafe(osCompleteArcFileName.c_str()).c_str(),
    3088             :                 szAuxFile, nullptr)
    3089           4 :                 .c_str()));
    3090             : 
    3091             :         // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + N.rel
    3092           4 :         CPLStrlcpy(szAuxFile, osBaseArcName.c_str(), MM_CPL_PATH_BUF_SIZE);
    3093           4 :         CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "N.rel" : "N.REL",
    3094             :                    MM_CPL_PATH_BUF_SIZE);
    3095             :         oFileList.AddStringDirectly(VSIGetCanonicalFilename(
    3096           8 :             CPLFormFilenameSafe(
    3097           8 :                 CPLGetDirnameSafe(osCompleteArcFileName.c_str()).c_str(),
    3098             :                 szAuxFile, nullptr)
    3099           4 :                 .c_str()));
    3100             : 
    3101             :         // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + N.dbf
    3102           4 :         CPLStrlcpy(szAuxFile, osBaseArcName.c_str(), MM_CPL_PATH_BUF_SIZE);
    3103           4 :         CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "N.dbf" : "N.DBF",
    3104             :                    MM_CPL_PATH_BUF_SIZE);
    3105             :         oFileList.AddStringDirectly(VSIGetCanonicalFilename(
    3106           8 :             CPLFormFilenameSafe(
    3107           8 :                 CPLGetDirnameSafe(osCompleteArcFileName.c_str()).c_str(),
    3108             :                 szAuxFile, nullptr)
    3109           4 :                 .c_str()));
    3110             :     }
    3111          10 :     CPLFree(pszMMExt);
    3112             : }

Generated by: LCOV version 1.14