LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/miramon - ogrmiramonlayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1324 1536 86.2 %
Date: 2025-01-18 12:42:00 Functions: 21 21 100.0 %

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

Generated by: LCOV version 1.14