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

Generated by: LCOV version 1.14