LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/miramon - mm_wrlayr.c (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 2735 3635 75.2 %
Date: 2026-04-19 18:43:50 Functions: 99 99 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  C API to create a MiraMon layer
       5             :  * Author:   Abel Pau, a.pau@creaf.uab.cat, based on the MiraMon codes,
       6             :  *           mainly written by Xavier Pons, Joan Maso (correctly written
       7             :  *           "Mas0xF3"), Abel Pau, Nuria Julia (N0xFAria Juli0xE0),
       8             :  *           Xavier Calaf, Lluis (Llu0xEDs) Pesquer and Alaitz Zabala, from
       9             :  *           CREAF and Universitat Autonoma (Aut0xF2noma) de Barcelona.
      10             :  *           For a complete list of contributors:
      11             :  *           https://www.miramon.cat/eng/QuiSom.htm
      12             :  ******************************************************************************
      13             :  * Copyright (c) 2024, Xavier Pons
      14             :  *
      15             :  * SPDX-License-Identifier: MIT
      16             :  ****************************************************************************/
      17             : 
      18             : #include "mm_wrlayr.h"
      19             : #include "../../../frmts/miramon_common/mm_gdal_functions.h"
      20             : #include "../../../frmts/miramon_common/mm_gdal_constants.h"
      21             : #include "mm_rdlayr.h"    // For MM_ReadExtendedDBFHeader()
      22             : #include "gdal.h"         // For GDALDatasetH
      23             : #include "ogr_srs_api.h"  // For OSRGetAuthorityCode
      24             : #include "cpl_string.h"   // For CPL_ENC_UTF8
      25             : 
      26             : CPL_C_START  // Necessary for compiling in GDAL project
      27             : 
      28             : /* -------------------------------------------------------------------- */
      29             : /*      COMING FROM mm_gdal_functions.c/h but only used here            */
      30             : /* -------------------------------------------------------------------- */
      31             : // MiraMon feature table descriptors
      32             : #define MM_MAX_IDENTIFIER_SIZE 50
      33             : #define MM_a_WITH_GRAVE 224
      34             : #define MM_a_WITH_ACUTE 225
      35             : #define MM_e_WITH_GRAVE 232
      36             : #define MM_e_WITH_ACUTE 233
      37             : #define MM_i_WITH_ACUTE 237
      38             : #define MM_o_WITH_GRAVE 242
      39             : #define MM_o_WITH_ACUTE 243
      40             : #define MM_u_WITH_ACUTE 250
      41             : 
      42             : #define MM_A_WITH_GRAVE 192
      43             : #define MM_A_WITH_ACUTE 193
      44             : #define MM_E_WITH_GRAVE 200
      45             : #define MM_E_WITH_ACUTE 201
      46             : #define MM_I_WITH_ACUTE 205
      47             : #define MM_O_WITH_GRAVE 210
      48             : #define MM_O_WITH_ACUTE 211
      49             : #define MM_U_WITH_ACUTE 218
      50             : 
      51             :     // In case of diaeresis use "_WITH_DIAERESIS"
      52             :     // In case of cedilla use "_WITH_CEDILLA"
      53             :     // In case of tilde use "_WITH_TILDE"
      54             :     // In case of middle dot use "_MIDDLE_DOT"
      55             : 
      56             :     char szInternalGraphicIdentifierEng[MM_MAX_IDENTIFIER_SIZE];
      57             : char szInternalGraphicIdentifierCat[MM_MAX_IDENTIFIER_SIZE];
      58             : char szInternalGraphicIdentifierSpa[MM_MAX_IDENTIFIER_SIZE];
      59             : 
      60             : char szNumberOfVerticesEng[MM_MAX_IDENTIFIER_SIZE];
      61             : char szNumberOfVerticesCat[MM_MAX_IDENTIFIER_SIZE];
      62             : char szNumberOfVerticesSpa[MM_MAX_IDENTIFIER_SIZE];
      63             : 
      64             : char szLengthOfAarcEng[MM_MAX_IDENTIFIER_SIZE];
      65             : char szLengthOfAarcCat[MM_MAX_IDENTIFIER_SIZE];
      66             : char szLengthOfAarcSpa[MM_MAX_IDENTIFIER_SIZE];
      67             : 
      68             : char szInitialNodeEng[MM_MAX_IDENTIFIER_SIZE];
      69             : char szInitialNodeCat[MM_MAX_IDENTIFIER_SIZE];
      70             : char szInitialNodeSpa[MM_MAX_IDENTIFIER_SIZE];
      71             : 
      72             : char szFinalNodeEng[MM_MAX_IDENTIFIER_SIZE];
      73             : char szFinalNodeCat[MM_MAX_IDENTIFIER_SIZE];
      74             : char szFinalNodeSpa[MM_MAX_IDENTIFIER_SIZE];
      75             : 
      76             : char szNumberOfArcsToNodeEng[MM_MAX_IDENTIFIER_SIZE];
      77             : char szNumberOfArcsToNodeCat[MM_MAX_IDENTIFIER_SIZE];
      78             : char szNumberOfArcsToNodeSpa[MM_MAX_IDENTIFIER_SIZE];
      79             : 
      80             : char szNodeTypeEng[MM_MAX_IDENTIFIER_SIZE];
      81             : char szNodeTypeCat[MM_MAX_IDENTIFIER_SIZE];
      82             : char szNodeTypeSpa[MM_MAX_IDENTIFIER_SIZE];
      83             : 
      84             : char szPerimeterOfThePolygonEng[MM_MAX_IDENTIFIER_SIZE];
      85             : char szPerimeterOfThePolygonCat[MM_MAX_IDENTIFIER_SIZE];
      86             : char szPerimeterOfThePolygonSpa[MM_MAX_IDENTIFIER_SIZE];
      87             : 
      88             : char szAreaOfThePolygonEng[MM_MAX_IDENTIFIER_SIZE];
      89             : char szAreaOfThePolygonCat[MM_MAX_IDENTIFIER_SIZE];
      90             : char szAreaOfThePolygonSpa[MM_MAX_IDENTIFIER_SIZE];
      91             : 
      92             : char szNumberOfArcsEng[MM_MAX_IDENTIFIER_SIZE];
      93             : char szNumberOfArcsCat[MM_MAX_IDENTIFIER_SIZE];
      94             : char szNumberOfArcsSpa[MM_MAX_IDENTIFIER_SIZE];
      95             : 
      96             : char szNumberOfElementaryPolygonsEng[MM_MAX_IDENTIFIER_SIZE];
      97             : char szNumberOfElementaryPolygonsCat[MM_MAX_IDENTIFIER_SIZE];
      98             : char szNumberOfElementaryPolygonsSpa[MM_MAX_IDENTIFIER_SIZE];
      99             : 
     100             : void MM_FillFieldDescriptorByLanguage(void);
     101             : 
     102             : /* -------------------------------------------------------------------- */
     103             : /*      Header Functions                                                */
     104             : /* -------------------------------------------------------------------- */
     105             : int MMAppendBlockToBuffer(struct MM_FLUSH_INFO *FlushInfo);
     106             : void MMInitBoundingBox(struct MMBoundingBox *dfBB);
     107             : int MMWriteAHArcSection(struct MiraMonVectLayerInfo *hMiraMonLayer,
     108             :                         MM_FILE_OFFSET DiskOffset);
     109             : int MMWriteNHNodeSection(struct MiraMonVectLayerInfo *hMiraMonLayer,
     110             :                          MM_FILE_OFFSET DiskOffset);
     111             : int MMWritePHPolygonSection(struct MiraMonVectLayerInfo *hMiraMonLayer,
     112             :                             MM_FILE_OFFSET DiskOffset);
     113             : int MMAppendIntegerDependingOnVersion(
     114             :     struct MiraMonVectLayerInfo *hMiraMonLayer, struct MM_FLUSH_INFO *FlushInfo,
     115             :     uint32_t *nUL32, GUInt64 nUI64);
     116             : int MMMoveFromFileToFile(VSILFILE *pSrcFile, VSILFILE *pDestFile,
     117             :                          MM_FILE_OFFSET *nOffset);
     118             : int MMResizeZSectionDescrPointer(struct MM_ZD **pZDescription, GUInt64 *nMax,
     119             :                                  GUInt64 nNum, GUInt64 nIncr,
     120             :                                  GUInt64 nProposedMax);
     121             : int MMResizeArcHeaderPointer(struct MM_AH **pArcHeader, GUInt64 *nMax,
     122             :                              GUInt64 nNum, GUInt64 nIncr, GUInt64 nProposedMax);
     123             : int MMResizeNodeHeaderPointer(struct MM_NH **pNodeHeader, GUInt64 *nMax,
     124             :                               GUInt64 nNum, GUInt64 nIncr,
     125             :                               GUInt64 nProposedMax);
     126             : int MMResizePolHeaderPointer(struct MM_PH **pPolHeader, GUInt64 *nMax,
     127             :                              GUInt64 nNum, GUInt64 nIncr, GUInt64 nProposedMax);
     128             : void MMUpdateBoundingBoxXY(struct MMBoundingBox *dfBB,
     129             :                            struct MM_POINT_2D *pCoord);
     130             : void MMUpdateBoundingBox(struct MMBoundingBox *dfBBToBeAct,
     131             :                          struct MMBoundingBox *dfBBWithData);
     132             : int MMCheckVersionFor3DOffset(struct MiraMonVectLayerInfo *hMiraMonLayer,
     133             :                               MM_INTERNAL_FID nElemCount,
     134             :                               MM_FILE_OFFSET nOffsetAL,
     135             :                               MM_FILE_OFFSET nZLOffset);
     136             : int MMCheckVersionOffset(struct MiraMonVectLayerInfo *hMiraMonLayer,
     137             :                          MM_FILE_OFFSET OffsetToCheck);
     138             : int MMCheckVersionForFID(struct MiraMonVectLayerInfo *hMiraMonLayer,
     139             :                          MM_INTERNAL_FID FID);
     140             : 
     141             : // Extended DBF functions
     142             : int MMCreateMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
     143             :                  struct MM_POINT_2D *pFirstCoord);
     144             : int MMAddDBFRecordToMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
     145             :                          struct MiraMonFeature *hMMFeature);
     146             : int MMAddPointRecordToMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
     147             :                            struct MiraMonFeature *hMMFeature,
     148             :                            MM_INTERNAL_FID nElemCount);
     149             : int MMAddArcRecordToMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
     150             :                          struct MiraMonFeature *hMMFeature,
     151             :                          MM_INTERNAL_FID nElemCount, struct MM_AH *pArcHeader);
     152             : int MMAddNodeRecordToMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
     153             :                           MM_INTERNAL_FID nElemCount,
     154             :                           struct MM_NH *pNodeHeader);
     155             : int MMAddPolygonRecordToMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
     156             :                              struct MiraMonFeature *hMMFeature,
     157             :                              MM_INTERNAL_FID nElemCount,
     158             :                              MM_N_VERTICES_TYPE nVerticesCount,
     159             :                              struct MM_PH *pPolHeader);
     160             : int MMCloseMMBD_XP(struct MiraMonVectLayerInfo *hMiraMonLayer);
     161             : void MMDestroyMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer);
     162             : 
     163             : /* -------------------------------------------------------------------- */
     164             : /*      Layer Functions: Version                                         */
     165             : /* -------------------------------------------------------------------- */
     166         234 : int MMGetVectorVersion(struct MM_TH *pTopHeader)
     167             : {
     168         234 :     if ((pTopHeader->aLayerVersion[0] == ' ' ||
     169           0 :          pTopHeader->aLayerVersion[0] == '0') &&
     170         234 :         pTopHeader->aLayerVersion[1] == '1' &&
     171         222 :         pTopHeader->aLayerSubVersion == '1')
     172         222 :         return MM_32BITS_VERSION;
     173             : 
     174          12 :     if ((pTopHeader->aLayerVersion[0] == ' ' ||
     175           0 :          pTopHeader->aLayerVersion[0] == '0') &&
     176          12 :         pTopHeader->aLayerVersion[1] == '2' &&
     177          12 :         pTopHeader->aLayerSubVersion == '0')
     178          12 :         return MM_64BITS_VERSION;
     179             : 
     180           0 :     return MM_UNKNOWN_VERSION;
     181             : }
     182             : 
     183         506 : static void MMSet1_1Version(struct MM_TH *pTopHeader)
     184             : {
     185         506 :     pTopHeader->aLayerVersion[0] = ' ';
     186         506 :     pTopHeader->aLayerVersion[1] = '1';
     187         506 :     pTopHeader->aLayerSubVersion = '1';
     188         506 : }
     189             : 
     190          36 : static void MMSet2_0Version(struct MM_TH *pTopHeader)
     191             : {
     192          36 :     pTopHeader->aLayerVersion[0] = ' ';
     193          36 :     pTopHeader->aLayerVersion[1] = '2';
     194          36 :     pTopHeader->aLayerSubVersion = '0';
     195          36 : }
     196             : 
     197             : /* -------------------------------------------------------------------- */
     198             : /*      Layer Functions: Header                                         */
     199             : /* -------------------------------------------------------------------- */
     200         209 : int MMReadHeader(VSILFILE *pF, struct MM_TH *pMMHeader)
     201             : {
     202             :     char dot;
     203             :     uint32_t NCount;
     204         209 :     int32_t reservat4 = 0L;
     205             : 
     206         209 :     pMMHeader->Flag = 0x0;
     207         209 :     if (VSIFSeekL(pF, 0, SEEK_SET))
     208           0 :         return 1;
     209         209 :     if (VSIFReadL(pMMHeader->aFileType, 1, 3, pF) != 3)
     210           0 :         return 1;
     211         209 :     if (VSIFReadL(pMMHeader->aLayerVersion, 1, 2, pF) != 2)
     212           0 :         return 1;
     213         209 :     if (VSIFReadL(&dot, 1, 1, pF) != 1)
     214           0 :         return 1;
     215         209 :     if (VSIFReadL(&pMMHeader->aLayerSubVersion, 1, 1, pF) != 1)
     216           0 :         return 1;
     217         209 :     if (VSIFReadL(&pMMHeader->Flag, sizeof(pMMHeader->Flag), 1, pF) != 1)
     218           0 :         return 1;
     219         209 :     if (VSIFReadL(&pMMHeader->hBB.dfMinX, sizeof(pMMHeader->hBB.dfMinX), 1,
     220             :                   pF) != 1)
     221           0 :         return 1;
     222         209 :     if (VSIFReadL(&pMMHeader->hBB.dfMaxX, sizeof(pMMHeader->hBB.dfMaxX), 1,
     223             :                   pF) != 1)
     224           0 :         return 1;
     225         209 :     if (VSIFReadL(&pMMHeader->hBB.dfMinY, sizeof(pMMHeader->hBB.dfMinY), 1,
     226             :                   pF) != 1)
     227           0 :         return 1;
     228         209 :     if (VSIFReadL(&pMMHeader->hBB.dfMaxY, sizeof(pMMHeader->hBB.dfMaxY), 1,
     229             :                   pF) != 1)
     230           0 :         return 1;
     231         209 :     if (pMMHeader->aLayerVersion[0] == ' ' &&
     232         209 :         pMMHeader->aLayerVersion[1] == '1')
     233             :     {
     234         199 :         if (VSIFReadL(&NCount, sizeof(NCount), 1, pF) != 1)
     235           0 :             return 1;
     236             : 
     237         199 :         pMMHeader->nElemCount = (MM_INTERNAL_FID)NCount;
     238             : 
     239         199 :         if (VSIFReadL(&reservat4, 4, 1, pF) != 1)
     240           0 :             return 1;
     241             :     }
     242          10 :     else if (pMMHeader->aLayerVersion[0] == ' ' &&
     243          10 :              pMMHeader->aLayerVersion[1] == '2')
     244             :     {
     245          10 :         if (VSIFReadL(&(pMMHeader->nElemCount), sizeof(pMMHeader->nElemCount),
     246             :                       1, pF) != 1)
     247           0 :             return 1;
     248             : 
     249          10 :         if (VSIFReadL(&reservat4, 4, 1, pF) != 1)
     250           0 :             return 1;
     251          10 :         if (VSIFReadL(&reservat4, 4, 1, pF) != 1)
     252           0 :             return 1;
     253             :     }
     254             : 
     255         209 :     if (pMMHeader->Flag & MM_LAYER_3D_INFO)
     256          33 :         pMMHeader->bIs3d = 1;
     257             : 
     258         209 :     if (pMMHeader->Flag & MM_LAYER_MULTIPOLYGON)
     259          21 :         pMMHeader->bIsMultipolygon = 1;
     260             : 
     261         209 :     return 0;
     262             : }
     263             : 
     264         177 : static int MMWriteHeader(VSILFILE *pF, struct MM_TH *pMMHeader)
     265             : {
     266         177 :     char dot = '.';
     267             :     uint32_t NCount;
     268         177 :     int32_t reservat4 = 0L;
     269         177 :     MM_INTERNAL_FID nNumber1 = 1, nNumber0 = 0;
     270             : 
     271         177 :     if (!pF)
     272           0 :         return 0;
     273             : 
     274         177 :     pMMHeader->Flag = MM_CREATED_USING_MIRAMON;  // Created from MiraMon
     275         177 :     if (pMMHeader->bIs3d)
     276         100 :         pMMHeader->Flag |= MM_LAYER_3D_INFO;  // 3D
     277             : 
     278         177 :     if (pMMHeader->bIsMultipolygon)
     279           4 :         pMMHeader->Flag |= MM_LAYER_MULTIPOLYGON;  // Multipolygon.
     280             : 
     281         177 :     if (pMMHeader->aFileType[0] == 'P' && pMMHeader->aFileType[1] == 'O' &&
     282          27 :         pMMHeader->aFileType[2] == 'L')
     283          27 :         pMMHeader->Flag |= MM_BIT_5_ON;  // Explicital polygons
     284             : 
     285         177 :     if (VSIFSeekL(pF, 0, SEEK_SET))
     286           0 :         return 1;
     287         177 :     if (VSIFWriteL(pMMHeader->aFileType, 1, 3, pF) != 3)
     288           0 :         return 1;
     289         177 :     if (VSIFWriteL(pMMHeader->aLayerVersion, 1, 2, pF) != 2)
     290           0 :         return 1;
     291         177 :     if (VSIFWriteL(&dot, 1, 1, pF) != 1)
     292           0 :         return 1;
     293         177 :     if (VSIFWriteL(&pMMHeader->aLayerSubVersion, 1, 1, pF) != 1)
     294           0 :         return 1;
     295         177 :     if (VSIFWriteL(&pMMHeader->Flag, sizeof(pMMHeader->Flag), 1, pF) != 1)
     296           0 :         return 1;
     297         177 :     if (VSIFWriteL(&pMMHeader->hBB.dfMinX, sizeof(pMMHeader->hBB.dfMinX), 1,
     298             :                    pF) != 1)
     299           0 :         return 1;
     300         177 :     if (VSIFWriteL(&pMMHeader->hBB.dfMaxX, sizeof(pMMHeader->hBB.dfMaxX), 1,
     301             :                    pF) != 1)
     302           0 :         return 1;
     303         177 :     if (VSIFWriteL(&pMMHeader->hBB.dfMinY, sizeof(pMMHeader->hBB.dfMinY), 1,
     304             :                    pF) != 1)
     305           0 :         return 1;
     306         177 :     if (VSIFWriteL(&pMMHeader->hBB.dfMaxY, sizeof(pMMHeader->hBB.dfMaxY), 1,
     307             :                    pF) != 1)
     308           0 :         return 1;
     309         177 :     if (pMMHeader->aLayerVersion[0] == ' ' &&
     310         177 :         pMMHeader->aLayerVersion[1] == '1')
     311             :     {
     312         165 :         NCount = (uint32_t)pMMHeader->nElemCount;
     313         165 :         if (VSIFWriteL(&NCount, sizeof(NCount), 1, pF) != 1)
     314           0 :             return 1;
     315             : 
     316         165 :         if (VSIFWriteL(&reservat4, 4, 1, pF) != 1)
     317           0 :             return 1;
     318             :     }
     319          12 :     else if (pMMHeader->aLayerVersion[0] == ' ' &&
     320          12 :              pMMHeader->aLayerVersion[1] == '2')
     321             :     {
     322          12 :         if (VSIFWriteL(&(pMMHeader->nElemCount), sizeof(pMMHeader->nElemCount),
     323             :                        1, pF) != 1)
     324           0 :             return 1;
     325             : 
     326             :         // Next part of the file (don't apply for the moment)
     327          12 :         if (VSIFWriteL(&nNumber1, sizeof(nNumber1), 1, pF) != 1)
     328           0 :             return 1;
     329          12 :         if (VSIFWriteL(&nNumber0, sizeof(nNumber0), 1, pF) != 1)
     330           0 :             return 1;
     331             : 
     332             :         // Reserved bytes
     333          12 :         if (VSIFWriteL(&reservat4, 4, 1, pF) != 1)
     334           0 :             return 1;
     335          12 :         if (VSIFWriteL(&reservat4, 4, 1, pF) != 1)
     336           0 :             return 1;
     337             :     }
     338         177 :     return 0;
     339             : }
     340             : 
     341             : /* -------------------------------------------------------------------- */
     342             : /*      Layer Functions: Z section                                      */
     343             : /* -------------------------------------------------------------------- */
     344          25 : int MMReadZSection(struct MiraMonVectLayerInfo *hMiraMonLayer, VSILFILE *pF,
     345             :                    struct MM_ZSection *pZSection)
     346             : {
     347          25 :     int32_t reservat4 = 0L;
     348             : 
     349          25 :     if (!hMiraMonLayer)
     350           0 :         return 1;
     351             : 
     352          25 :     if (hMiraMonLayer->bIsPoint)
     353             :     {
     354          12 :         if (MMCheckSize_t(hMiraMonLayer->TopHeader.nElemCount, MM_SIZE_OF_TL))
     355           0 :             return 1;
     356          12 :         if (hMiraMonLayer->TopHeader.nElemCount * MM_SIZE_OF_TL >
     357          12 :             UINT64_MAX - hMiraMonLayer->nHeaderDiskSize)
     358           0 :             return 1;
     359          12 :         pZSection->ZSectionOffset =
     360          12 :             hMiraMonLayer->nHeaderDiskSize +
     361          12 :             hMiraMonLayer->TopHeader.nElemCount * MM_SIZE_OF_TL;
     362             :     }
     363          13 :     else if (hMiraMonLayer->bIsArc && !(hMiraMonLayer->bIsPolygon) &&
     364           7 :              hMiraMonLayer->TopHeader.nElemCount > 0)
     365           7 :     {
     366           7 :         const struct MM_AH *pArcHeader =
     367             :             &(hMiraMonLayer->MMArc
     368           7 :                   .pArcHeader[hMiraMonLayer->TopHeader.nElemCount - 1]);
     369           7 :         if (MMCheckSize_t(pArcHeader->nElemCount, MM_SIZE_OF_COORDINATE))
     370           0 :             return 1;
     371           7 :         if (pArcHeader->nElemCount * MM_SIZE_OF_COORDINATE >
     372           7 :             UINT64_MAX - pArcHeader->nOffset)
     373           0 :             return 1;
     374             :         // Z section begins just after last coordinate of the last arc
     375           7 :         pZSection->ZSectionOffset =
     376           7 :             pArcHeader->nOffset +
     377           7 :             pArcHeader->nElemCount * MM_SIZE_OF_COORDINATE;
     378             :     }
     379           6 :     else if (hMiraMonLayer->bIsPolygon &&
     380           6 :              hMiraMonLayer->MMPolygon.TopArcHeader.nElemCount > 0)
     381           6 :     {
     382           6 :         const struct MM_AH *pArcHeader =
     383             :             &(hMiraMonLayer->MMPolygon.MMArc
     384           6 :                   .pArcHeader[hMiraMonLayer->MMPolygon.TopArcHeader.nElemCount -
     385             :                               1]);
     386           6 :         if (MMCheckSize_t(pArcHeader->nElemCount, MM_SIZE_OF_COORDINATE))
     387           0 :             return 1;
     388           6 :         if (pArcHeader->nElemCount * MM_SIZE_OF_COORDINATE >
     389           6 :             UINT64_MAX - pArcHeader->nOffset)
     390           0 :             return 1;
     391             :         // Z section begins just after last coordinate of the last arc
     392           6 :         pZSection->ZSectionOffset =
     393           6 :             pArcHeader->nOffset +
     394           6 :             pArcHeader->nElemCount * MM_SIZE_OF_COORDINATE;
     395             :     }
     396             :     else
     397           0 :         return 1;
     398             : 
     399          25 :     if (pF)
     400             :     {
     401          25 :         if (VSIFSeekL(pF, pZSection->ZSectionOffset, SEEK_SET))
     402           0 :             return 1;
     403             : 
     404          25 :         if (VSIFReadL(&reservat4, 4, 1, pF) != 1)
     405           0 :             return 1;
     406          25 :         pZSection->ZSectionOffset += 4;
     407          25 :         if (VSIFReadL(&reservat4, 4, 1, pF) != 1)
     408           0 :             return 1;
     409          25 :         pZSection->ZSectionOffset += 4;
     410          25 :         if (VSIFReadL(&reservat4, 4, 1, pF) != 1)
     411           0 :             return 1;
     412          25 :         pZSection->ZSectionOffset += 4;
     413          25 :         if (VSIFReadL(&reservat4, 4, 1, pF) != 1)
     414           0 :             return 1;
     415          25 :         pZSection->ZSectionOffset += 4;
     416             : 
     417          25 :         if (VSIFReadL(&pZSection->ZHeader.dfBBminz,
     418             :                       sizeof(pZSection->ZHeader.dfBBminz), 1, pF) != 1)
     419           0 :             return 1;
     420          25 :         pZSection->ZSectionOffset += sizeof(pZSection->ZHeader.dfBBminz);
     421             : 
     422          25 :         if (VSIFReadL(&pZSection->ZHeader.dfBBmaxz,
     423             :                       sizeof(pZSection->ZHeader.dfBBmaxz), 1, pF) != 1)
     424           0 :             return 1;
     425          25 :         pZSection->ZSectionOffset += sizeof(pZSection->ZHeader.dfBBmaxz);
     426             :     }
     427          25 :     return 0;
     428             : }
     429             : 
     430          32 : static int MMWriteZSection(VSILFILE *pF, struct MM_ZSection *pZSection)
     431             : {
     432          32 :     int32_t reservat4 = 0L;
     433             : 
     434          32 :     if (VSIFSeekL(pF, pZSection->ZSectionOffset, SEEK_SET))
     435           0 :         return 1;
     436             : 
     437          32 :     if (VSIFWriteL(&reservat4, 4, 1, pF) != 1)
     438           0 :         return 1;
     439          32 :     if (VSIFWriteL(&reservat4, 4, 1, pF) != 1)
     440           0 :         return 1;
     441          32 :     if (VSIFWriteL(&reservat4, 4, 1, pF) != 1)
     442           0 :         return 1;
     443          32 :     if (VSIFWriteL(&reservat4, 4, 1, pF) != 1)
     444           0 :         return 1;
     445             : 
     446          32 :     pZSection->ZSectionOffset += 16;
     447             : 
     448          32 :     if (VSIFWriteL(&pZSection->ZHeader.dfBBminz,
     449             :                    sizeof(pZSection->ZHeader.dfBBminz), 1, pF) != 1)
     450           0 :         return 1;
     451          32 :     pZSection->ZSectionOffset += sizeof(pZSection->ZHeader.dfBBminz);
     452          32 :     if (VSIFWriteL(&pZSection->ZHeader.dfBBmaxz,
     453             :                    sizeof(pZSection->ZHeader.dfBBmaxz), 1, pF) != 1)
     454           0 :         return 1;
     455          32 :     pZSection->ZSectionOffset += sizeof(pZSection->ZHeader.dfBBmaxz);
     456          32 :     return 0;
     457             : }
     458             : 
     459          25 : int MMReadZDescriptionHeaders(struct MiraMonVectLayerInfo *hMiraMonLayer,
     460             :                               VSILFILE *pF, MM_INTERNAL_FID nElements,
     461             :                               struct MM_ZSection *pZSection)
     462             : {
     463             :     struct MM_FLUSH_INFO FlushTMP;
     464          25 :     char *pBuffer = nullptr;
     465          25 :     MM_INTERNAL_FID nIndex = 0;
     466             :     MM_FILE_OFFSET nBlockSize;
     467             :     struct MM_ZD *pZDescription;
     468             : 
     469          25 :     if (!hMiraMonLayer)
     470           0 :         return 1;
     471             : 
     472          25 :     if (!pZSection)
     473           0 :         return 1;
     474             : 
     475          25 :     if (!nElements)
     476           3 :         return 0;  // No elements to read
     477             : 
     478          22 :     pZDescription = pZSection->pZDescription;
     479             : 
     480          22 :     nBlockSize = nElements * pZSection->nZDDiskSize;
     481             : 
     482          22 :     if (MMInitFlush(&FlushTMP, pF, nBlockSize, &pBuffer,
     483             :                     pZSection->ZSectionOffset, 0))
     484             :     {
     485           0 :         if (pBuffer)
     486           0 :             VSIFree(pBuffer);
     487           0 :         return 1;
     488             :     }
     489             : 
     490          22 :     FlushTMP.pBlockWhereToSaveOrRead = (void *)pBuffer;
     491          22 :     if (MMReadFlush(&FlushTMP))
     492             :     {
     493           0 :         if (pBuffer)
     494           0 :             VSIFree(pBuffer);
     495           0 :         return 1;
     496             :     }
     497             : 
     498         361 :     for (nIndex = 0; nIndex < nElements; nIndex++)
     499             :     {
     500         339 :         FlushTMP.SizeOfBlockToBeSaved =
     501             :             sizeof((pZDescription + nIndex)->dfBBminz);
     502         339 :         FlushTMP.pBlockToBeSaved = (void *)&(pZDescription + nIndex)->dfBBminz;
     503         339 :         if (MMReadBlockFromBuffer(&FlushTMP))
     504             :         {
     505           0 :             if (pBuffer)
     506           0 :                 VSIFree(pBuffer);
     507           0 :             return 1;
     508             :         }
     509             : 
     510         339 :         FlushTMP.SizeOfBlockToBeSaved =
     511             :             sizeof((pZDescription + nIndex)->dfBBmaxz);
     512         339 :         FlushTMP.pBlockToBeSaved = (void *)&(pZDescription + nIndex)->dfBBmaxz;
     513         339 :         if (MMReadBlockFromBuffer(&FlushTMP))
     514             :         {
     515           0 :             if (pBuffer)
     516           0 :                 VSIFree(pBuffer);
     517           0 :             return 1;
     518             :         }
     519             : 
     520         339 :         FlushTMP.SizeOfBlockToBeSaved =
     521             :             sizeof((pZDescription + nIndex)->nZCount);
     522         339 :         FlushTMP.pBlockToBeSaved = (void *)&(pZDescription + nIndex)->nZCount;
     523         339 :         if (MMReadBlockFromBuffer(&FlushTMP))
     524             :         {
     525           0 :             if (pBuffer)
     526           0 :                 VSIFree(pBuffer);
     527           0 :             return 1;
     528             :         }
     529             : 
     530         339 :         if (hMiraMonLayer->LayerVersion == MM_64BITS_VERSION)
     531             :         {
     532           0 :             FlushTMP.SizeOfBlockToBeSaved = 4;
     533           0 :             FlushTMP.pBlockToBeSaved = (void *)nullptr;
     534           0 :             if (MMReadBlockFromBuffer(&FlushTMP))
     535             :             {
     536           0 :                 if (pBuffer)
     537           0 :                     VSIFree(pBuffer);
     538           0 :                 return 1;
     539             :             }
     540             :         }
     541             : 
     542         339 :         if (MMReadOffsetDependingOnVersion(hMiraMonLayer, &FlushTMP,
     543         339 :                                            &(pZDescription + nIndex)->nOffsetZ))
     544             :         {
     545           0 :             if (pBuffer)
     546           0 :                 VSIFree(pBuffer);
     547           0 :             return 1;
     548             :         }
     549             :     }
     550          22 :     if (pBuffer)
     551          22 :         VSIFree(pBuffer);
     552             : 
     553          22 :     return 0;
     554             : }
     555             : 
     556             : static int
     557          32 : MMWriteZDescriptionHeaders(struct MiraMonVectLayerInfo *hMiraMonLayer,
     558             :                            VSILFILE *pF, MM_INTERNAL_FID nElements,
     559             :                            struct MM_ZSection *pZSection)
     560             : {
     561             :     struct MM_FLUSH_INFO FlushTMP;
     562          32 :     char *pBuffer = nullptr;
     563             :     uint32_t nUL32;
     564          32 :     MM_INTERNAL_FID nIndex = 0;
     565             :     MM_FILE_OFFSET nOffsetDiff;
     566             :     struct MM_ZD *pZDescription;
     567             : 
     568          32 :     if (!hMiraMonLayer)
     569           0 :         return 1;
     570             : 
     571          32 :     if (!pF)
     572           0 :         return 1;
     573             : 
     574          32 :     if (!pZSection)
     575           0 :         return 1;
     576             : 
     577          32 :     pZDescription = pZSection->pZDescription;
     578             : 
     579          32 :     nOffsetDiff =
     580          32 :         pZSection->ZSectionOffset + nElements * pZSection->nZDDiskSize;
     581             : 
     582          32 :     if (MMInitFlush(&FlushTMP, pF, MM_1MB, &pBuffer, pZSection->ZSectionOffset,
     583             :                     0))
     584             :     {
     585           0 :         if (pBuffer)
     586           0 :             VSIFree(pBuffer);
     587           0 :         return 1;
     588             :     }
     589             : 
     590          32 :     FlushTMP.pBlockWhereToSaveOrRead = (void *)pBuffer;
     591         110 :     for (nIndex = 0; nIndex < nElements; nIndex++)
     592             :     {
     593          78 :         FlushTMP.SizeOfBlockToBeSaved =
     594             :             sizeof((pZDescription + nIndex)->dfBBminz);
     595          78 :         FlushTMP.pBlockToBeSaved = (void *)&(pZDescription + nIndex)->dfBBminz;
     596          78 :         if (MMAppendBlockToBuffer(&FlushTMP))
     597             :         {
     598           0 :             if (pBuffer)
     599           0 :                 VSIFree(pBuffer);
     600           0 :             return 1;
     601             :         }
     602             : 
     603          78 :         FlushTMP.SizeOfBlockToBeSaved =
     604             :             sizeof((pZDescription + nIndex)->dfBBmaxz);
     605          78 :         FlushTMP.pBlockToBeSaved = (void *)&(pZDescription + nIndex)->dfBBmaxz;
     606          78 :         if (MMAppendBlockToBuffer(&FlushTMP))
     607             :         {
     608           0 :             if (pBuffer)
     609           0 :                 VSIFree(pBuffer);
     610           0 :             return 1;
     611             :         }
     612             : 
     613          78 :         FlushTMP.SizeOfBlockToBeSaved =
     614             :             sizeof((pZDescription + nIndex)->nZCount);
     615          78 :         FlushTMP.pBlockToBeSaved = (void *)&(pZDescription + nIndex)->nZCount;
     616          78 :         if (MMAppendBlockToBuffer(&FlushTMP))
     617             :         {
     618           0 :             if (pBuffer)
     619           0 :                 VSIFree(pBuffer);
     620           0 :             return 1;
     621             :         }
     622             : 
     623          78 :         if (hMiraMonLayer->LayerVersion == MM_64BITS_VERSION)
     624             :         {
     625           0 :             FlushTMP.SizeOfBlockToBeSaved = 4;
     626           0 :             FlushTMP.pBlockToBeSaved = (void *)nullptr;
     627           0 :             if (MMAppendBlockToBuffer(&FlushTMP))
     628             :             {
     629           0 :                 if (pBuffer)
     630           0 :                     VSIFree(pBuffer);
     631           0 :                 return 1;
     632             :             }
     633             :         }
     634             : 
     635             :         // Overflow?
     636          78 :         if (hMiraMonLayer->LayerVersion == MM_32BITS_VERSION &&
     637          78 :             (pZDescription + nIndex)->nOffsetZ >
     638          78 :                 MAXIMUM_OFFSET_IN_2GB_VECTORS - nOffsetDiff)
     639             :         {
     640           0 :             CPLError(CE_Failure, CPLE_OpenFailed, "Offset Overflow in V1.1");
     641           0 :             return 1;
     642             :         }
     643             : 
     644          78 :         if (MMAppendIntegerDependingOnVersion(
     645             :                 hMiraMonLayer, &FlushTMP, &nUL32,
     646          78 :                 (pZDescription + nIndex)->nOffsetZ + nOffsetDiff))
     647             :         {
     648           0 :             if (pBuffer)
     649           0 :                 VSIFree(pBuffer);
     650           0 :             return 1;
     651             :         }
     652             :     }
     653          32 :     FlushTMP.SizeOfBlockToBeSaved = 0;
     654          32 :     if (MMAppendBlockToBuffer(&FlushTMP))
     655             :     {
     656           0 :         if (pBuffer)
     657           0 :             VSIFree(pBuffer);
     658           0 :         return 1;
     659             :     }
     660          32 :     pZSection->ZSectionOffset += FlushTMP.TotalSavedBytes;
     661             : 
     662          32 :     if (pBuffer)
     663          32 :         VSIFree(pBuffer);
     664             : 
     665          32 :     return 0;
     666             : }
     667             : 
     668         213 : static void MMDestroyZSectionDescription(struct MM_ZSection *pZSection)
     669             : {
     670         213 :     if (pZSection->pZL)
     671             :     {
     672          92 :         VSIFree(pZSection->pZL);
     673          92 :         pZSection->pZL = nullptr;
     674             :     }
     675             : 
     676         213 :     if (pZSection->pZDescription)
     677             :     {
     678         114 :         VSIFree(pZSection->pZDescription);
     679         114 :         pZSection->pZDescription = nullptr;
     680             :     }
     681         213 : }
     682             : 
     683         117 : static int MMInitZSectionDescription(struct MM_ZSection *pZSection)
     684             : {
     685         117 :     if (MMCheckSize_t(pZSection->nMaxZDescription,
     686             :                       sizeof(*pZSection->pZDescription)))
     687           0 :         return 1;
     688             : 
     689         117 :     if (!pZSection->nMaxZDescription)
     690             :     {
     691           3 :         pZSection->pZDescription = nullptr;
     692           3 :         return 0;  // No elements to read (or write)
     693             :     }
     694             : 
     695         228 :     pZSection->pZDescription = (struct MM_ZD *)VSICalloc(
     696         114 :         (size_t)pZSection->nMaxZDescription, sizeof(*pZSection->pZDescription));
     697         114 :     if (!pZSection->pZDescription)
     698           0 :         return 1;
     699         114 :     return 0;
     700             : }
     701             : 
     702         117 : static int MMInitZSectionLayer(struct MiraMonVectLayerInfo *hMiraMonLayer,
     703             :                                VSILFILE *pF3d, struct MM_ZSection *pZSection)
     704             : {
     705         117 :     if (!hMiraMonLayer)
     706           0 :         return 1;
     707             : 
     708             :     // Zsection
     709         117 :     if (!hMiraMonLayer->TopHeader.bIs3d)
     710             :     {
     711           0 :         pZSection->pZDescription = nullptr;
     712           0 :         return 0;
     713             :     }
     714             : 
     715         117 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
     716             :     {
     717          92 :         pZSection->ZHeader.dfBBminz = STATISTICAL_UNDEF_VALUE;
     718          92 :         pZSection->ZHeader.dfBBmaxz = -STATISTICAL_UNDEF_VALUE;
     719             :     }
     720             : 
     721             :     // ZH
     722         117 :     pZSection->ZHeader.nMyDiskSize = 32;
     723         117 :     pZSection->ZSectionOffset = 0;
     724             : 
     725             :     // ZD
     726         117 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
     727             :     {
     728          92 :         pZSection->nMaxZDescription =
     729             :             MM_FIRST_NUMBER_OF_VERTICES * sizeof(double);
     730          92 :         if (MMInitZSectionDescription(pZSection))
     731           0 :             return 1;
     732             :     }
     733             :     else
     734             :     {
     735          25 :         if (hMiraMonLayer->bIsPolygon)
     736             :         {
     737           6 :             if (MMCheckSize_t(hMiraMonLayer->MMPolygon.TopArcHeader.nElemCount,
     738             :                               sizeof(double)))
     739           0 :                 return 1;
     740             : 
     741           6 :             pZSection->nMaxZDescription =
     742           6 :                 hMiraMonLayer->MMPolygon.TopArcHeader.nElemCount *
     743             :                 sizeof(double);
     744             :         }
     745             :         else
     746             :         {
     747          19 :             if (MMCheckSize_t(hMiraMonLayer->TopHeader.nElemCount,
     748             :                               sizeof(double)))
     749           0 :                 return 1;
     750             : 
     751          19 :             pZSection->nMaxZDescription =
     752          19 :                 hMiraMonLayer->TopHeader.nElemCount * sizeof(double);
     753             :         }
     754          25 :         if (MMInitZSectionDescription(pZSection))
     755           0 :             return 1;
     756             :     }
     757             : 
     758         117 :     if (hMiraMonLayer->LayerVersion == MM_32BITS_VERSION)
     759         111 :         pZSection->nZDDiskSize = MM_SIZE_OF_ZD_32_BITS;
     760             :     else
     761           6 :         pZSection->nZDDiskSize = MM_SIZE_OF_ZD_64_BITS;
     762             : 
     763         117 :     pZSection->ZDOffset = 0;
     764             : 
     765             :     // ZL
     766         117 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
     767             :     {
     768          92 :         if (MMInitFlush(&pZSection->FlushZL, pF3d, MM_1MB, &pZSection->pZL, 0,
     769             :                         sizeof(double)))
     770           0 :             return 1;
     771             :     }
     772         117 :     return 0;
     773             : }
     774             : 
     775             : /* -------------------------------------------------------------------- */
     776             : /*      Layer Functions: Extensions                                     */
     777             : /* -------------------------------------------------------------------- */
     778             : 
     779             : /* Find the last occurrence of pszFinalPart in pszName
     780             :     and changes it by pszNewPart.
     781             : 
     782             :     Examples of desired behavior
     783             :     AA.pnt -> AAT.rel
     784             :     AA.nod -> N.~idx
     785             :     AA.nod -> N.dbf
     786             :     AA.nod -> N.rel
     787             : */
     788             : 
     789         501 : static int MMChangeFinalPartOfTheName(char *pszName, size_t nMaxSizeOfName,
     790             :                                       const char *pszFinalPart,
     791             :                                       const char *pszNewPart)
     792             : {
     793         501 :     char *pAux, *pszWhereToFind, *pszLastFound = nullptr;
     794             :     ;
     795             : 
     796         501 :     if (!pszName || !pszFinalPart || !pszNewPart)
     797           0 :         return 0;
     798        1002 :     if (MMIsEmptyString(pszName) || MMIsEmptyString(pszFinalPart) ||
     799         501 :         MMIsEmptyString(pszNewPart))
     800           0 :         return 0;
     801             : 
     802         501 :     if (strlen(pszName) - strlen(pszFinalPart) + strlen(pszNewPart) >=
     803             :         nMaxSizeOfName)
     804           0 :         return 1;  // It's not possible to change the final part
     805             : 
     806             :     // It's the implementation on windows of the linux strrstr()
     807             :     // pszLastFound = strrstr(pszWhereToFind, pszFinalPart);
     808         501 :     pszWhereToFind = pszName;
     809        1002 :     while (nullptr != (pAux = MM_stristr(pszWhereToFind, pszFinalPart)))
     810             :     {
     811         501 :         pszLastFound = pAux;
     812         501 :         pszWhereToFind = pAux + strlen(pAux);
     813             :     }
     814             : 
     815         501 :     if (!pszLastFound)
     816           0 :         return 1;  // Not found not changed
     817             : 
     818         501 :     memcpy(pszLastFound, pszNewPart, strlen(pszNewPart));
     819             : 
     820         501 :     return 0;
     821             : }
     822             : 
     823             : /* -------------------------------------------------------------------- */
     824             : /*      Layer Functions: initializing MiraMon layers                    */
     825             : /* -------------------------------------------------------------------- */
     826          76 : static int MMInitPointLayer(struct MiraMonVectLayerInfo *hMiraMonLayer)
     827             : {
     828          76 :     if (!hMiraMonLayer)
     829           0 :         return 1;
     830             : 
     831          76 :     hMiraMonLayer->bIsPoint = 1;
     832             : 
     833          76 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
     834             :     {
     835             :         // Geometrical part
     836             :         // Init header structure
     837          34 :         hMiraMonLayer->TopHeader.nElemCount = 0;
     838          34 :         MMInitBoundingBox(&hMiraMonLayer->TopHeader.hBB);
     839             : 
     840          34 :         hMiraMonLayer->TopHeader.bIs3d = 1;  // Read description of bRealIs3d
     841          34 :         hMiraMonLayer->TopHeader.aFileType[0] = 'P';
     842          34 :         hMiraMonLayer->TopHeader.aFileType[1] = 'N';
     843          34 :         hMiraMonLayer->TopHeader.aFileType[2] = 'T';
     844             : 
     845             :         // Opening the binary file where sections TH, TL[...] and ZH-ZD[...]-ZL[...]
     846             :         // are going to be written.
     847             : 
     848          34 :         snprintf(hMiraMonLayer->MMPoint.pszLayerName,
     849             :                  sizeof(hMiraMonLayer->MMPoint.pszLayerName), "%s.pnt",
     850             :                  hMiraMonLayer->pszSrcLayerName);
     851             :     }
     852          76 :     if (nullptr == (hMiraMonLayer->MMPoint.pF =
     853          76 :                         VSIFOpenL(hMiraMonLayer->MMPoint.pszLayerName,
     854          76 :                                   hMiraMonLayer->pszFlags)))
     855             :     {
     856           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     857             :                  "Error MMPoint.pF: Cannot open file %s.",
     858           0 :                  hMiraMonLayer->MMPoint.pszLayerName);
     859           0 :         return 1;
     860             :     }
     861          76 :     VSIFSeekL(hMiraMonLayer->MMPoint.pF, 0, SEEK_SET);
     862             : 
     863          76 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
     864             :     {
     865             :         // TL
     866          34 :         snprintf(hMiraMonLayer->MMPoint.pszTLName,
     867             :                  sizeof(hMiraMonLayer->MMPoint.pszTLName), "%sT.~xy",
     868             :                  hMiraMonLayer->pszSrcLayerName);
     869             : 
     870          34 :         if (nullptr == (hMiraMonLayer->MMPoint.pFTL =
     871          34 :                             VSIFOpenL(hMiraMonLayer->MMPoint.pszTLName,
     872          34 :                                       hMiraMonLayer->pszFlags)))
     873             :         {
     874           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
     875             :                      "Error MMPoint.pFTL: Cannot open file %s.",
     876           0 :                      hMiraMonLayer->MMPoint.pszTLName);
     877           0 :             return 1;
     878             :         }
     879          34 :         VSIFSeekL(hMiraMonLayer->MMPoint.pFTL, 0, SEEK_SET);
     880             : 
     881          34 :         if (MMInitFlush(&hMiraMonLayer->MMPoint.FlushTL,
     882             :                         hMiraMonLayer->MMPoint.pFTL, MM_1MB,
     883             :                         &hMiraMonLayer->MMPoint.pTL, 0, MM_SIZE_OF_TL))
     884           0 :             return 1;
     885             : 
     886             :         // 3D part
     887          34 :         if (hMiraMonLayer->TopHeader.bIs3d)
     888             :         {
     889          34 :             snprintf(hMiraMonLayer->MMPoint.psz3DLayerName,
     890             :                      sizeof(hMiraMonLayer->MMPoint.psz3DLayerName), "%sT.~z",
     891             :                      hMiraMonLayer->pszSrcLayerName);
     892             : 
     893          34 :             if (nullptr == (hMiraMonLayer->MMPoint.pF3d =
     894          34 :                                 VSIFOpenL(hMiraMonLayer->MMPoint.psz3DLayerName,
     895          34 :                                           hMiraMonLayer->pszFlags)))
     896             :             {
     897           0 :                 CPLError(CE_Failure, CPLE_OpenFailed,
     898             :                          "Error MMPoint.pF3d: Cannot open file %s.",
     899           0 :                          hMiraMonLayer->MMPoint.psz3DLayerName);
     900           0 :                 return 1;
     901             :             }
     902          34 :             VSIFSeekL(hMiraMonLayer->MMPoint.pF3d, 0, SEEK_SET);
     903             :         }
     904             :     }
     905             :     // Zsection
     906          76 :     if (hMiraMonLayer->TopHeader.bIs3d)
     907             :     {
     908          46 :         if (MMInitZSectionLayer(hMiraMonLayer, hMiraMonLayer->MMPoint.pF3d,
     909             :                                 &hMiraMonLayer->MMPoint.pZSection))
     910           0 :             return 1;
     911             : 
     912          46 :         if (hMiraMonLayer->ReadOrWrite == MM_READING_MODE)
     913             :         {
     914          12 :             if (MMReadZSection(hMiraMonLayer, hMiraMonLayer->MMPoint.pF,
     915             :                                &hMiraMonLayer->MMPoint.pZSection))
     916           0 :                 return 1;
     917             : 
     918          12 :             if (MMReadZDescriptionHeaders(hMiraMonLayer,
     919             :                                           hMiraMonLayer->MMPoint.pF,
     920             :                                           hMiraMonLayer->TopHeader.nElemCount,
     921             :                                           &hMiraMonLayer->MMPoint.pZSection))
     922           0 :                 return 1;
     923             :         }
     924             :     }
     925             : 
     926             :     // MiraMon metadata
     927          76 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
     928             :     {
     929          34 :         snprintf(hMiraMonLayer->MMPoint.pszREL_LayerName,
     930             :                  sizeof(hMiraMonLayer->MMPoint.pszREL_LayerName), "%sT.rel",
     931             :                  hMiraMonLayer->pszSrcLayerName);
     932             :     }
     933             :     else
     934             :     {
     935          42 :         CPLStrlcpy(hMiraMonLayer->MMPoint.pszREL_LayerName,
     936          42 :                    hMiraMonLayer->pszSrcLayerName,
     937             :                    sizeof(hMiraMonLayer->MMPoint.pszREL_LayerName));
     938          42 :         if (MMChangeFinalPartOfTheName(hMiraMonLayer->MMPoint.pszREL_LayerName,
     939             :                                        MM_CPL_PATH_BUF_SIZE, ".pnt", "T.rel"))
     940           0 :             return 1;
     941             :     }
     942             : 
     943          76 :     hMiraMonLayer->pszMainREL_LayerName =
     944          76 :         hMiraMonLayer->MMPoint.pszREL_LayerName;
     945             : 
     946          76 :     if (hMiraMonLayer->ReadOrWrite == MM_READING_MODE)
     947             :     {
     948             :         // This file has to exist and be the appropriate version.
     949          42 :         if (MMCheck_REL_FILE(hMiraMonLayer->MMPoint.pszREL_LayerName))
     950           1 :             return 1;
     951             :     }
     952             : 
     953             :     // MIRAMON DATA BASE
     954             :     // Creating the DBF file name
     955          75 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
     956             :     {
     957          34 :         snprintf(hMiraMonLayer->MMPoint.MMAdmDB.pszExtDBFLayerName,
     958             :                  sizeof(hMiraMonLayer->MMPoint.MMAdmDB.pszExtDBFLayerName),
     959             :                  "%sT.dbf", hMiraMonLayer->pszSrcLayerName);
     960             :     }
     961             :     else
     962             :     {
     963          41 :         CPLStrlcpy(hMiraMonLayer->MMPoint.MMAdmDB.pszExtDBFLayerName,
     964          41 :                    hMiraMonLayer->pszSrcLayerName,
     965             :                    sizeof(hMiraMonLayer->MMPoint.MMAdmDB.pszExtDBFLayerName));
     966             : 
     967          41 :         if (MMChangeFinalPartOfTheName(
     968          41 :                 hMiraMonLayer->MMPoint.MMAdmDB.pszExtDBFLayerName,
     969             :                 MM_CPL_PATH_BUF_SIZE, ".pnt", "T.dbf"))
     970           0 :             return 1;
     971             :     }
     972             : 
     973          75 :     if (hMiraMonLayer->ReadOrWrite == MM_READING_MODE)
     974             :     {
     975          41 :         if (MM_ReadExtendedDBFHeader(hMiraMonLayer))
     976           1 :             return 1;
     977             :     }
     978             : 
     979          74 :     return 0;
     980             : }
     981             : 
     982         132 : static int MMInitNodeLayer(struct MiraMonVectLayerInfo *hMiraMonLayer)
     983             : {
     984             :     struct MiraMonArcLayer *pMMArcLayer;
     985             : 
     986         132 :     if (!hMiraMonLayer)
     987           0 :         return 1;
     988             : 
     989         132 :     if (hMiraMonLayer->bIsPolygon)
     990          71 :         pMMArcLayer = &hMiraMonLayer->MMPolygon.MMArc;
     991             :     else
     992          61 :         pMMArcLayer = &hMiraMonLayer->MMArc;
     993             : 
     994         132 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
     995             :     {
     996             :         // Init header structure
     997          58 :         pMMArcLayer->TopNodeHeader.aFileType[0] = 'N';
     998          58 :         pMMArcLayer->TopNodeHeader.aFileType[1] = 'O';
     999          58 :         pMMArcLayer->TopNodeHeader.aFileType[2] = 'D';
    1000             : 
    1001          58 :         pMMArcLayer->TopNodeHeader.bIs3d = 1;  // Read description of bRealIs3d
    1002          58 :         MMInitBoundingBox(&pMMArcLayer->TopNodeHeader.hBB);
    1003             :     }
    1004             : 
    1005             :     // Opening the binary file where sections TH, NH and NL[...]
    1006             :     // are going to be written.
    1007         132 :     strcpy(pMMArcLayer->MMNode.pszLayerName, pMMArcLayer->pszLayerName);
    1008         132 :     CPLStrlcpy(pMMArcLayer->MMNode.pszLayerName,
    1009         132 :                CPLResetExtension(pMMArcLayer->MMNode.pszLayerName, "nod"),
    1010             :                sizeof(pMMArcLayer->MMNode.pszLayerName));
    1011             : 
    1012         132 :     if (nullptr ==
    1013         132 :         (pMMArcLayer->MMNode.pF = VSIFOpenL(pMMArcLayer->MMNode.pszLayerName,
    1014         132 :                                             hMiraMonLayer->pszFlags)))
    1015             :     {
    1016             : 
    1017           1 :         CPLError(CE_Failure, CPLE_OpenFailed,
    1018             :                  "Error MMNode.pF: Cannot open file %s.",
    1019           1 :                  pMMArcLayer->MMNode.pszLayerName);
    1020           1 :         return 1;
    1021             :     }
    1022         131 :     VSIFSeekL(pMMArcLayer->MMNode.pF, 0, SEEK_SET);
    1023             : 
    1024         131 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    1025             :     {
    1026             :         // Node Header
    1027          58 :         pMMArcLayer->MMNode.nMaxNodeHeader = MM_FIRST_NUMBER_OF_NODES;
    1028          58 :         if (MMCheckSize_t(pMMArcLayer->MMNode.nMaxNodeHeader,
    1029             :                           sizeof(*pMMArcLayer->MMNode.pNodeHeader)))
    1030           0 :             return 1;
    1031             : 
    1032          58 :         if (!pMMArcLayer->MMNode.nMaxNodeHeader)
    1033             :         {
    1034           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
    1035             :                      "Error in MiraMon "
    1036             :                      "driver: no nodes to write?");
    1037           0 :             return 1;
    1038             :         }
    1039             : 
    1040          58 :         if (nullptr ==
    1041          58 :             (pMMArcLayer->MMNode.pNodeHeader = (struct MM_NH *)VSICalloc(
    1042          58 :                  (size_t)pMMArcLayer->MMNode.nMaxNodeHeader,
    1043             :                  sizeof(*pMMArcLayer->MMNode.pNodeHeader))))
    1044             :         {
    1045           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
    1046             :                      "Memory error in MiraMon "
    1047             :                      "driver (MMInitNodeLayer())");
    1048           0 :             return 1;
    1049             :         }
    1050             : 
    1051          58 :         if (hMiraMonLayer->LayerVersion == MM_32BITS_VERSION)
    1052          54 :             pMMArcLayer->MMNode.nSizeNodeHeader = MM_SIZE_OF_NH_32BITS;
    1053             :         else
    1054           4 :             pMMArcLayer->MMNode.nSizeNodeHeader = MM_SIZE_OF_NH_64BITS;
    1055             : 
    1056             :         // NL Section
    1057          58 :         strcpy(pMMArcLayer->MMNode.pszNLName, pMMArcLayer->MMNode.pszLayerName);
    1058          58 :         if (MMChangeFinalPartOfTheName(pMMArcLayer->MMNode.pszNLName,
    1059             :                                        MM_CPL_PATH_BUF_SIZE, ".nod", "N.~idx"))
    1060           0 :             return 1;
    1061             : 
    1062          58 :         if (nullptr ==
    1063          58 :             (pMMArcLayer->MMNode.pFNL = VSIFOpenL(pMMArcLayer->MMNode.pszNLName,
    1064          58 :                                                   hMiraMonLayer->pszFlags)))
    1065             :         {
    1066             : 
    1067           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
    1068             :                      "Error MMNode.pFNL: Cannot open file %s.",
    1069           0 :                      pMMArcLayer->MMNode.pszNLName);
    1070           0 :             return 1;
    1071             :         }
    1072          58 :         VSIFSeekL(pMMArcLayer->MMNode.pFNL, 0, SEEK_SET);
    1073             : 
    1074          58 :         if (MMInitFlush(&pMMArcLayer->MMNode.FlushNL, pMMArcLayer->MMNode.pFNL,
    1075             :                         MM_1MB, &pMMArcLayer->MMNode.pNL, 0, 0))
    1076           0 :             return 1;
    1077             : 
    1078             :         // Creating the DBF file name
    1079          58 :         strcpy(pMMArcLayer->MMNode.MMAdmDB.pszExtDBFLayerName,
    1080          58 :                pMMArcLayer->MMNode.pszLayerName);
    1081          58 :         if (MMChangeFinalPartOfTheName(
    1082          58 :                 pMMArcLayer->MMNode.MMAdmDB.pszExtDBFLayerName,
    1083             :                 MM_CPL_PATH_BUF_SIZE, ".nod", "N.dbf"))
    1084           0 :             return 1;
    1085             : 
    1086             :         // MiraMon metadata
    1087          58 :         strcpy(pMMArcLayer->MMNode.pszREL_LayerName,
    1088          58 :                pMMArcLayer->MMNode.pszLayerName);
    1089          58 :         if (MMChangeFinalPartOfTheName(pMMArcLayer->MMNode.pszREL_LayerName,
    1090             :                                        MM_CPL_PATH_BUF_SIZE, ".nod", "N.rel"))
    1091           0 :             return 1;
    1092             :     }
    1093         131 :     return 0;
    1094             : }
    1095             : 
    1096         133 : static int MMInitArcLayer(struct MiraMonVectLayerInfo *hMiraMonLayer)
    1097             : {
    1098             :     struct MiraMonArcLayer *pMMArcLayer;
    1099             :     struct MM_TH *pArcTopHeader;
    1100             : 
    1101         133 :     if (!hMiraMonLayer)
    1102           0 :         return 1;
    1103             : 
    1104         133 :     if (hMiraMonLayer->bIsPolygon)
    1105             :     {
    1106          71 :         pMMArcLayer = &hMiraMonLayer->MMPolygon.MMArc;
    1107          71 :         pArcTopHeader = &hMiraMonLayer->MMPolygon.TopArcHeader;
    1108             :     }
    1109             :     else
    1110             :     {
    1111          62 :         pMMArcLayer = &hMiraMonLayer->MMArc;
    1112          62 :         pArcTopHeader = &hMiraMonLayer->TopHeader;
    1113             :     }
    1114             : 
    1115             :     // Init header structure
    1116         133 :     hMiraMonLayer->bIsArc = 1;
    1117             : 
    1118         133 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    1119             :     {
    1120          58 :         pArcTopHeader->bIs3d = 1;  // Read description of bRealIs3d
    1121          58 :         MMInitBoundingBox(&pArcTopHeader->hBB);
    1122             : 
    1123          58 :         pArcTopHeader->aFileType[0] = 'A';
    1124          58 :         pArcTopHeader->aFileType[1] = 'R';
    1125          58 :         pArcTopHeader->aFileType[2] = 'C';
    1126             : 
    1127          58 :         if (hMiraMonLayer->bIsPolygon)
    1128             :         {
    1129          27 :             snprintf(pMMArcLayer->pszLayerName,
    1130             :                      sizeof(pMMArcLayer->pszLayerName), "%s_bound.arc",
    1131             :                      hMiraMonLayer->pszSrcLayerName);
    1132             :         }
    1133             :         else
    1134             :         {
    1135          31 :             snprintf(pMMArcLayer->pszLayerName,
    1136             :                      sizeof(pMMArcLayer->pszLayerName), "%s.arc",
    1137             :                      hMiraMonLayer->pszSrcLayerName);
    1138             :         }
    1139             :     }
    1140             : 
    1141         133 :     if (nullptr == (pMMArcLayer->pF = VSIFOpenL(pMMArcLayer->pszLayerName,
    1142         133 :                                                 hMiraMonLayer->pszFlags)))
    1143             :     {
    1144           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
    1145             :                  "Error pMMArcLayer->pF: Cannot open file %s.",
    1146           0 :                  pMMArcLayer->pszLayerName);
    1147           0 :         return 1;
    1148             :     }
    1149             : 
    1150         133 :     if (hMiraMonLayer->ReadOrWrite == MM_READING_MODE &&
    1151          75 :         hMiraMonLayer->bIsPolygon)
    1152             :     {
    1153          44 :         VSIFSeekL(pMMArcLayer->pF, 0, SEEK_SET);
    1154          44 :         if (MMReadHeader(pMMArcLayer->pF,
    1155             :                          &hMiraMonLayer->MMPolygon.TopArcHeader))
    1156             :         {
    1157           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    1158             :                      "Error reading the format in file %s.",
    1159           0 :                      pMMArcLayer->pszLayerName);
    1160           0 :             return 1;
    1161             :         }
    1162             :         // 3D information is in arcs file
    1163          44 :         hMiraMonLayer->TopHeader.bIs3d =
    1164          44 :             hMiraMonLayer->MMPolygon.TopArcHeader.bIs3d;
    1165             :     }
    1166             : 
    1167             :     // AH
    1168         133 :     if (hMiraMonLayer->LayerVersion == MM_32BITS_VERSION)
    1169         125 :         pMMArcLayer->nSizeArcHeader = MM_SIZE_OF_AH_32BITS;
    1170             :     else
    1171           8 :         pMMArcLayer->nSizeArcHeader = MM_SIZE_OF_AH_64BITS;
    1172             : 
    1173         133 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    1174          58 :         pMMArcLayer->nMaxArcHeader = MM_FIRST_NUMBER_OF_ARCS;
    1175             :     else
    1176          75 :         pMMArcLayer->nMaxArcHeader = pArcTopHeader->nElemCount;
    1177             : 
    1178         133 :     if (pMMArcLayer->nMaxArcHeader)
    1179             :     {
    1180         127 :         if (MMCheckSize_t(pMMArcLayer->nMaxArcHeader,
    1181             :                           sizeof(*pMMArcLayer->pArcHeader)))
    1182           0 :             return 1;
    1183         127 :         if (nullptr == (pMMArcLayer->pArcHeader = (struct MM_AH *)VSICalloc(
    1184         127 :                             (size_t)pMMArcLayer->nMaxArcHeader,
    1185             :                             sizeof(*pMMArcLayer->pArcHeader))))
    1186             :         {
    1187           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
    1188             :                      "Memory error in MiraMon "
    1189             :                      "driver (MMInitArcLayer())");
    1190           0 :             return 1;
    1191             :         }
    1192         127 :         if (hMiraMonLayer->ReadOrWrite == MM_READING_MODE)
    1193             :         {
    1194          69 :             if (MMReadAHArcSection(hMiraMonLayer))
    1195             :             {
    1196           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
    1197             :                          "Error reading the format in file %s.",
    1198           0 :                          pMMArcLayer->pszLayerName);
    1199           0 :                 return 1;
    1200             :             }
    1201             :         }
    1202             :     }
    1203             :     else
    1204           6 :         pMMArcLayer->pArcHeader = nullptr;
    1205             : 
    1206             :     // AL
    1207         133 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    1208             :     {
    1209          58 :         pMMArcLayer->nALElementSize = MM_SIZE_OF_AL;
    1210             : 
    1211          58 :         if (hMiraMonLayer->bIsPolygon)
    1212             :         {
    1213          27 :             snprintf(pMMArcLayer->pszALName, sizeof(pMMArcLayer->pszALName),
    1214             :                      "%s_boundA.~xy", hMiraMonLayer->pszSrcLayerName);
    1215             :         }
    1216             :         else
    1217             :         {
    1218          31 :             snprintf(pMMArcLayer->pszALName, sizeof(pMMArcLayer->pszALName),
    1219             :                      "%sA.~xy", hMiraMonLayer->pszSrcLayerName);
    1220             :         }
    1221             : 
    1222          58 :         if (nullptr == (pMMArcLayer->pFAL = VSIFOpenL(pMMArcLayer->pszALName,
    1223          58 :                                                       hMiraMonLayer->pszFlags)))
    1224             :         {
    1225           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
    1226             :                      "Error pMMArcLayer->pFAL: Cannot open file %s.",
    1227           0 :                      pMMArcLayer->pszALName);
    1228           0 :             return 1;
    1229             :         }
    1230          58 :         VSIFSeekL(pMMArcLayer->pFAL, 0, SEEK_SET);
    1231             : 
    1232          58 :         if (MMInitFlush(&pMMArcLayer->FlushAL, pMMArcLayer->pFAL, MM_1MB,
    1233             :                         &pMMArcLayer->pAL, 0, 0))
    1234           0 :             return 1;
    1235             :     }
    1236             : 
    1237             :     // 3D
    1238         133 :     if (pArcTopHeader->bIs3d)
    1239             :     {
    1240          71 :         if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    1241             :         {
    1242          58 :             if (hMiraMonLayer->bIsPolygon)
    1243             :             {
    1244          27 :                 snprintf(pMMArcLayer->psz3DLayerName,
    1245             :                          sizeof(pMMArcLayer->psz3DLayerName), "%s_boundA.~z",
    1246             :                          hMiraMonLayer->pszSrcLayerName);
    1247             :             }
    1248             :             else
    1249             :             {
    1250          31 :                 snprintf(pMMArcLayer->psz3DLayerName,
    1251             :                          sizeof(pMMArcLayer->psz3DLayerName), "%sA.~z",
    1252             :                          hMiraMonLayer->pszSrcLayerName);
    1253             :             }
    1254             : 
    1255          58 :             if (nullptr ==
    1256          58 :                 (pMMArcLayer->pF3d = VSIFOpenL(pMMArcLayer->psz3DLayerName,
    1257          58 :                                                hMiraMonLayer->pszFlags)))
    1258             :             {
    1259           0 :                 CPLError(CE_Failure, CPLE_OpenFailed,
    1260             :                          "Error pMMArcLayer->pF3d: Cannot open file %s.",
    1261           0 :                          pMMArcLayer->psz3DLayerName);
    1262           0 :                 return 1;
    1263             :             }
    1264          58 :             VSIFSeekL(pMMArcLayer->pF3d, 0, SEEK_SET);
    1265             :         }
    1266             : 
    1267          71 :         if (MMInitZSectionLayer(hMiraMonLayer, pMMArcLayer->pF3d,
    1268             :                                 &pMMArcLayer->pZSection))
    1269             :         {
    1270           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    1271             :                      "Error reading the format in file %s %d.",
    1272           0 :                      pMMArcLayer->pszLayerName, 6);
    1273           0 :             return 1;
    1274             :         }
    1275             : 
    1276          71 :         if (hMiraMonLayer->ReadOrWrite == MM_READING_MODE)
    1277             :         {
    1278          13 :             if (MMReadZSection(hMiraMonLayer, pMMArcLayer->pF,
    1279             :                                &pMMArcLayer->pZSection))
    1280             :             {
    1281           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
    1282             :                          "Error reading the format in file %s.",
    1283           0 :                          pMMArcLayer->pszLayerName);
    1284           0 :                 return 1;
    1285             :             }
    1286             : 
    1287          13 :             if (MMReadZDescriptionHeaders(hMiraMonLayer, pMMArcLayer->pF,
    1288             :                                           pArcTopHeader->nElemCount,
    1289             :                                           &pMMArcLayer->pZSection))
    1290             :             {
    1291           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
    1292             :                          "Error reading the format in file %s.",
    1293           0 :                          pMMArcLayer->pszLayerName);
    1294           0 :                 return 1;
    1295             :             }
    1296             :         }
    1297             :     }
    1298             :     // MiraMon metadata
    1299         133 :     if (hMiraMonLayer->bIsPolygon)
    1300             :     {
    1301          71 :         if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    1302             :         {
    1303          27 :             snprintf(pMMArcLayer->pszREL_LayerName,
    1304             :                      sizeof(pMMArcLayer->pszREL_LayerName), "%s_boundA.rel",
    1305             :                      hMiraMonLayer->pszSrcLayerName);
    1306             :         }
    1307             :         else
    1308             :         {
    1309          44 :             strcpy(pMMArcLayer->pszREL_LayerName, pMMArcLayer->pszLayerName);
    1310          44 :             if (MMChangeFinalPartOfTheName(pMMArcLayer->pszREL_LayerName,
    1311             :                                            MM_CPL_PATH_BUF_SIZE, ".arc",
    1312             :                                            "A.rel"))
    1313           0 :                 return 1;
    1314             :         }
    1315             :     }
    1316             :     else
    1317             :     {
    1318          62 :         if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    1319             :         {
    1320          31 :             snprintf(pMMArcLayer->pszREL_LayerName,
    1321             :                      sizeof(pMMArcLayer->pszREL_LayerName), "%sA.rel",
    1322             :                      hMiraMonLayer->pszSrcLayerName);
    1323             :         }
    1324             :         else
    1325             :         {
    1326          31 :             CPLStrlcpy(pMMArcLayer->pszREL_LayerName,
    1327          31 :                        hMiraMonLayer->pszSrcLayerName,
    1328             :                        sizeof(pMMArcLayer->pszREL_LayerName));
    1329          31 :             if (MMChangeFinalPartOfTheName(pMMArcLayer->pszREL_LayerName,
    1330             :                                            MM_CPL_PATH_BUF_SIZE, ".arc",
    1331             :                                            "A.rel"))
    1332           0 :                 return 1;
    1333             :         }
    1334             :     }
    1335             : 
    1336         133 :     if (hMiraMonLayer->ReadOrWrite == MM_READING_MODE)
    1337             :     {
    1338             :         // This file has to exist and be the appropriate version.
    1339          75 :         if (MMCheck_REL_FILE(pMMArcLayer->pszREL_LayerName))
    1340           1 :             return 1;
    1341             :     }
    1342             : 
    1343         132 :     if (!hMiraMonLayer->bIsPolygon)
    1344          61 :         hMiraMonLayer->pszMainREL_LayerName = pMMArcLayer->pszREL_LayerName;
    1345             : 
    1346             :     // MIRAMON DATA BASE
    1347             :     // Creating the DBF file name
    1348         132 :     if (hMiraMonLayer->bIsPolygon)
    1349             :     {
    1350          71 :         if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    1351             :         {
    1352          27 :             snprintf(pMMArcLayer->MMAdmDB.pszExtDBFLayerName,
    1353             :                      sizeof(pMMArcLayer->MMAdmDB.pszExtDBFLayerName),
    1354             :                      "%s_boundA.dbf", hMiraMonLayer->pszSrcLayerName);
    1355             :         }
    1356             :         else
    1357             :         {
    1358          44 :             strcpy(pMMArcLayer->MMAdmDB.pszExtDBFLayerName,
    1359          44 :                    pMMArcLayer->pszLayerName);
    1360          44 :             if (MMChangeFinalPartOfTheName(
    1361          44 :                     pMMArcLayer->MMAdmDB.pszExtDBFLayerName,
    1362             :                     MM_CPL_PATH_BUF_SIZE, ".arc", "A.dbf"))
    1363           0 :                 return 1;
    1364             :         }
    1365             :     }
    1366             :     else
    1367             :     {
    1368          61 :         if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    1369             :         {
    1370          31 :             snprintf(pMMArcLayer->MMAdmDB.pszExtDBFLayerName,
    1371             :                      sizeof(pMMArcLayer->MMAdmDB.pszExtDBFLayerName), "%sA.dbf",
    1372             :                      hMiraMonLayer->pszSrcLayerName);
    1373             :         }
    1374             :         else
    1375             :         {
    1376          30 :             CPLStrlcpy(pMMArcLayer->MMAdmDB.pszExtDBFLayerName,
    1377          30 :                        hMiraMonLayer->pszSrcLayerName,
    1378             :                        sizeof(pMMArcLayer->MMAdmDB.pszExtDBFLayerName));
    1379          30 :             if (MMChangeFinalPartOfTheName(
    1380          30 :                     pMMArcLayer->MMAdmDB.pszExtDBFLayerName,
    1381             :                     MM_CPL_PATH_BUF_SIZE, ".arc", "A.dbf"))
    1382           0 :                 return 1;
    1383             :         }
    1384             :     }
    1385             : 
    1386         132 :     if (hMiraMonLayer->ReadOrWrite == MM_READING_MODE)
    1387             :     {
    1388          74 :         if (MM_ReadExtendedDBFHeader(hMiraMonLayer))
    1389           0 :             return 1;
    1390             :     }
    1391             : 
    1392             :     // Node part
    1393         132 :     if (MMInitNodeLayer(hMiraMonLayer))
    1394           1 :         return 1;
    1395         131 :     if (hMiraMonLayer->LayerVersion == MM_32BITS_VERSION)
    1396         123 :         MMSet1_1Version(&pMMArcLayer->TopNodeHeader);
    1397             :     else
    1398           8 :         MMSet2_0Version(&pMMArcLayer->TopNodeHeader);
    1399             : 
    1400         131 :     return 0;
    1401             : }
    1402             : 
    1403          75 : static int MMInitPolygonLayer(struct MiraMonVectLayerInfo *hMiraMonLayer)
    1404             : {
    1405             :     struct MiraMonPolygonLayer *pMMPolygonLayer;
    1406             : 
    1407          75 :     if (!hMiraMonLayer)
    1408           0 :         return 1;
    1409             : 
    1410          75 :     pMMPolygonLayer = &hMiraMonLayer->MMPolygon;
    1411             : 
    1412             :     // Init header structure
    1413          75 :     hMiraMonLayer->bIsPolygon = 1;
    1414             : 
    1415          75 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    1416             :     {
    1417          27 :         hMiraMonLayer->TopHeader.bIs3d = 1;  // Read description of bRealIs3d
    1418          27 :         MMInitBoundingBox(&hMiraMonLayer->TopHeader.hBB);
    1419             : 
    1420          27 :         hMiraMonLayer->TopHeader.aFileType[0] = 'P';
    1421          27 :         hMiraMonLayer->TopHeader.aFileType[1] = 'O';
    1422          27 :         hMiraMonLayer->TopHeader.aFileType[2] = 'L';
    1423             : 
    1424          27 :         snprintf(pMMPolygonLayer->pszLayerName,
    1425             :                  sizeof(pMMPolygonLayer->pszLayerName), "%s.pol",
    1426             :                  hMiraMonLayer->pszSrcLayerName);
    1427             :     }
    1428             : 
    1429          75 :     if (nullptr ==
    1430          75 :         (pMMPolygonLayer->pF =
    1431          75 :              VSIFOpenL(pMMPolygonLayer->pszLayerName, hMiraMonLayer->pszFlags)))
    1432             :     {
    1433           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
    1434             :                  "Error pMMPolygonLayer->pF: Cannot open file %s.",
    1435           0 :                  pMMPolygonLayer->pszLayerName);
    1436           0 :         return 1;
    1437             :     }
    1438             : 
    1439             :     // PS
    1440          75 :     if (hMiraMonLayer->LayerVersion == MM_32BITS_VERSION)
    1441          71 :         pMMPolygonLayer->nPSElementSize = MM_SIZE_OF_PS_32BITS;
    1442             :     else
    1443           4 :         pMMPolygonLayer->nPSElementSize = MM_SIZE_OF_PS_64BITS;
    1444             : 
    1445          75 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    1446             :     {
    1447          27 :         snprintf(pMMPolygonLayer->pszPSName, sizeof(pMMPolygonLayer->pszPSName),
    1448             :                  "%sP.~PS", hMiraMonLayer->pszSrcLayerName);
    1449             : 
    1450          27 :         if (nullptr ==
    1451          27 :             (pMMPolygonLayer->pFPS = VSIFOpenL(pMMPolygonLayer->pszPSName,
    1452          27 :                                                hMiraMonLayer->pszFlags)))
    1453             :         {
    1454           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
    1455             :                      "Error pMMPolygonLayer->pFPS: Cannot open file %s.",
    1456           0 :                      pMMPolygonLayer->pszPSName);
    1457           0 :             return 1;
    1458             :         }
    1459          27 :         VSIFSeekL(pMMPolygonLayer->pFPS, 0, SEEK_SET);
    1460             : 
    1461          27 :         if (MMInitFlush(&pMMPolygonLayer->FlushPS, pMMPolygonLayer->pFPS,
    1462             :                         MM_1MB, &pMMPolygonLayer->pPS, 0,
    1463          27 :                         pMMPolygonLayer->nPSElementSize))
    1464           0 :             return 1;
    1465             :     }
    1466             : 
    1467             :     // PH
    1468          75 :     if (hMiraMonLayer->LayerVersion == MM_32BITS_VERSION)
    1469          71 :         pMMPolygonLayer->nPHElementSize = MM_SIZE_OF_PH_32BITS;
    1470             :     else
    1471           4 :         pMMPolygonLayer->nPHElementSize = MM_SIZE_OF_PH_64BITS;
    1472             : 
    1473          75 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    1474          27 :         pMMPolygonLayer->nMaxPolHeader = MM_FIRST_NUMBER_OF_POLYGONS + 1;
    1475             :     else
    1476          48 :         pMMPolygonLayer->nMaxPolHeader = hMiraMonLayer->TopHeader.nElemCount;
    1477             : 
    1478          75 :     if (pMMPolygonLayer->nMaxPolHeader)
    1479             :     {
    1480          75 :         if (MMCheckSize_t(pMMPolygonLayer->nMaxPolHeader,
    1481             :                           sizeof(*pMMPolygonLayer->pPolHeader)))
    1482           0 :             return 1;
    1483          75 :         if (nullptr == (pMMPolygonLayer->pPolHeader = (struct MM_PH *)VSICalloc(
    1484          75 :                             (size_t)pMMPolygonLayer->nMaxPolHeader,
    1485             :                             sizeof(*pMMPolygonLayer->pPolHeader))))
    1486             :         {
    1487           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
    1488             :                      "Memory error in MiraMon "
    1489             :                      "driver (MMInitPolygonLayer())");
    1490           0 :             return 1;
    1491             :         }
    1492             :     }
    1493             :     else
    1494           0 :         pMMPolygonLayer->pPolHeader = nullptr;
    1495             : 
    1496             :     // PAL
    1497          75 :     if (hMiraMonLayer->LayerVersion == MM_32BITS_VERSION)
    1498          71 :         pMMPolygonLayer->nPALElementSize = MM_SIZE_OF_PAL_32BITS;
    1499             :     else
    1500           4 :         pMMPolygonLayer->nPALElementSize = MM_SIZE_OF_PAL_64BITS;
    1501             : 
    1502          75 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    1503             :     {
    1504             :         // Universal polygon.
    1505          27 :         memset(pMMPolygonLayer->pPolHeader, 0,
    1506             :                sizeof(*pMMPolygonLayer->pPolHeader));
    1507          27 :         hMiraMonLayer->TopHeader.nElemCount = 1;
    1508             : 
    1509             :         // PAL
    1510          27 :         snprintf(pMMPolygonLayer->pszPALName,
    1511             :                  sizeof(pMMPolygonLayer->pszPALName), "%sP.~idx",
    1512             :                  hMiraMonLayer->pszSrcLayerName);
    1513             : 
    1514          27 :         if (nullptr ==
    1515          27 :             (pMMPolygonLayer->pFPAL = VSIFOpenL(pMMPolygonLayer->pszPALName,
    1516          27 :                                                 hMiraMonLayer->pszFlags)))
    1517             :         {
    1518           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
    1519             :                      "Error pMMPolygonLayer->pFPAL: Cannot open file %s.",
    1520           0 :                      pMMPolygonLayer->pszPALName);
    1521           0 :             return 1;
    1522             :         }
    1523          27 :         VSIFSeekL(pMMPolygonLayer->pFPAL, 0, SEEK_SET);
    1524             : 
    1525          27 :         if (MMInitFlush(&pMMPolygonLayer->FlushPAL, pMMPolygonLayer->pFPAL,
    1526             :                         MM_1MB, &pMMPolygonLayer->pPAL, 0, 0))
    1527           0 :             return 1;
    1528             :     }
    1529             : 
    1530             :     // MiraMon metadata
    1531             : 
    1532          75 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    1533             :     {
    1534          27 :         snprintf(hMiraMonLayer->MMPolygon.pszREL_LayerName,
    1535             :                  sizeof(hMiraMonLayer->MMPolygon.pszREL_LayerName), "%sP.rel",
    1536             :                  hMiraMonLayer->pszSrcLayerName);
    1537             :     }
    1538             :     else
    1539             :     {
    1540          48 :         CPLStrlcpy(hMiraMonLayer->MMPolygon.pszREL_LayerName,
    1541          48 :                    hMiraMonLayer->pszSrcLayerName,
    1542             :                    sizeof(hMiraMonLayer->MMPolygon.pszREL_LayerName));
    1543             : 
    1544          48 :         if (MMChangeFinalPartOfTheName(
    1545          48 :                 hMiraMonLayer->MMPolygon.pszREL_LayerName, MM_CPL_PATH_BUF_SIZE,
    1546             :                 ".pol", "P.rel"))
    1547           0 :             return 1;
    1548             :     }
    1549             : 
    1550          75 :     if (hMiraMonLayer->ReadOrWrite == MM_READING_MODE)
    1551             :     {
    1552             :         // This file has to exist and be the appropriate version.
    1553          48 :         if (MMCheck_REL_FILE(hMiraMonLayer->MMPolygon.pszREL_LayerName))
    1554           1 :             return 1;
    1555             :     }
    1556             : 
    1557          74 :     hMiraMonLayer->pszMainREL_LayerName =
    1558          74 :         hMiraMonLayer->MMPolygon.pszREL_LayerName;
    1559             : 
    1560             :     // MIRAMON DATA BASE
    1561          74 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    1562             :     {
    1563          27 :         snprintf(pMMPolygonLayer->MMAdmDB.pszExtDBFLayerName,
    1564             :                  sizeof(pMMPolygonLayer->MMAdmDB.pszExtDBFLayerName), "%sP.dbf",
    1565             :                  hMiraMonLayer->pszSrcLayerName);
    1566             :     }
    1567             :     else
    1568             :     {
    1569          47 :         CPLStrlcpy(pMMPolygonLayer->MMAdmDB.pszExtDBFLayerName,
    1570          47 :                    hMiraMonLayer->pszSrcLayerName,
    1571             :                    sizeof(pMMPolygonLayer->MMAdmDB.pszExtDBFLayerName));
    1572          47 :         if (MMChangeFinalPartOfTheName(
    1573          47 :                 pMMPolygonLayer->MMAdmDB.pszExtDBFLayerName,
    1574             :                 MM_CPL_PATH_BUF_SIZE, ".pol", "P.dbf"))
    1575           0 :             return 1;
    1576             :     }
    1577             : 
    1578          74 :     if (hMiraMonLayer->ReadOrWrite == MM_READING_MODE)
    1579             :     {
    1580          47 :         if (MM_ReadExtendedDBFHeader(hMiraMonLayer))
    1581           0 :             return 1;
    1582             :     }
    1583             : 
    1584          74 :     return 0;
    1585             : }
    1586             : 
    1587             : // The map file must be written in ANSI encoding; therefore, some
    1588             : // conversions are performed for strings that may originally
    1589             : // be in UTF-8.
    1590             : 
    1591         230 : int MMInitLayerByType(struct MiraMonVectLayerInfo *hMiraMonLayer)
    1592             : {
    1593             :     char *pszSrcLayerNameCP1252;
    1594             : 
    1595         230 :     if (!hMiraMonLayer)
    1596           0 :         return 1;
    1597             : 
    1598         230 :     pszSrcLayerNameCP1252 = CPLRecode(
    1599         230 :         CPLGetBasename(hMiraMonLayer->pszSrcLayerName), CPL_ENC_UTF8, "CP1252");
    1600             : 
    1601         230 :     if (hMiraMonLayer->eLT == MM_LayerType_Point ||
    1602         176 :         hMiraMonLayer->eLT == MM_LayerType_Point3d)
    1603             :     {
    1604          76 :         if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    1605             :         {
    1606          34 :             snprintf(hMiraMonLayer->MMPoint.pszLayerName,
    1607             :                      sizeof(hMiraMonLayer->MMPoint.pszLayerName), "%s.pnt",
    1608             :                      hMiraMonLayer->pszSrcLayerName);
    1609             :         }
    1610             :         else
    1611             :         {
    1612          42 :             CPLStrlcpy(hMiraMonLayer->MMPoint.pszLayerName,
    1613          42 :                        hMiraMonLayer->pszSrcLayerName,
    1614             :                        sizeof(hMiraMonLayer->MMPoint.pszLayerName));
    1615             :         }
    1616          76 :         if (hMiraMonLayer->MMMap && hMiraMonLayer->MMMap->fMMMap)
    1617             :         {
    1618             : 
    1619          24 :             hMiraMonLayer->MMMap->nNumberOfLayers++;
    1620          24 :             VSIFPrintfL(hMiraMonLayer->MMMap->fMMMap, "[VECTOR_%d]\n",
    1621          24 :                         hMiraMonLayer->MMMap->nNumberOfLayers);
    1622             : 
    1623          24 :             VSIFPrintfL(hMiraMonLayer->MMMap->fMMMap, "Fitxer=%s.pnt\n",
    1624             :                         pszSrcLayerNameCP1252
    1625             :                             ? pszSrcLayerNameCP1252
    1626           0 :                             : CPLGetBasename(hMiraMonLayer->pszSrcLayerName));
    1627             :         }
    1628             : 
    1629          76 :         if (MMInitPointLayer(hMiraMonLayer))
    1630             :         {
    1631             :             // Error specified inside the function
    1632           2 :             CPLFree(pszSrcLayerNameCP1252);
    1633           2 :             return 1;
    1634             :         }
    1635          74 :         CPLFree(pszSrcLayerNameCP1252);
    1636          74 :         return 0;
    1637             :     }
    1638         154 :     if (hMiraMonLayer->eLT == MM_LayerType_Arc ||
    1639         111 :         hMiraMonLayer->eLT == MM_LayerType_Arc3d)
    1640             :     {
    1641          62 :         struct MiraMonArcLayer *pMMArcLayer = &hMiraMonLayer->MMArc;
    1642             : 
    1643          62 :         if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    1644             :         {
    1645          31 :             snprintf(pMMArcLayer->pszLayerName,
    1646             :                      sizeof(pMMArcLayer->pszLayerName), "%s.arc",
    1647             :                      hMiraMonLayer->pszSrcLayerName);
    1648             :         }
    1649             :         else
    1650             :         {
    1651          31 :             CPLStrlcpy(pMMArcLayer->pszLayerName,
    1652          31 :                        hMiraMonLayer->pszSrcLayerName,
    1653             :                        sizeof(pMMArcLayer->pszLayerName));
    1654             :         }
    1655             : 
    1656          62 :         if (hMiraMonLayer->MMMap && hMiraMonLayer->MMMap->fMMMap)
    1657             :         {
    1658          26 :             hMiraMonLayer->MMMap->nNumberOfLayers++;
    1659          26 :             VSIFPrintfL(hMiraMonLayer->MMMap->fMMMap, "[VECTOR_%d]\n",
    1660          26 :                         hMiraMonLayer->MMMap->nNumberOfLayers);
    1661          26 :             VSIFPrintfL(hMiraMonLayer->MMMap->fMMMap, "Fitxer=%s.arc\n",
    1662             :                         pszSrcLayerNameCP1252
    1663             :                             ? pszSrcLayerNameCP1252
    1664           0 :                             : CPLGetBasename(hMiraMonLayer->pszSrcLayerName));
    1665             :         }
    1666             : 
    1667          62 :         if (MMInitArcLayer(hMiraMonLayer))
    1668             :         {
    1669             :             // Error specified inside the function
    1670           2 :             CPLFree(pszSrcLayerNameCP1252);
    1671           2 :             return 1;
    1672             :         }
    1673          60 :         CPLFree(pszSrcLayerNameCP1252);
    1674          60 :         return 0;
    1675             :     }
    1676          92 :     if (hMiraMonLayer->eLT == MM_LayerType_Pol ||
    1677          29 :         hMiraMonLayer->eLT == MM_LayerType_Pol3d)
    1678          71 :     {
    1679          75 :         struct MiraMonPolygonLayer *pMMPolygonLayer = &hMiraMonLayer->MMPolygon;
    1680             : 
    1681          75 :         if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    1682             :         {
    1683          27 :             snprintf(pMMPolygonLayer->pszLayerName,
    1684             :                      sizeof(pMMPolygonLayer->pszLayerName), "%s.pol",
    1685             :                      hMiraMonLayer->pszSrcLayerName);
    1686             :         }
    1687             :         else
    1688             :         {
    1689          48 :             CPLStrlcpy(pMMPolygonLayer->pszLayerName,
    1690          48 :                        hMiraMonLayer->pszSrcLayerName,
    1691             :                        sizeof(pMMPolygonLayer->pszLayerName));
    1692             :         }
    1693             : 
    1694          75 :         if (hMiraMonLayer->MMMap && hMiraMonLayer->MMMap->fMMMap)
    1695             :         {
    1696          20 :             hMiraMonLayer->MMMap->nNumberOfLayers++;
    1697          20 :             VSIFPrintfL(hMiraMonLayer->MMMap->fMMMap, "[VECTOR_%d]\n",
    1698          20 :                         hMiraMonLayer->MMMap->nNumberOfLayers);
    1699          20 :             VSIFPrintfL(hMiraMonLayer->MMMap->fMMMap, "Fitxer=%s.pol\n",
    1700             :                         pszSrcLayerNameCP1252
    1701             :                             ? pszSrcLayerNameCP1252
    1702           0 :                             : CPLGetBasename(hMiraMonLayer->pszSrcLayerName));
    1703             :         }
    1704             : 
    1705          75 :         if (MMInitPolygonLayer(hMiraMonLayer))
    1706             :         {
    1707             :             // Error specified inside the function
    1708           1 :             CPLFree(pszSrcLayerNameCP1252);
    1709           1 :             return 1;
    1710             :         }
    1711             : 
    1712          74 :         if (hMiraMonLayer->ReadOrWrite == MM_READING_MODE)
    1713             :         {
    1714             :             char *pszArcLayerName;
    1715             :             const char *pszExt;
    1716             :             // StringLine associated to the polygon
    1717          47 :             pszArcLayerName = MMReturnValueFromSectionINIFile(
    1718          47 :                 pMMPolygonLayer->pszREL_LayerName,
    1719             :                 SECTION_OVVW_ASPECTES_TECNICS, KEY_ArcSource);
    1720          47 :             if (pszArcLayerName)
    1721             :             {
    1722          46 :                 MM_RemoveInitial_and_FinalQuotationMarks(pszArcLayerName);
    1723             : 
    1724             :                 // If extension is not specified ".arc" will be used
    1725          46 :                 pszExt = CPLGetExtension(pszArcLayerName);
    1726          46 :                 if (MMIsEmptyString(pszExt))
    1727             :                 {
    1728             :                     char *pszArcLayerNameAux =
    1729           2 :                         VSICalloc(1, strlen(pszArcLayerName) + 5);
    1730           2 :                     if (!pszArcLayerNameAux)
    1731             :                     {
    1732           0 :                         CPLError(CE_Failure, CPLE_OutOfMemory,
    1733             :                                  "Memory error in MiraMon "
    1734             :                                  "driver (MMInitLayerByType())");
    1735           0 :                         VSIFree(pszArcLayerName);
    1736           0 :                         CPLFree(pszSrcLayerNameCP1252);
    1737           0 :                         return 1;
    1738             :                     }
    1739           2 :                     snprintf(pszArcLayerNameAux, strlen(pszArcLayerName) + 5,
    1740             :                              "%s.arc", pszArcLayerName);
    1741             : 
    1742           2 :                     VSIFree(pszArcLayerName);
    1743           2 :                     pszArcLayerName = pszArcLayerNameAux;
    1744             :                 }
    1745             : 
    1746          46 :                 CPLStrlcpy(
    1747          46 :                     pMMPolygonLayer->MMArc.pszLayerName,
    1748          46 :                     CPLFormFilename(CPLGetPath(hMiraMonLayer->pszSrcLayerName),
    1749             :                                     pszArcLayerName, ""),
    1750             :                     sizeof(pMMPolygonLayer->MMArc.pszLayerName));
    1751             : 
    1752          46 :                 VSIFree(pszArcLayerName);
    1753             :             }
    1754             :             else
    1755             :             {
    1756             :                 // There is no arc layer on the metada file
    1757           1 :                 CPLError(CE_Failure, CPLE_OpenFailed,
    1758             :                          "Error reading the ARC file in the metadata file %s.",
    1759           1 :                          pMMPolygonLayer->pszREL_LayerName);
    1760           1 :                 CPLFree(pszSrcLayerNameCP1252);
    1761           1 :                 return 1;
    1762             :             }
    1763             : 
    1764          46 :             if (nullptr == (hMiraMonLayer->MMPolygon.MMArc.pF =
    1765          46 :                                 VSIFOpenL(pMMPolygonLayer->MMArc.pszLayerName,
    1766          46 :                                           hMiraMonLayer->pszFlags)))
    1767             :             {
    1768           2 :                 CPLError(CE_Failure, CPLE_OpenFailed,
    1769             :                          "Error pMMPolygonLayer.MMArc.pF: Cannot open file %s.",
    1770           2 :                          pMMPolygonLayer->MMArc.pszLayerName);
    1771           2 :                 CPLFree(pszSrcLayerNameCP1252);
    1772           2 :                 return 1;
    1773             :             }
    1774             : 
    1775          44 :             if (MMReadHeader(hMiraMonLayer->MMPolygon.MMArc.pF,
    1776             :                              &hMiraMonLayer->MMPolygon.TopArcHeader))
    1777             :             {
    1778           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
    1779             :                          "Error reading the format in file %s.",
    1780           0 :                          pMMPolygonLayer->MMArc.pszLayerName);
    1781           0 :                 CPLFree(pszSrcLayerNameCP1252);
    1782           0 :                 return 1;
    1783             :             }
    1784             : 
    1785          44 :             if (MMReadPHPolygonSection(hMiraMonLayer))
    1786             :             {
    1787           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
    1788             :                          "Error reading the format in file %s.",
    1789           0 :                          pMMPolygonLayer->MMArc.pszLayerName);
    1790           0 :                 CPLFree(pszSrcLayerNameCP1252);
    1791           0 :                 return 1;
    1792             :             }
    1793             : 
    1794          44 :             fclose_and_nullify(&hMiraMonLayer->MMPolygon.MMArc.pF);
    1795             :         }
    1796             :         else
    1797             :         {
    1798             :             // Creating the stringLine file associated to the polygon
    1799          27 :             snprintf(pMMPolygonLayer->MMArc.pszLayerName,
    1800             :                      sizeof(pMMPolygonLayer->MMArc.pszLayerName), "%s.arc",
    1801             :                      hMiraMonLayer->pszSrcLayerName);
    1802             :         }
    1803             : 
    1804          71 :         if (MMInitArcLayer(hMiraMonLayer))
    1805             :         {
    1806             :             // Error specified inside the function
    1807           0 :             CPLFree(pszSrcLayerNameCP1252);
    1808           0 :             return 1;
    1809             :         }
    1810             : 
    1811             :         // Polygon is 3D if Arc is 3D, by definition.
    1812          71 :         hMiraMonLayer->TopHeader.bIs3d =
    1813          71 :             hMiraMonLayer->MMPolygon.TopArcHeader.bIs3d;
    1814             : 
    1815          71 :         if (hMiraMonLayer->LayerVersion == MM_32BITS_VERSION)
    1816          67 :             MMSet1_1Version(&pMMPolygonLayer->TopArcHeader);
    1817             :         else
    1818           4 :             MMSet2_0Version(&pMMPolygonLayer->TopArcHeader);
    1819             :     }
    1820          17 :     else if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    1821             :     {
    1822             :         // Trying to get DBF information
    1823          17 :         snprintf(hMiraMonLayer->MMAdmDBWriting.pszExtDBFLayerName,
    1824             :                  sizeof(hMiraMonLayer->MMAdmDBWriting.pszExtDBFLayerName),
    1825             :                  "%s.dbf", hMiraMonLayer->pszSrcLayerName);
    1826             :     }
    1827             : 
    1828          88 :     CPLFree(pszSrcLayerNameCP1252);
    1829          88 :     return 0;
    1830             : }
    1831             : 
    1832         340 : int MMInitLayer(struct MiraMonVectLayerInfo *hMiraMonLayer,
    1833             :                 const char *pzFileName, int LayerVersion, char nMMRecode,
    1834             :                 char nMMLanguage, struct MiraMonDataBase *pLayerDB,
    1835             :                 MM_BOOLEAN ReadOrWrite, struct MiraMonVectMapInfo *MMMap)
    1836             : {
    1837         340 :     if (!hMiraMonLayer)
    1838           0 :         return 1;
    1839             : 
    1840             :     // Some variables must be initialized
    1841         340 :     MM_FillFieldDescriptorByLanguage();
    1842             : 
    1843         340 :     memset(hMiraMonLayer, 0, sizeof(*hMiraMonLayer));
    1844             : 
    1845             :     //hMiraMonLayer->Version = MM_VECTOR_LAYER_LAST_VERSION;
    1846             : 
    1847         340 :     hMiraMonLayer->ReadOrWrite = ReadOrWrite;
    1848         340 :     hMiraMonLayer->MMMap = MMMap;
    1849             : 
    1850             :     // Don't free in destructor
    1851         340 :     hMiraMonLayer->pLayerDB = pLayerDB;
    1852             : 
    1853             :     // Opening mode
    1854         340 :     strcpy(hMiraMonLayer->pszFlags, "wb+");
    1855             : 
    1856         340 :     if (LayerVersion == MM_UNKNOWN_VERSION)
    1857             :     {
    1858           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    1859             :                  "Unknown version in MiraMon driver.");
    1860           0 :         return 1;
    1861             :     }
    1862         340 :     if (LayerVersion == MM_LAST_VERSION)
    1863             :     {
    1864           0 :         MMSet1_1Version(&hMiraMonLayer->TopHeader);
    1865           0 :         hMiraMonLayer->nHeaderDiskSize = MM_HEADER_SIZE_64_BITS;
    1866           0 :         hMiraMonLayer->LayerVersion = MM_64BITS_VERSION;
    1867             :     }
    1868         340 :     else if (LayerVersion == MM_32BITS_VERSION)
    1869             :     {
    1870         316 :         MMSet1_1Version(&hMiraMonLayer->TopHeader);
    1871         316 :         hMiraMonLayer->nHeaderDiskSize = MM_HEADER_SIZE_32_BITS;
    1872         316 :         hMiraMonLayer->LayerVersion = MM_32BITS_VERSION;
    1873             :     }
    1874             :     else
    1875             :     {
    1876          24 :         MMSet2_0Version(&hMiraMonLayer->TopHeader);
    1877          24 :         hMiraMonLayer->nHeaderDiskSize = MM_HEADER_SIZE_64_BITS;
    1878          24 :         hMiraMonLayer->LayerVersion = MM_64BITS_VERSION;
    1879             :     }
    1880             : 
    1881         340 :     hMiraMonLayer->pszSrcLayerName = CPLStrdup(pzFileName);
    1882         340 :     hMiraMonLayer->szLayerTitle = CPLStrdup(CPLGetFilename(pzFileName));
    1883             : 
    1884         340 :     if (!hMiraMonLayer->bIsBeenInit &&
    1885         340 :         hMiraMonLayer->eLT != MM_LayerType_Unknown)
    1886             :     {
    1887           0 :         if (MMInitLayerByType(hMiraMonLayer))
    1888             :         {
    1889             :             // Error specified inside the function
    1890           0 :             return 1;
    1891             :         }
    1892           0 :         hMiraMonLayer->bIsBeenInit = 1;
    1893             :     }
    1894             : 
    1895             :     // If more nNumStringToOperate is needed, it'll be increased.
    1896         340 :     hMiraMonLayer->nNumStringToOperate = 0;
    1897         340 :     if (MMResizeStringToOperateIfNeeded(hMiraMonLayer, 500))
    1898             :     {
    1899           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    1900             :                  "Memory error in MiraMon "
    1901             :                  "driver (MMInitLayer())");
    1902           0 :         return 1;
    1903             :     }
    1904             : 
    1905         340 :     hMiraMonLayer->nMMLanguage = nMMLanguage;
    1906             : 
    1907         340 :     if (nMMRecode == MM_RECODE_UTF8)
    1908           4 :         hMiraMonLayer->nCharSet = MM_JOC_CARAC_UTF8_DBF;
    1909             :     else  //if(nMMRecode==MM_RECODE_ANSI)
    1910         336 :         hMiraMonLayer->nCharSet = MM_JOC_CARAC_ANSI_DBASE;
    1911         340 :     return 0;
    1912             : }
    1913             : 
    1914             : /* -------------------------------------------------------------------- */
    1915             : /*      Layer Functions: Closing MiraMon layers                         */
    1916             : /* -------------------------------------------------------------------- */
    1917          92 : static int MMClose3DSectionLayer(struct MiraMonVectLayerInfo *hMiraMonLayer,
    1918             :                                  MM_INTERNAL_FID nElements, VSILFILE *pF,
    1919             :                                  VSILFILE **pF3d, const char *pszF3d,
    1920             :                                  struct MM_ZSection *pZSection,
    1921             :                                  MM_FILE_OFFSET FinalOffset)
    1922             : {
    1923          92 :     int ret_code = 1;
    1924          92 :     if (!hMiraMonLayer)
    1925           0 :         return 1;
    1926             : 
    1927             :     // Avoid closing when it has no sense. But it's not an error.
    1928             :     // Just return elegantly.
    1929          92 :     if (!pF || !pF3d || !(*pF3d) || !pszF3d || !pZSection)
    1930           0 :         return 0;
    1931             : 
    1932          92 :     if (hMiraMonLayer->bIsReal3d)
    1933             :     {
    1934          32 :         pZSection->ZSectionOffset = FinalOffset;
    1935          32 :         if (MMWriteZSection(pF, pZSection))
    1936           0 :             goto end_label;
    1937             : 
    1938             :         // Header 3D. Writes it after header
    1939          32 :         if (MMWriteZDescriptionHeaders(hMiraMonLayer, pF, nElements, pZSection))
    1940           0 :             goto end_label;
    1941             : 
    1942             :         // ZL section
    1943          32 :         pZSection->FlushZL.SizeOfBlockToBeSaved = 0;
    1944          32 :         if (MMAppendBlockToBuffer(&pZSection->FlushZL))
    1945           0 :             goto end_label;
    1946             : 
    1947          32 :         if (MMMoveFromFileToFile(*pF3d, pF, &pZSection->ZSectionOffset))
    1948           0 :             goto end_label;
    1949             :     }
    1950             : 
    1951          92 :     ret_code = 0;
    1952          92 : end_label:
    1953          92 :     fclose_and_nullify(pF3d);
    1954          92 :     if (pszF3d && *pszF3d != '\0')
    1955          92 :         VSIUnlink(pszF3d);
    1956             : 
    1957          92 :     return ret_code;
    1958             : }
    1959             : 
    1960          76 : static int MMClosePointLayer(struct MiraMonVectLayerInfo *hMiraMonLayer)
    1961             : {
    1962          76 :     int ret_code = 1;
    1963          76 :     if (!hMiraMonLayer)
    1964           0 :         return 1;
    1965             : 
    1966          76 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    1967             :     {
    1968          34 :         hMiraMonLayer->nFinalElemCount = hMiraMonLayer->TopHeader.nElemCount;
    1969          34 :         hMiraMonLayer->TopHeader.bIs3d = hMiraMonLayer->bIsReal3d;
    1970             : 
    1971          34 :         if (MMWriteHeader(hMiraMonLayer->MMPoint.pF, &hMiraMonLayer->TopHeader))
    1972             :         {
    1973           0 :             CPLError(CE_Failure, CPLE_NoWriteAccess, "Error writing to file %s",
    1974           0 :                      hMiraMonLayer->MMPoint.pszLayerName);
    1975           0 :             goto end_label;
    1976             :         }
    1977          34 :         hMiraMonLayer->OffsetCheck = hMiraMonLayer->nHeaderDiskSize;
    1978             : 
    1979             :         // TL Section
    1980          34 :         hMiraMonLayer->MMPoint.FlushTL.SizeOfBlockToBeSaved = 0;
    1981          34 :         if (MMAppendBlockToBuffer(&hMiraMonLayer->MMPoint.FlushTL))
    1982             :         {
    1983           0 :             CPLError(CE_Failure, CPLE_NoWriteAccess, "Error writing to file %s",
    1984           0 :                      hMiraMonLayer->MMPoint.pszLayerName);
    1985           0 :             goto end_label;
    1986             :         }
    1987          34 :         if (MMMoveFromFileToFile(hMiraMonLayer->MMPoint.pFTL,
    1988             :                                  hMiraMonLayer->MMPoint.pF,
    1989             :                                  &hMiraMonLayer->OffsetCheck))
    1990             :         {
    1991           0 :             CPLError(CE_Failure, CPLE_NoWriteAccess, "Error writing to file %s",
    1992           0 :                      hMiraMonLayer->MMPoint.pszLayerName);
    1993           0 :             goto end_label;
    1994             :         }
    1995             : 
    1996          34 :         fclose_and_nullify(&hMiraMonLayer->MMPoint.pFTL);
    1997             : 
    1998          34 :         if (*hMiraMonLayer->MMPoint.pszTLName != '\0')
    1999          34 :             VSIUnlink(hMiraMonLayer->MMPoint.pszTLName);
    2000             : 
    2001          34 :         if (MMClose3DSectionLayer(
    2002             :                 hMiraMonLayer, hMiraMonLayer->TopHeader.nElemCount,
    2003             :                 hMiraMonLayer->MMPoint.pF, &hMiraMonLayer->MMPoint.pF3d,
    2004          34 :                 hMiraMonLayer->MMPoint.psz3DLayerName,
    2005             :                 &hMiraMonLayer->MMPoint.pZSection, hMiraMonLayer->OffsetCheck))
    2006             :         {
    2007           0 :             CPLError(CE_Failure, CPLE_NoWriteAccess, "Error writing to file %s",
    2008           0 :                      hMiraMonLayer->MMPoint.pszLayerName);
    2009           0 :             goto end_label;
    2010             :         }
    2011             :     }
    2012             : 
    2013          76 :     ret_code = 0;
    2014          76 : end_label:
    2015          76 :     fclose_and_nullify(&hMiraMonLayer->MMPoint.pF);
    2016          76 :     fclose_and_nullify(&hMiraMonLayer->MMPoint.pF3d);
    2017          76 :     return ret_code;
    2018             : }
    2019             : 
    2020         137 : static int MMCloseNodeLayer(struct MiraMonVectLayerInfo *hMiraMonLayer)
    2021             : {
    2022         137 :     int ret_code = 1;
    2023             :     struct MiraMonArcLayer *pMMArcLayer;
    2024             : 
    2025         137 :     if (!hMiraMonLayer)
    2026           0 :         return 1;
    2027             : 
    2028         137 :     if (hMiraMonLayer->bIsPolygon)
    2029          75 :         pMMArcLayer = &hMiraMonLayer->MMPolygon.MMArc;
    2030             :     else
    2031          62 :         pMMArcLayer = &hMiraMonLayer->MMArc;
    2032             : 
    2033         137 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    2034             :     {
    2035          58 :         hMiraMonLayer->TopHeader.bIs3d = hMiraMonLayer->bIsReal3d;
    2036             : 
    2037          58 :         if (MMWriteHeader(pMMArcLayer->MMNode.pF, &pMMArcLayer->TopNodeHeader))
    2038           0 :             goto end_label;
    2039          58 :         hMiraMonLayer->OffsetCheck = hMiraMonLayer->nHeaderDiskSize;
    2040             : 
    2041             :         // NH Section
    2042          58 :         if (MMWriteNHNodeSection(hMiraMonLayer, hMiraMonLayer->nHeaderDiskSize))
    2043           0 :             goto end_label;
    2044             : 
    2045             :         // NL Section
    2046          58 :         pMMArcLayer->MMNode.FlushNL.SizeOfBlockToBeSaved = 0;
    2047          58 :         if (MMAppendBlockToBuffer(&pMMArcLayer->MMNode.FlushNL))
    2048           0 :             goto end_label;
    2049          58 :         if (MMMoveFromFileToFile(pMMArcLayer->MMNode.pFNL,
    2050             :                                  pMMArcLayer->MMNode.pF,
    2051             :                                  &hMiraMonLayer->OffsetCheck))
    2052           0 :             goto end_label;
    2053             : 
    2054          58 :         fclose_and_nullify(&pMMArcLayer->MMNode.pFNL);
    2055          58 :         if (*pMMArcLayer->MMNode.pszNLName != '\0')
    2056          58 :             VSIUnlink(pMMArcLayer->MMNode.pszNLName);
    2057             :     }
    2058             : 
    2059         137 :     ret_code = 0;
    2060         137 : end_label:
    2061         137 :     fclose_and_nullify(&pMMArcLayer->MMNode.pFNL);
    2062             : 
    2063         137 :     fclose_and_nullify(&pMMArcLayer->MMNode.pF);
    2064             : 
    2065         137 :     return ret_code;
    2066             : }
    2067             : 
    2068         137 : static int MMCloseArcLayer(struct MiraMonVectLayerInfo *hMiraMonLayer)
    2069             : {
    2070         137 :     int ret_code = 0;
    2071             :     struct MiraMonArcLayer *pMMArcLayer;
    2072             :     struct MM_TH *pArcTopHeader;
    2073             : 
    2074         137 :     if (!hMiraMonLayer)
    2075           0 :         return 1;
    2076             : 
    2077         137 :     if (hMiraMonLayer->bIsPolygon)
    2078             :     {
    2079          75 :         pMMArcLayer = &hMiraMonLayer->MMPolygon.MMArc;
    2080          75 :         pArcTopHeader = &hMiraMonLayer->MMPolygon.TopArcHeader;
    2081             :     }
    2082             :     else
    2083             :     {
    2084          62 :         pMMArcLayer = &hMiraMonLayer->MMArc;
    2085          62 :         pArcTopHeader = &hMiraMonLayer->TopHeader;
    2086             :     }
    2087             : 
    2088         137 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    2089             :     {
    2090          58 :         hMiraMonLayer->nFinalElemCount = pArcTopHeader->nElemCount;
    2091          58 :         pArcTopHeader->bIs3d = hMiraMonLayer->bIsReal3d;
    2092             : 
    2093          58 :         if (MMWriteHeader(pMMArcLayer->pF, pArcTopHeader))
    2094             :         {
    2095           0 :             CPLError(CE_Failure, CPLE_NoWriteAccess, "Error writing to file %s",
    2096           0 :                      pMMArcLayer->pszLayerName);
    2097           0 :             goto end_label;
    2098             :         }
    2099          58 :         hMiraMonLayer->OffsetCheck = hMiraMonLayer->nHeaderDiskSize;
    2100             : 
    2101             :         // AH Section
    2102          58 :         if (MMWriteAHArcSection(hMiraMonLayer, hMiraMonLayer->OffsetCheck))
    2103             :         {
    2104           0 :             CPLError(CE_Failure, CPLE_NoWriteAccess, "Error writing to file %s",
    2105           0 :                      pMMArcLayer->pszLayerName);
    2106           0 :             goto end_label;
    2107             :         }
    2108             : 
    2109             :         // AL Section
    2110          58 :         pMMArcLayer->FlushAL.SizeOfBlockToBeSaved = 0;
    2111          58 :         if (MMAppendBlockToBuffer(&pMMArcLayer->FlushAL))
    2112             :         {
    2113           0 :             CPLError(CE_Failure, CPLE_NoWriteAccess, "Error writing to file %s",
    2114           0 :                      pMMArcLayer->pszLayerName);
    2115           0 :             goto end_label;
    2116             :         }
    2117          58 :         if (MMMoveFromFileToFile(pMMArcLayer->pFAL, pMMArcLayer->pF,
    2118             :                                  &hMiraMonLayer->OffsetCheck))
    2119             :         {
    2120           0 :             CPLError(CE_Failure, CPLE_NoWriteAccess, "Error writing to file %s",
    2121           0 :                      pMMArcLayer->pszLayerName);
    2122           0 :             goto end_label;
    2123             :         }
    2124          58 :         fclose_and_nullify(&pMMArcLayer->pFAL);
    2125             : 
    2126          58 :         if (*pMMArcLayer->pszALName != '\0')
    2127          58 :             VSIUnlink(pMMArcLayer->pszALName);
    2128             : 
    2129             :         // 3D Section
    2130          58 :         if (MMClose3DSectionLayer(
    2131             :                 hMiraMonLayer, pArcTopHeader->nElemCount, pMMArcLayer->pF,
    2132          58 :                 &pMMArcLayer->pF3d, pMMArcLayer->psz3DLayerName,
    2133             :                 &pMMArcLayer->pZSection, hMiraMonLayer->OffsetCheck))
    2134             :         {
    2135           0 :             CPLError(CE_Failure, CPLE_NoWriteAccess, "Error writing to file %s",
    2136           0 :                      pMMArcLayer->pszLayerName);
    2137           0 :             goto end_label;
    2138             :         }
    2139             :     }
    2140             : 
    2141         137 :     ret_code = 0;
    2142         137 : end_label:
    2143         137 :     fclose_and_nullify(&pMMArcLayer->pF);
    2144         137 :     fclose_and_nullify(&pMMArcLayer->pF3d);
    2145             : 
    2146         137 :     fclose_and_nullify(&pMMArcLayer->pFAL);
    2147             : 
    2148         137 :     if (MMCloseNodeLayer(hMiraMonLayer))
    2149           0 :         ret_code = 1;
    2150             : 
    2151         137 :     return ret_code;
    2152             : }
    2153             : 
    2154          75 : static int MMClosePolygonLayer(struct MiraMonVectLayerInfo *hMiraMonLayer)
    2155             : {
    2156          75 :     int ret_code = 0;
    2157             :     struct MiraMonPolygonLayer *pMMPolygonLayer;
    2158             : 
    2159          75 :     if (!hMiraMonLayer)
    2160           0 :         return 1;
    2161             : 
    2162          75 :     pMMPolygonLayer = &hMiraMonLayer->MMPolygon;
    2163             : 
    2164          75 :     MMCloseArcLayer(hMiraMonLayer);
    2165             : 
    2166          75 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    2167             :     {
    2168          27 :         hMiraMonLayer->nFinalElemCount = hMiraMonLayer->TopHeader.nElemCount;
    2169          27 :         hMiraMonLayer->TopHeader.bIs3d = hMiraMonLayer->bIsReal3d;
    2170             : 
    2171          27 :         if (MMWriteHeader(pMMPolygonLayer->pF, &hMiraMonLayer->TopHeader))
    2172             :         {
    2173           0 :             CPLError(CE_Failure, CPLE_NoWriteAccess, "Error writing to file %s",
    2174           0 :                      pMMPolygonLayer->pszLayerName);
    2175           0 :             goto end_label;
    2176             :         }
    2177          27 :         hMiraMonLayer->OffsetCheck = hMiraMonLayer->nHeaderDiskSize;
    2178             : 
    2179             :         // PS Section
    2180          27 :         pMMPolygonLayer->FlushPS.SizeOfBlockToBeSaved = 0;
    2181          27 :         if (MMAppendBlockToBuffer(&pMMPolygonLayer->FlushPS))
    2182             :         {
    2183           0 :             CPLError(CE_Failure, CPLE_NoWriteAccess, "Error writing to file %s",
    2184           0 :                      pMMPolygonLayer->pszLayerName);
    2185           0 :             goto end_label;
    2186             :         }
    2187          27 :         if (MMMoveFromFileToFile(pMMPolygonLayer->pFPS, pMMPolygonLayer->pF,
    2188             :                                  &hMiraMonLayer->OffsetCheck))
    2189             :         {
    2190           0 :             CPLError(CE_Failure, CPLE_NoWriteAccess, "Error writing to file %s",
    2191           0 :                      pMMPolygonLayer->pszLayerName);
    2192           0 :             goto end_label;
    2193             :         }
    2194             : 
    2195          27 :         fclose_and_nullify(&pMMPolygonLayer->pFPS);
    2196          27 :         if (*pMMPolygonLayer->pszPSName != '\0')
    2197          27 :             VSIUnlink(pMMPolygonLayer->pszPSName);
    2198             : 
    2199             :         // AH Section
    2200          27 :         if (MMWritePHPolygonSection(hMiraMonLayer, hMiraMonLayer->OffsetCheck))
    2201             :         {
    2202           0 :             CPLError(CE_Failure, CPLE_NoWriteAccess, "Error writing to file %s",
    2203           0 :                      pMMPolygonLayer->pszLayerName);
    2204           0 :             goto end_label;
    2205             :         }
    2206             : 
    2207             :         // PAL Section
    2208          27 :         pMMPolygonLayer->FlushPAL.SizeOfBlockToBeSaved = 0;
    2209          27 :         if (MMAppendBlockToBuffer(&pMMPolygonLayer->FlushPAL))
    2210             :         {
    2211           0 :             CPLError(CE_Failure, CPLE_NoWriteAccess, "Error writing to file %s",
    2212           0 :                      pMMPolygonLayer->pszLayerName);
    2213           0 :             goto end_label;
    2214             :         }
    2215          27 :         if (MMMoveFromFileToFile(pMMPolygonLayer->pFPAL, pMMPolygonLayer->pF,
    2216             :                                  &hMiraMonLayer->OffsetCheck))
    2217             :         {
    2218           0 :             CPLError(CE_Failure, CPLE_NoWriteAccess, "Error writing to file %s",
    2219           0 :                      pMMPolygonLayer->pszLayerName);
    2220           0 :             goto end_label;
    2221             :         }
    2222          27 :         fclose_and_nullify(&pMMPolygonLayer->pFPAL);
    2223             : 
    2224          27 :         if (*pMMPolygonLayer->pszPALName != '\0')
    2225          27 :             VSIUnlink(pMMPolygonLayer->pszPALName);
    2226             :     }
    2227             : 
    2228          75 :     ret_code = 0;
    2229             : 
    2230          75 : end_label:
    2231          75 :     fclose_and_nullify(&pMMPolygonLayer->pF);
    2232             : 
    2233          75 :     fclose_and_nullify(&pMMPolygonLayer->pFPAL);
    2234             : 
    2235          75 :     return ret_code;
    2236             : }
    2237             : 
    2238         230 : int MMCloseLayer(struct MiraMonVectLayerInfo *hMiraMonLayer)
    2239             : {
    2240         230 :     int ret_code = 0;
    2241             :     //CheckMMVectorLayerVersion(hMiraMonLayer, 1)
    2242             : 
    2243         230 :     if (!hMiraMonLayer)
    2244           0 :         return 0;
    2245             : 
    2246         230 :     if (hMiraMonLayer->bIsPoint)
    2247             :     {
    2248          76 :         ret_code = MMClosePointLayer(hMiraMonLayer);
    2249             :     }
    2250         154 :     else if (hMiraMonLayer->bIsArc && !hMiraMonLayer->bIsPolygon)
    2251             :     {
    2252          62 :         ret_code = MMCloseArcLayer(hMiraMonLayer);
    2253             :     }
    2254          92 :     else if (hMiraMonLayer->bIsPolygon)
    2255             :     {
    2256          75 :         ret_code = MMClosePolygonLayer(hMiraMonLayer);
    2257             :     }
    2258          17 :     else if (hMiraMonLayer->bIsDBF)
    2259             :     {
    2260             :         // If no geometry, remove all created files
    2261          17 :         if (hMiraMonLayer->pszSrcLayerName)
    2262          17 :             VSIUnlink(hMiraMonLayer->pszSrcLayerName);
    2263          17 :         if (hMiraMonLayer->szLayerTitle)
    2264          17 :             VSIUnlink(hMiraMonLayer->szLayerTitle);
    2265             :     }
    2266             : 
    2267             :     // MiraMon metadata files
    2268         230 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    2269             :     {
    2270         109 :         if (MMWriteVectorMetadata(hMiraMonLayer))
    2271             :         {
    2272           0 :             CPLError(CE_Failure, CPLE_NoWriteAccess,
    2273             :                      "Some error writing in metadata file of the layer");
    2274           0 :             ret_code = 1;
    2275             :         }
    2276             :     }
    2277             : 
    2278             :     // MiraMon database files
    2279         230 :     if (MMCloseMMBD_XP(hMiraMonLayer))
    2280             :     {
    2281           0 :         CPLError(CE_Failure, CPLE_NoWriteAccess,
    2282             :                  "Some error writing in DBF file of the layer");
    2283           0 :         ret_code = 1;
    2284             :     }
    2285         230 :     return ret_code;
    2286             : }
    2287             : 
    2288             : /* -------------------------------------------------------------------- */
    2289             : /*      Layer Functions: Destroying (allocated memory)                  */
    2290             : /* -------------------------------------------------------------------- */
    2291         425 : static void MMDestroyMMAdmDB(struct MMAdmDatabase *pMMAdmDB)
    2292             : {
    2293         425 :     if (pMMAdmDB->pRecList)
    2294             :     {
    2295         150 :         VSIFree(pMMAdmDB->pRecList);
    2296         150 :         pMMAdmDB->pRecList = nullptr;
    2297             :     }
    2298             : 
    2299         425 :     if (pMMAdmDB->szRecordOnCourse)
    2300             :     {
    2301         150 :         VSIFree(pMMAdmDB->szRecordOnCourse);
    2302         150 :         pMMAdmDB->szRecordOnCourse = nullptr;
    2303         150 :         pMMAdmDB->nNumRecordOnCourse = 0;
    2304             :     }
    2305         425 : }
    2306             : 
    2307          76 : static int MMDestroyPointLayer(struct MiraMonVectLayerInfo *hMiraMonLayer)
    2308             : {
    2309          76 :     if (!hMiraMonLayer)
    2310           0 :         return 1;
    2311             : 
    2312          76 :     if (hMiraMonLayer->MMPoint.pTL)
    2313             :     {
    2314          34 :         VSIFree(hMiraMonLayer->MMPoint.pTL);
    2315          34 :         hMiraMonLayer->MMPoint.pTL = nullptr;
    2316             :     }
    2317             : 
    2318          76 :     MMDestroyZSectionDescription(&hMiraMonLayer->MMPoint.pZSection);
    2319          76 :     MMDestroyMMAdmDB(&hMiraMonLayer->MMPoint.MMAdmDB);
    2320             : 
    2321          76 :     return 0;
    2322             : }
    2323             : 
    2324         137 : static int MMDestroyNodeLayer(struct MiraMonVectLayerInfo *hMiraMonLayer)
    2325             : {
    2326             :     struct MiraMonArcLayer *pMMArcLayer;
    2327             : 
    2328         137 :     if (!hMiraMonLayer)
    2329           0 :         return 1;
    2330             : 
    2331         137 :     if (hMiraMonLayer->bIsPolygon)
    2332          75 :         pMMArcLayer = &hMiraMonLayer->MMPolygon.MMArc;
    2333             :     else
    2334          62 :         pMMArcLayer = &hMiraMonLayer->MMArc;
    2335             : 
    2336         137 :     if (pMMArcLayer->MMNode.pNL)
    2337             :     {
    2338          58 :         VSIFree(pMMArcLayer->MMNode.pNL);
    2339          58 :         pMMArcLayer->MMNode.pNL = nullptr;
    2340             :     }
    2341             : 
    2342         137 :     if (pMMArcLayer->MMNode.pNodeHeader)
    2343             :     {
    2344          58 :         VSIFree(pMMArcLayer->MMNode.pNodeHeader);
    2345          58 :         pMMArcLayer->MMNode.pNodeHeader = nullptr;
    2346             :     }
    2347             : 
    2348         137 :     MMDestroyMMAdmDB(&hMiraMonLayer->MMArc.MMNode.MMAdmDB);
    2349         137 :     return 0;
    2350             : }
    2351             : 
    2352         137 : static int MMDestroyArcLayer(struct MiraMonVectLayerInfo *hMiraMonLayer)
    2353             : {
    2354             :     struct MiraMonArcLayer *pMMArcLayer;
    2355             : 
    2356         137 :     if (!hMiraMonLayer)
    2357           0 :         return 1;
    2358             : 
    2359         137 :     if (hMiraMonLayer->bIsPolygon)
    2360          75 :         pMMArcLayer = &hMiraMonLayer->MMPolygon.MMArc;
    2361             :     else
    2362          62 :         pMMArcLayer = &hMiraMonLayer->MMArc;
    2363             : 
    2364         137 :     if (pMMArcLayer->pAL)
    2365             :     {
    2366          58 :         VSIFree(pMMArcLayer->pAL);
    2367          58 :         pMMArcLayer->pAL = nullptr;
    2368             :     }
    2369         137 :     if (pMMArcLayer->pArcHeader)
    2370             :     {
    2371         127 :         VSIFree(pMMArcLayer->pArcHeader);
    2372         127 :         pMMArcLayer->pArcHeader = nullptr;
    2373             :     }
    2374             : 
    2375         137 :     MMDestroyZSectionDescription(&pMMArcLayer->pZSection);
    2376         137 :     MMDestroyMMAdmDB(&pMMArcLayer->MMAdmDB);
    2377             : 
    2378         137 :     MMDestroyNodeLayer(hMiraMonLayer);
    2379         137 :     return 0;
    2380             : }
    2381             : 
    2382          75 : static int MMDestroyPolygonLayer(struct MiraMonVectLayerInfo *hMiraMonLayer)
    2383             : {
    2384             :     struct MiraMonPolygonLayer *pMMPolygonLayer;
    2385             : 
    2386          75 :     if (!hMiraMonLayer)
    2387           0 :         return 1;
    2388             : 
    2389          75 :     pMMPolygonLayer = &hMiraMonLayer->MMPolygon;
    2390             : 
    2391          75 :     MMDestroyArcLayer(hMiraMonLayer);
    2392             : 
    2393          75 :     if (pMMPolygonLayer->pPAL)
    2394             :     {
    2395          27 :         VSIFree(pMMPolygonLayer->pPAL);
    2396          27 :         pMMPolygonLayer->pPAL = nullptr;
    2397             :     }
    2398             : 
    2399          75 :     if (pMMPolygonLayer->pPS)
    2400             :     {
    2401          27 :         VSIFree(pMMPolygonLayer->pPS);
    2402          27 :         pMMPolygonLayer->pPS = nullptr;
    2403             :     }
    2404             : 
    2405          75 :     if (pMMPolygonLayer->pPolHeader)
    2406             :     {
    2407          75 :         VSIFree(pMMPolygonLayer->pPolHeader);
    2408          75 :         pMMPolygonLayer->pPolHeader = nullptr;
    2409             :     }
    2410             : 
    2411          75 :     MMDestroyMMAdmDB(&pMMPolygonLayer->MMAdmDB);
    2412             : 
    2413          75 :     return 0;
    2414             : }
    2415             : 
    2416         824 : int MMDestroyLayer(struct MiraMonVectLayerInfo *hMiraMonLayer)
    2417             : {
    2418             :     //CheckMMVectorLayerVersion(hMiraMonLayer, 1)
    2419             : 
    2420         824 :     if (!hMiraMonLayer)
    2421           0 :         return 1;
    2422             : 
    2423         824 :     if (hMiraMonLayer->bIsPoint)
    2424          76 :         MMDestroyPointLayer(hMiraMonLayer);
    2425         748 :     else if (hMiraMonLayer->bIsArc && !hMiraMonLayer->bIsPolygon)
    2426          62 :         MMDestroyArcLayer(hMiraMonLayer);
    2427         686 :     else if (hMiraMonLayer->bIsPolygon)
    2428          75 :         MMDestroyPolygonLayer(hMiraMonLayer);
    2429             : 
    2430         824 :     if (hMiraMonLayer->pszSrcLayerName)
    2431             :     {
    2432         461 :         VSIFree(hMiraMonLayer->pszSrcLayerName);
    2433         461 :         hMiraMonLayer->pszSrcLayerName = nullptr;
    2434             :     }
    2435         824 :     if (hMiraMonLayer->szLayerTitle)
    2436             :     {
    2437         340 :         VSIFree(hMiraMonLayer->szLayerTitle);
    2438         340 :         hMiraMonLayer->szLayerTitle = nullptr;
    2439             :     }
    2440         824 :     if (hMiraMonLayer->pSRS)
    2441             :     {
    2442         173 :         VSIFree(hMiraMonLayer->pSRS);
    2443         173 :         hMiraMonLayer->pSRS = nullptr;
    2444             :     }
    2445             : 
    2446         824 :     if (hMiraMonLayer->pZUnit)
    2447             :     {
    2448           0 :         VSIFree(hMiraMonLayer->pZUnit);
    2449           0 :         hMiraMonLayer->pZUnit = nullptr;
    2450             :     }
    2451             : 
    2452         824 :     if (hMiraMonLayer->pMultRecordIndex)
    2453             :     {
    2454         104 :         VSIFree(hMiraMonLayer->pMultRecordIndex);
    2455         104 :         hMiraMonLayer->pMultRecordIndex = nullptr;
    2456             :     }
    2457             : 
    2458         824 :     if (hMiraMonLayer->ReadFeature.pNCoordRing)
    2459             :     {
    2460          85 :         free(hMiraMonLayer->ReadFeature.pNCoordRing);
    2461          85 :         hMiraMonLayer->ReadFeature.pNCoordRing = nullptr;
    2462             :     }
    2463         824 :     if (hMiraMonLayer->ReadFeature.pCoord)
    2464             :     {
    2465          97 :         free(hMiraMonLayer->ReadFeature.pCoord);
    2466          97 :         hMiraMonLayer->ReadFeature.pCoord = nullptr;
    2467             :     }
    2468         824 :     if (hMiraMonLayer->ReadFeature.pZCoord)
    2469             :     {
    2470          19 :         free(hMiraMonLayer->ReadFeature.pZCoord);
    2471          19 :         hMiraMonLayer->ReadFeature.pZCoord = nullptr;
    2472             :     }
    2473         824 :     if (hMiraMonLayer->ReadFeature.pRecords)
    2474             :     {
    2475           0 :         free(hMiraMonLayer->ReadFeature.pRecords);
    2476           0 :         hMiraMonLayer->ReadFeature.pRecords = nullptr;
    2477             :     }
    2478         824 :     if (hMiraMonLayer->ReadFeature.flag_VFG)
    2479             :     {
    2480          38 :         free(hMiraMonLayer->ReadFeature.flag_VFG);
    2481          38 :         hMiraMonLayer->ReadFeature.flag_VFG = nullptr;
    2482             :     }
    2483             : 
    2484         824 :     if (hMiraMonLayer->pArcs)
    2485             :     {
    2486          44 :         VSIFree(hMiraMonLayer->pArcs);
    2487          44 :         hMiraMonLayer->pArcs = nullptr;
    2488             :     }
    2489             : 
    2490         824 :     if (hMiraMonLayer->szStringToOperate)
    2491             :     {
    2492         453 :         VSIFree(hMiraMonLayer->szStringToOperate);
    2493         453 :         hMiraMonLayer->szStringToOperate = nullptr;
    2494         453 :         hMiraMonLayer->nNumStringToOperate = 0;
    2495             :     }
    2496             : 
    2497         824 :     if (hMiraMonLayer->pLayerDB)
    2498             :     {
    2499         108 :         if (hMiraMonLayer->pLayerDB->pFields)
    2500             :         {
    2501         108 :             VSIFree(hMiraMonLayer->pLayerDB->pFields);
    2502         108 :             hMiraMonLayer->pLayerDB->pFields = nullptr;
    2503             :         }
    2504         108 :         VSIFree(hMiraMonLayer->pLayerDB);
    2505         108 :         hMiraMonLayer->pLayerDB = nullptr;
    2506             :     }
    2507             : 
    2508             :     // Destroys all database objects
    2509         824 :     MMDestroyMMDB(hMiraMonLayer);
    2510             : 
    2511         824 :     return 0;
    2512             : }
    2513             : 
    2514             : /* -------------------------------------------------------------------- */
    2515             : /*      Flush Layer Functions                                           */
    2516             : /* -------------------------------------------------------------------- */
    2517             : 
    2518             : // Initializes a MM_FLUSH_INFO structure, which is used for buffering
    2519             : // data before writing it to a file.
    2520        1152 : int MMInitFlush(struct MM_FLUSH_INFO *pFlush, VSILFILE *pF, GUInt64 nBlockSize,
    2521             :                 char **pBuffer, MM_FILE_OFFSET DiskOffsetWhereToFlush,
    2522             :                 GInt32 nMyDiskSize)
    2523             : {
    2524        1152 :     memset(pFlush, 0, sizeof(*pFlush));
    2525        1152 :     *pBuffer = nullptr;
    2526             : 
    2527        1152 :     pFlush->nMyDiskSize = nMyDiskSize;
    2528        1152 :     pFlush->pF = pF;
    2529        1152 :     pFlush->nBlockSize = nBlockSize;
    2530        1152 :     pFlush->nNumBytes = 0;
    2531        1152 :     if (MMCheckSize_t(nBlockSize, 1))
    2532           0 :         return 1;
    2533             : 
    2534        1152 :     if (!nBlockSize)
    2535             :     {
    2536           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    2537             :                  "Error in MiraMon "
    2538             :                  "driver: MMInitFlush() with no bytes to process");
    2539           0 :         return 1;
    2540             :     }
    2541             : 
    2542        1152 :     if (nullptr == (*pBuffer = (char *)VSICalloc(1, (size_t)nBlockSize)))
    2543             :     {
    2544           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    2545             :                  "Memory error in MiraMon "
    2546             :                  "driver (MMInitFlush())");
    2547           0 :         return 1;
    2548             :     }
    2549        1152 :     pFlush->OffsetWhereToFlush = DiskOffsetWhereToFlush;
    2550        1152 :     pFlush->CurrentOffset = 0;
    2551        1152 :     return 0;
    2552             : }
    2553             : 
    2554             : // Reads data from a file into a buffer.
    2555         487 : int MMReadFlush(struct MM_FLUSH_INFO *pFlush)
    2556             : {
    2557         487 :     VSIFSeekL(pFlush->pF, pFlush->OffsetWhereToFlush, SEEK_SET);
    2558         487 :     if (pFlush->nBlockSize !=
    2559         487 :         (GUInt64)(VSIFReadL(pFlush->pBlockWhereToSaveOrRead, 1,
    2560         487 :                             (size_t)pFlush->nBlockSize, pFlush->pF)))
    2561           6 :         return 1;
    2562         481 :     return 0;
    2563             : }
    2564             : 
    2565             : // Flushes data from a buffer to a disk file.
    2566         722 : static int MMFlushToDisk(struct MM_FLUSH_INFO *FlushInfo)
    2567             : {
    2568         722 :     if (!FlushInfo->nNumBytes)
    2569          86 :         return 0;
    2570             :     // Just flush to the disk at the correct place.
    2571         636 :     VSIFSeekL(FlushInfo->pF, FlushInfo->OffsetWhereToFlush, SEEK_SET);
    2572             : 
    2573         636 :     if (FlushInfo->nNumBytes !=
    2574         636 :         (GUInt64)VSIFWriteL(FlushInfo->pBlockWhereToSaveOrRead, 1,
    2575         636 :                             (size_t)FlushInfo->nNumBytes, FlushInfo->pF))
    2576           0 :         return 1;
    2577         636 :     FlushInfo->OffsetWhereToFlush += FlushInfo->nNumBytes;
    2578         636 :     FlushInfo->NTimesFlushed++;
    2579         636 :     FlushInfo->TotalSavedBytes += FlushInfo->nNumBytes;
    2580         636 :     FlushInfo->nNumBytes = 0;
    2581             : 
    2582         636 :     return 0;
    2583             : }
    2584             : 
    2585             : // Reads a block of data from a buffer in memory
    2586        8344 : int MMReadBlockFromBuffer(struct MM_FLUSH_INFO *FlushInfo)
    2587             : {
    2588        8344 :     if (!FlushInfo->SizeOfBlockToBeSaved)
    2589           0 :         return 0;
    2590             : 
    2591        8344 :     if (FlushInfo->pBlockToBeSaved)
    2592             :     {
    2593        8344 :         memcpy(FlushInfo->pBlockToBeSaved,
    2594        8344 :                (void *)((char *)FlushInfo->pBlockWhereToSaveOrRead +
    2595        8344 :                         FlushInfo->CurrentOffset),
    2596             :                FlushInfo->SizeOfBlockToBeSaved);
    2597             :     }
    2598        8344 :     FlushInfo->CurrentOffset += FlushInfo->SizeOfBlockToBeSaved;
    2599             : 
    2600        8344 :     return 0;
    2601             : }
    2602             : 
    2603             : // Appends a block of data to a buffer in memory, which is
    2604             : // used for later flushing to disk.
    2605        5592 : int MMAppendBlockToBuffer(struct MM_FLUSH_INFO *FlushInfo)
    2606             : {
    2607        5592 :     if (FlushInfo->SizeOfBlockToBeSaved)
    2608             :     {
    2609             :         // If all the block itself does not fit to the buffer,
    2610             :         // then all the block is written directly to the disk
    2611        4870 :         if (FlushInfo->nNumBytes == 0 &&
    2612         696 :             FlushInfo->SizeOfBlockToBeSaved >= FlushInfo->nBlockSize)
    2613             :         {
    2614           0 :             if (MMFlushToDisk(FlushInfo))
    2615           0 :                 return 1;
    2616           0 :             return 0;
    2617             :         }
    2618             : 
    2619             :         // There is space in FlushInfo->pBlockWhereToSaveOrRead?
    2620        4870 :         if (FlushInfo->nNumBytes + FlushInfo->SizeOfBlockToBeSaved <=
    2621        4870 :             FlushInfo->nBlockSize)
    2622             :         {
    2623        4870 :             if (FlushInfo->pBlockToBeSaved)
    2624             :             {
    2625        4549 :                 memcpy((void *)((char *)FlushInfo->pBlockWhereToSaveOrRead +
    2626        4549 :                                 FlushInfo->nNumBytes),
    2627        4549 :                        FlushInfo->pBlockToBeSaved,
    2628             :                        FlushInfo->SizeOfBlockToBeSaved);
    2629             :             }
    2630             :             else  // Add zero characters
    2631             :             {
    2632         321 :                 char zero_caracters[8] = {0, 0, 0, 0, 0, 0, 0, 0};
    2633         321 :                 memcpy((char *)FlushInfo->pBlockWhereToSaveOrRead +
    2634         321 :                            FlushInfo->nNumBytes,
    2635             :                        zero_caracters, FlushInfo->SizeOfBlockToBeSaved);
    2636             :             }
    2637             : 
    2638        4870 :             FlushInfo->nNumBytes += FlushInfo->SizeOfBlockToBeSaved;
    2639             :         }
    2640             :         else
    2641             :         {
    2642             :             // Empty the buffer
    2643           0 :             if (MMFlushToDisk(FlushInfo))
    2644           0 :                 return 1;
    2645             :             // Append the pendant bytes
    2646           0 :             if (MMAppendBlockToBuffer(FlushInfo))
    2647           0 :                 return 1;
    2648             :         }
    2649        4870 :         return 0;
    2650             :     }
    2651             :     // Just flush to the disc.
    2652         722 :     return MMFlushToDisk(FlushInfo);
    2653             : }
    2654             : 
    2655             : // Copy the contents of a temporary file to a final file.
    2656             : // Used everywhere when closing layers.
    2657         236 : int MMMoveFromFileToFile(VSILFILE *pSrcFile, VSILFILE *pDestFile,
    2658             :                          MM_FILE_OFFSET *pnOffset)
    2659             : {
    2660         236 :     size_t bufferSize = 1024 * 1024;  // 1 MB buffer;
    2661             :     unsigned char *buffer;
    2662             :     size_t bytesRead, bytesWritten;
    2663             : 
    2664         236 :     if (!pSrcFile || !pDestFile || !pnOffset)
    2665           0 :         return 0;
    2666             : 
    2667         236 :     buffer = (unsigned char *)VSICalloc(1, bufferSize);
    2668             : 
    2669         236 :     if (!buffer)
    2670           0 :         return 1;
    2671             : 
    2672         236 :     VSIFSeekL(pSrcFile, 0, SEEK_SET);
    2673         236 :     VSIFSeekL(pDestFile, *pnOffset, SEEK_SET);
    2674         472 :     while ((bytesRead = VSIFReadL(buffer, sizeof(unsigned char), bufferSize,
    2675             :                                   pSrcFile)) > 0)
    2676             :     {
    2677             :         bytesWritten =
    2678         236 :             VSIFWriteL(buffer, sizeof(unsigned char), bytesRead, pDestFile);
    2679         236 :         if (bytesWritten != bytesRead)
    2680             :         {
    2681           0 :             VSIFree(buffer);
    2682           0 :             return 1;
    2683             :         }
    2684         236 :         (*pnOffset) += bytesWritten;
    2685             :     }
    2686         236 :     VSIFree(buffer);
    2687         236 :     return 0;
    2688             : }
    2689             : 
    2690             : /* -------------------------------------------------------------------- */
    2691             : /*      Layer: Offsets and variables types managing                     */
    2692             : /* -------------------------------------------------------------------- */
    2693             : 
    2694             : // Alineation described in format documents.
    2695         192 : static void MMGetOffsetAlignedTo8(MM_FILE_OFFSET *Offset)
    2696             : {
    2697             :     MM_FILE_OFFSET reajust;
    2698             : 
    2699         192 :     if ((*Offset) % 8L)
    2700             :     {
    2701         170 :         reajust = 8 - ((*Offset) % 8L);
    2702         170 :         (*Offset) += reajust;
    2703             :     }
    2704         192 : }
    2705             : 
    2706             : // Reading integers depending on the version being read.
    2707        2821 : int MMReadGUInt64DependingOnVersion(struct MiraMonVectLayerInfo *hMiraMonLayer,
    2708             :                                     struct MM_FLUSH_INFO *FlushInfo,
    2709             :                                     GUInt64 *pnUI64)
    2710             : {
    2711             :     uint32_t nUL32;
    2712             : 
    2713        2821 :     if (!hMiraMonLayer)
    2714           0 :         return 1;
    2715             : 
    2716        2821 :     if (hMiraMonLayer->LayerVersion == MM_32BITS_VERSION)
    2717             :     {
    2718        2743 :         FlushInfo->pBlockToBeSaved = (void *)&nUL32;
    2719        2743 :         FlushInfo->SizeOfBlockToBeSaved = sizeof(nUL32);
    2720        2743 :         if (MMReadBlockFromBuffer(FlushInfo))
    2721             :         {
    2722           0 :             FlushInfo->pBlockToBeSaved = nullptr;
    2723           0 :             return 1;
    2724             :         }
    2725        2743 :         *pnUI64 = (GUInt64)nUL32;
    2726             :     }
    2727             :     else
    2728             :     {
    2729          78 :         FlushInfo->pBlockToBeSaved = (void *)pnUI64;
    2730          78 :         FlushInfo->SizeOfBlockToBeSaved = sizeof(*pnUI64);
    2731          78 :         if (MMReadBlockFromBuffer(FlushInfo))
    2732             :         {
    2733           0 :             FlushInfo->pBlockToBeSaved = nullptr;
    2734           0 :             return 1;
    2735             :         }
    2736             :     }
    2737        2821 :     FlushInfo->pBlockToBeSaved = nullptr;
    2738        2821 :     return 0;
    2739             : }
    2740             : 
    2741             : // Reading offsets depending on the version is being read.
    2742         744 : int MMReadOffsetDependingOnVersion(struct MiraMonVectLayerInfo *hMiraMonLayer,
    2743             :                                    struct MM_FLUSH_INFO *FlushInfo,
    2744             :                                    MM_FILE_OFFSET *pnUI64)
    2745             : {
    2746             :     uint32_t nUL32;
    2747             : 
    2748         744 :     if (!hMiraMonLayer)
    2749           0 :         return 1;
    2750             : 
    2751         744 :     if (hMiraMonLayer->LayerVersion == MM_32BITS_VERSION)
    2752             :     {
    2753         722 :         FlushInfo->pBlockToBeSaved = (void *)&nUL32;
    2754         722 :         FlushInfo->SizeOfBlockToBeSaved = sizeof(nUL32);
    2755         722 :         if (MMReadBlockFromBuffer(FlushInfo))
    2756             :         {
    2757           0 :             FlushInfo->pBlockToBeSaved = nullptr;
    2758           0 :             return 1;
    2759             :         }
    2760         722 :         *pnUI64 = (MM_FILE_OFFSET)nUL32;
    2761             :     }
    2762             :     else
    2763             :     {
    2764          22 :         FlushInfo->pBlockToBeSaved = (void *)pnUI64;
    2765          22 :         FlushInfo->SizeOfBlockToBeSaved = sizeof(*pnUI64);
    2766          22 :         if (MMReadBlockFromBuffer(FlushInfo))
    2767             :         {
    2768           0 :             FlushInfo->pBlockToBeSaved = nullptr;
    2769           0 :             return 1;
    2770             :         }
    2771             :     }
    2772         744 :     FlushInfo->pBlockToBeSaved = nullptr;
    2773         744 :     return 0;
    2774             : }
    2775             : 
    2776             : // Appending integers depending on the version.
    2777        1219 : int MMAppendIntegerDependingOnVersion(
    2778             :     struct MiraMonVectLayerInfo *hMiraMonLayer, struct MM_FLUSH_INFO *FlushInfo,
    2779             :     uint32_t *nUL32, GUInt64 nUI64)
    2780             : {
    2781             :     int result;
    2782             : 
    2783        1219 :     if (!hMiraMonLayer)
    2784           0 :         return 1;
    2785             : 
    2786        1219 :     if (hMiraMonLayer->LayerVersion == MM_32BITS_VERSION)
    2787             :     {
    2788        1069 :         *nUL32 = (uint32_t)nUI64;
    2789        1069 :         FlushInfo->SizeOfBlockToBeSaved = sizeof(*nUL32);
    2790        1069 :         hMiraMonLayer->OffsetCheck += FlushInfo->SizeOfBlockToBeSaved;
    2791        1069 :         FlushInfo->pBlockToBeSaved = (void *)nUL32;
    2792             :     }
    2793             :     else
    2794             :     {
    2795         150 :         FlushInfo->SizeOfBlockToBeSaved = sizeof(nUI64);
    2796         150 :         hMiraMonLayer->OffsetCheck += FlushInfo->SizeOfBlockToBeSaved;
    2797         150 :         FlushInfo->pBlockToBeSaved = (void *)&nUI64;
    2798             :     }
    2799        1219 :     result = MMAppendBlockToBuffer(FlushInfo);
    2800        1219 :     FlushInfo->pBlockToBeSaved = nullptr;
    2801        1219 :     return result;
    2802             : }
    2803             : 
    2804             : /* -------------------------------------------------------------------- */
    2805             : /*      Layer: Reading and writing layer sections                       */
    2806             : /*      This code follows the specifications of the following document: */
    2807             : /*             https://www.miramon.cat/new_note/eng/notes/   \          */
    2808             : /*              FormatFitxersTopologicsMiraMon.pdf                      */
    2809             : /* -------------------------------------------------------------------- */
    2810          69 : int MMReadAHArcSection(struct MiraMonVectLayerInfo *hMiraMonLayer)
    2811             : {
    2812             :     MM_INTERNAL_FID iElem, nElem;
    2813             :     struct MM_FLUSH_INFO FlushTMP;
    2814          69 :     char *pBuffer = nullptr;
    2815             :     MM_FILE_OFFSET nBlockSize;
    2816             :     struct MiraMonArcLayer *pMMArcLayer;
    2817             :     MM_N_VERTICES_TYPE nElementCount;
    2818             : 
    2819          69 :     if (!hMiraMonLayer)
    2820           0 :         return 1;
    2821             : 
    2822          69 :     if (hMiraMonLayer->bIsPolygon)
    2823             :     {
    2824          41 :         pMMArcLayer = &hMiraMonLayer->MMPolygon.MMArc;
    2825          41 :         nElem = hMiraMonLayer->MMPolygon.TopArcHeader.nElemCount;
    2826             :     }
    2827             :     else
    2828             :     {
    2829          28 :         pMMArcLayer = &hMiraMonLayer->MMArc;
    2830          28 :         nElem = hMiraMonLayer->TopHeader.nElemCount;
    2831             :     }
    2832             : 
    2833          69 :     if (MMCheckSize_t(nElem, pMMArcLayer->nSizeArcHeader))
    2834             :     {
    2835           0 :         return 1;
    2836             :     }
    2837             : 
    2838          69 :     nBlockSize = nElem * (pMMArcLayer->nSizeArcHeader);
    2839             : 
    2840          69 :     if (MMInitFlush(&FlushTMP, pMMArcLayer->pF, nBlockSize, &pBuffer,
    2841          69 :                     hMiraMonLayer->nHeaderDiskSize, 0))
    2842             :     {
    2843           0 :         if (pBuffer)
    2844           0 :             VSIFree(pBuffer);
    2845           0 :         return 1;
    2846             :     }
    2847          69 :     FlushTMP.pBlockWhereToSaveOrRead = (void *)pBuffer;
    2848          69 :     if (MMReadFlush(&FlushTMP))
    2849             :     {
    2850           0 :         if (pBuffer)
    2851           0 :             VSIFree(pBuffer);
    2852           0 :         return 1;
    2853             :     }
    2854             : 
    2855         343 :     for (iElem = 0; iElem < nElem; iElem++)
    2856             :     {
    2857             :         // Bounding box
    2858         274 :         FlushTMP.pBlockToBeSaved =
    2859         274 :             (void *)&(pMMArcLayer->pArcHeader[iElem].dfBB.dfMinX);
    2860         274 :         FlushTMP.SizeOfBlockToBeSaved =
    2861             :             sizeof(pMMArcLayer->pArcHeader[iElem].dfBB.dfMinX);
    2862         274 :         if (MMReadBlockFromBuffer(&FlushTMP))
    2863             :         {
    2864           0 :             if (pBuffer)
    2865           0 :                 VSIFree(pBuffer);
    2866           0 :             return 1;
    2867             :         }
    2868         274 :         FlushTMP.pBlockToBeSaved =
    2869         274 :             (void *)&pMMArcLayer->pArcHeader[iElem].dfBB.dfMaxX;
    2870         274 :         FlushTMP.SizeOfBlockToBeSaved =
    2871             :             sizeof(pMMArcLayer->pArcHeader[iElem].dfBB.dfMaxX);
    2872         274 :         if (MMReadBlockFromBuffer(&FlushTMP))
    2873             :         {
    2874           0 :             if (pBuffer)
    2875           0 :                 VSIFree(pBuffer);
    2876           0 :             return 1;
    2877             :         }
    2878         274 :         FlushTMP.pBlockToBeSaved =
    2879         274 :             (void *)&pMMArcLayer->pArcHeader[iElem].dfBB.dfMinY;
    2880         274 :         FlushTMP.SizeOfBlockToBeSaved =
    2881             :             sizeof(pMMArcLayer->pArcHeader[iElem].dfBB.dfMinY);
    2882         274 :         if (MMReadBlockFromBuffer(&FlushTMP))
    2883             :         {
    2884           0 :             if (pBuffer)
    2885           0 :                 VSIFree(pBuffer);
    2886           0 :             return 1;
    2887             :         }
    2888         274 :         FlushTMP.pBlockToBeSaved =
    2889         274 :             (void *)&pMMArcLayer->pArcHeader[iElem].dfBB.dfMaxY;
    2890         274 :         FlushTMP.SizeOfBlockToBeSaved =
    2891             :             sizeof(pMMArcLayer->pArcHeader[iElem].dfBB.dfMaxY);
    2892         274 :         if (MMReadBlockFromBuffer(&FlushTMP))
    2893             :         {
    2894           0 :             if (pBuffer)
    2895           0 :                 VSIFree(pBuffer);
    2896           0 :             return 1;
    2897             :         }
    2898             : 
    2899             :         // Element count: number of vertices of the arc
    2900         274 :         nElementCount = pMMArcLayer->pArcHeader[iElem].nElemCount;
    2901         274 :         if (MMReadGUInt64DependingOnVersion(hMiraMonLayer, &FlushTMP,
    2902             :                                             &nElementCount))
    2903             :         {
    2904           0 :             if (pBuffer)
    2905           0 :                 VSIFree(pBuffer);
    2906           0 :             return 1;
    2907             :         }
    2908         274 :         pMMArcLayer->pArcHeader[iElem].nElemCount = nElementCount;
    2909             : 
    2910             :         // Offset: offset of the first vertice of the arc
    2911         274 :         if (MMReadOffsetDependingOnVersion(
    2912             :                 hMiraMonLayer, &FlushTMP,
    2913         274 :                 &pMMArcLayer->pArcHeader[iElem].nOffset))
    2914             :         {
    2915           0 :             if (pBuffer)
    2916           0 :                 VSIFree(pBuffer);
    2917           0 :             return 1;
    2918             :         }
    2919             :         // First node: first node of the arc
    2920         274 :         if (MMReadGUInt64DependingOnVersion(
    2921             :                 hMiraMonLayer, &FlushTMP,
    2922         274 :                 &pMMArcLayer->pArcHeader[iElem].nFirstIdNode))
    2923             :         {
    2924           0 :             if (pBuffer)
    2925           0 :                 VSIFree(pBuffer);
    2926           0 :             return 1;
    2927             :         }
    2928             :         // Last node: first node of the arc
    2929         274 :         if (MMReadGUInt64DependingOnVersion(
    2930             :                 hMiraMonLayer, &FlushTMP,
    2931         274 :                 &pMMArcLayer->pArcHeader[iElem].nLastIdNode))
    2932             :         {
    2933           0 :             if (pBuffer)
    2934           0 :                 VSIFree(pBuffer);
    2935           0 :             return 1;
    2936             :         }
    2937             :         // Length of the arc
    2938         274 :         FlushTMP.pBlockToBeSaved =
    2939         274 :             (void *)&pMMArcLayer->pArcHeader[iElem].dfLength;
    2940         274 :         FlushTMP.SizeOfBlockToBeSaved =
    2941             :             sizeof(pMMArcLayer->pArcHeader[iElem].dfLength);
    2942         274 :         if (MMReadBlockFromBuffer(&FlushTMP))
    2943             :         {
    2944           0 :             if (pBuffer)
    2945           0 :                 VSIFree(pBuffer);
    2946           0 :             return 1;
    2947             :         }
    2948             :     }
    2949             : 
    2950          69 :     if (pBuffer)
    2951          69 :         VSIFree(pBuffer);
    2952          69 :     return 0;
    2953             : }
    2954             : 
    2955          58 : int MMWriteAHArcSection(struct MiraMonVectLayerInfo *hMiraMonLayer,
    2956             :                         MM_FILE_OFFSET DiskOffset)
    2957             : {
    2958             :     MM_INTERNAL_FID iElem;
    2959             :     struct MM_FLUSH_INFO FlushTMP;
    2960          58 :     char *pBuffer = nullptr;
    2961             :     uint32_t nUL32;
    2962             :     MM_FILE_OFFSET nOffsetDiff;
    2963             :     struct MiraMonArcLayer *pMMArcLayer;
    2964             : 
    2965          58 :     if (!hMiraMonLayer)
    2966           0 :         return 1;
    2967             : 
    2968          58 :     if (hMiraMonLayer->bIsPolygon)
    2969          27 :         pMMArcLayer = &hMiraMonLayer->MMPolygon.MMArc;
    2970             :     else
    2971          31 :         pMMArcLayer = &hMiraMonLayer->MMArc;
    2972             : 
    2973          58 :     nOffsetDiff =
    2974          58 :         hMiraMonLayer->nHeaderDiskSize +
    2975          58 :         hMiraMonLayer->nFinalElemCount * (pMMArcLayer->nSizeArcHeader);
    2976             : 
    2977          58 :     if (MMInitFlush(&FlushTMP, pMMArcLayer->pF, MM_1MB, &pBuffer, DiskOffset,
    2978             :                     0))
    2979             :     {
    2980           0 :         if (pBuffer)
    2981           0 :             VSIFree(pBuffer);
    2982           0 :         return 1;
    2983             :     }
    2984             : 
    2985          58 :     FlushTMP.pBlockWhereToSaveOrRead = (void *)pBuffer;
    2986         160 :     for (iElem = 0; iElem < hMiraMonLayer->nFinalElemCount; iElem++)
    2987             :     {
    2988             :         // Bounding box
    2989         102 :         FlushTMP.SizeOfBlockToBeSaved =
    2990             :             sizeof(pMMArcLayer->pArcHeader[iElem].dfBB.dfMinX);
    2991         102 :         FlushTMP.pBlockToBeSaved =
    2992         102 :             (void *)&pMMArcLayer->pArcHeader[iElem].dfBB.dfMinX;
    2993         102 :         hMiraMonLayer->OffsetCheck += FlushTMP.SizeOfBlockToBeSaved;
    2994         102 :         if (MMAppendBlockToBuffer(&FlushTMP))
    2995             :         {
    2996           0 :             if (pBuffer)
    2997           0 :                 VSIFree(pBuffer);
    2998           0 :             return 1;
    2999             :         }
    3000         102 :         FlushTMP.pBlockToBeSaved =
    3001         102 :             (void *)&pMMArcLayer->pArcHeader[iElem].dfBB.dfMaxX;
    3002         102 :         hMiraMonLayer->OffsetCheck += FlushTMP.SizeOfBlockToBeSaved;
    3003         102 :         if (MMAppendBlockToBuffer(&FlushTMP))
    3004             :         {
    3005           0 :             if (pBuffer)
    3006           0 :                 VSIFree(pBuffer);
    3007           0 :             return 1;
    3008             :         }
    3009         102 :         FlushTMP.pBlockToBeSaved =
    3010         102 :             (void *)&pMMArcLayer->pArcHeader[iElem].dfBB.dfMinY;
    3011         102 :         hMiraMonLayer->OffsetCheck += FlushTMP.SizeOfBlockToBeSaved;
    3012         102 :         if (MMAppendBlockToBuffer(&FlushTMP))
    3013             :         {
    3014           0 :             if (pBuffer)
    3015           0 :                 VSIFree(pBuffer);
    3016           0 :             return 1;
    3017             :         }
    3018         102 :         FlushTMP.pBlockToBeSaved =
    3019         102 :             (void *)&pMMArcLayer->pArcHeader[iElem].dfBB.dfMaxY;
    3020         102 :         hMiraMonLayer->OffsetCheck += FlushTMP.SizeOfBlockToBeSaved;
    3021         102 :         if (MMAppendBlockToBuffer(&FlushTMP))
    3022             :         {
    3023           0 :             if (pBuffer)
    3024           0 :                 VSIFree(pBuffer);
    3025           0 :             return 1;
    3026             :         }
    3027             : 
    3028             :         // Element count: number of vertices of the arc
    3029         102 :         if (MMAppendIntegerDependingOnVersion(
    3030             :                 hMiraMonLayer, &FlushTMP, &nUL32,
    3031         102 :                 pMMArcLayer->pArcHeader[iElem].nElemCount))
    3032             :         {
    3033           0 :             if (pBuffer)
    3034           0 :                 VSIFree(pBuffer);
    3035           0 :             return 1;
    3036             :         }
    3037             : 
    3038             :         // Offset: offset of the first vertice of the arc
    3039         102 :         if (MMAppendIntegerDependingOnVersion(
    3040             :                 hMiraMonLayer, &FlushTMP, &nUL32,
    3041         102 :                 pMMArcLayer->pArcHeader[iElem].nOffset + nOffsetDiff))
    3042             :         {
    3043           0 :             if (pBuffer)
    3044           0 :                 VSIFree(pBuffer);
    3045           0 :             return 1;
    3046             :         }
    3047             :         // First node: first node of the arc
    3048         102 :         if (MMAppendIntegerDependingOnVersion(
    3049             :                 hMiraMonLayer, &FlushTMP, &nUL32,
    3050         102 :                 pMMArcLayer->pArcHeader[iElem].nFirstIdNode))
    3051             :         {
    3052           0 :             if (pBuffer)
    3053           0 :                 VSIFree(pBuffer);
    3054           0 :             return 1;
    3055             :         }
    3056             :         // Last node: first node of the arc
    3057         102 :         if (MMAppendIntegerDependingOnVersion(
    3058             :                 hMiraMonLayer, &FlushTMP, &nUL32,
    3059         102 :                 pMMArcLayer->pArcHeader[iElem].nLastIdNode))
    3060             :         {
    3061           0 :             if (pBuffer)
    3062           0 :                 VSIFree(pBuffer);
    3063           0 :             return 1;
    3064             :         }
    3065             :         // Length of the arc
    3066         102 :         FlushTMP.SizeOfBlockToBeSaved =
    3067             :             sizeof(pMMArcLayer->pArcHeader[iElem].dfLength);
    3068         102 :         hMiraMonLayer->OffsetCheck += FlushTMP.SizeOfBlockToBeSaved;
    3069         102 :         FlushTMP.pBlockToBeSaved =
    3070         102 :             (void *)&pMMArcLayer->pArcHeader[iElem].dfLength;
    3071         102 :         if (MMAppendBlockToBuffer(&FlushTMP))
    3072             :         {
    3073           0 :             if (pBuffer)
    3074           0 :                 VSIFree(pBuffer);
    3075           0 :             return 1;
    3076             :         }
    3077             :     }
    3078          58 :     FlushTMP.SizeOfBlockToBeSaved = 0;
    3079          58 :     if (MMAppendBlockToBuffer(&FlushTMP))
    3080             :     {
    3081           0 :         if (pBuffer)
    3082           0 :             VSIFree(pBuffer);
    3083           0 :         return 1;
    3084             :     }
    3085             : 
    3086          58 :     if (pBuffer)
    3087          58 :         VSIFree(pBuffer);
    3088          58 :     return 0;
    3089             : }
    3090             : 
    3091             : #ifdef JUST_IN_CASE_WE_NEED_IT_SOMEDAY
    3092             : static int MMReadNHNodeSection(struct MiraMonVectLayerInfo *hMiraMonLayer)
    3093             : {
    3094             :     MM_INTERNAL_FID iElem, nElem;
    3095             :     struct MM_FLUSH_INFO FlushTMP;
    3096             :     char *pBuffer = nullptr;
    3097             :     MM_FILE_OFFSET nBlockSize;
    3098             :     struct MiraMonArcLayer *pMMArcLayer;
    3099             : 
    3100             :     if (hMiraMonLayer->bIsPolygon)
    3101             :         pMMArcLayer = &hMiraMonLayer->MMPolygon.MMArc;
    3102             :     else
    3103             :         pMMArcLayer = &hMiraMonLayer->MMArc;
    3104             : 
    3105             :     nElem = pMMArcLayer->TopNodeHeader.nElemCount;
    3106             : 
    3107             :     nBlockSize = nElem * pMMArcLayer->MMNode.nSizeNodeHeader;
    3108             : 
    3109             :     if (MMInitFlush(&FlushTMP, pMMArcLayer->MMNode.pF, nBlockSize, &pBuffer,
    3110             :                     hMiraMonLayer->nHeaderDiskSize, 0))
    3111             :     {
    3112             :         if (pBuffer)
    3113             :             VSIFree(pBuffer);
    3114             :         return 1;
    3115             :     }
    3116             : 
    3117             :     FlushTMP.pBlockWhereToSaveOrRead = (void *)pBuffer;
    3118             :     if (MMReadFlush(&FlushTMP))
    3119             :     {
    3120             :         if (pBuffer)
    3121             :             VSIFree(pBuffer);
    3122             :         return 1;
    3123             :     }
    3124             : 
    3125             :     for (iElem = 0; iElem < nElem; iElem++)
    3126             :     {
    3127             :         // Arcs count
    3128             :         FlushTMP.pBlockToBeSaved =
    3129             :             (void *)&pMMArcLayer->MMNode.pNodeHeader[iElem].nArcsCount;
    3130             :         FlushTMP.SizeOfBlockToBeSaved =
    3131             :             sizeof(pMMArcLayer->MMNode.pNodeHeader[iElem].nArcsCount);
    3132             :         if (MMReadBlockFromBuffer(&FlushTMP))
    3133             :         {
    3134             :             if (pBuffer)
    3135             :                 VSIFree(pBuffer);
    3136             :             return 1;
    3137             :         }
    3138             :         // Node type
    3139             :         FlushTMP.pBlockToBeSaved =
    3140             :             (void *)&pMMArcLayer->MMNode.pNodeHeader[iElem].cNodeType;
    3141             :         FlushTMP.SizeOfBlockToBeSaved =
    3142             :             sizeof(pMMArcLayer->MMNode.pNodeHeader[iElem].cNodeType);
    3143             :         if (MMReadBlockFromBuffer(&FlushTMP))
    3144             :         {
    3145             :             if (pBuffer)
    3146             :                 VSIFree(pBuffer);
    3147             :             return 1;
    3148             :         }
    3149             :         FlushTMP.SizeOfBlockToBeSaved = 1;
    3150             :         FlushTMP.pBlockToBeSaved = (void *)nullptr;
    3151             :         if (MMReadBlockFromBuffer(&FlushTMP))
    3152             :         {
    3153             :             if (pBuffer)
    3154             :                 VSIFree(pBuffer);
    3155             :             return 1;
    3156             :         }
    3157             : 
    3158             :         // Offset: offset of the first arc to the node
    3159             :         if (MMReadOffsetDependingOnVersion(
    3160             :                 hMiraMonLayer, &FlushTMP,
    3161             :                 &pMMArcLayer->MMNode.pNodeHeader[iElem].nOffset))
    3162             :         {
    3163             :             if (pBuffer)
    3164             :                 VSIFree(pBuffer);
    3165             :             return 1;
    3166             :         }
    3167             :     }
    3168             : 
    3169             :     if (pBuffer)
    3170             :         VSIFree(pBuffer);
    3171             :     return 0;
    3172             : }
    3173             : #endif  // JUST_IN_CASE_WE_NEED_IT_SOMEDAY
    3174             : 
    3175          58 : int MMWriteNHNodeSection(struct MiraMonVectLayerInfo *hMiraMonLayer,
    3176             :                          MM_FILE_OFFSET DiskOffset)
    3177             : {
    3178             :     MM_INTERNAL_FID iElem;
    3179             :     struct MM_FLUSH_INFO FlushTMP;
    3180          58 :     char *pBuffer = nullptr;
    3181             :     uint32_t nUL32;
    3182             :     MM_FILE_OFFSET nOffsetDiff;
    3183             :     struct MiraMonArcLayer *pMMArcLayer;
    3184             : 
    3185          58 :     if (!hMiraMonLayer)
    3186           0 :         return 1;
    3187             : 
    3188          58 :     if (hMiraMonLayer->bIsPolygon)
    3189          27 :         pMMArcLayer = &hMiraMonLayer->MMPolygon.MMArc;
    3190             :     else
    3191          31 :         pMMArcLayer = &hMiraMonLayer->MMArc;
    3192             : 
    3193          58 :     nOffsetDiff = hMiraMonLayer->nHeaderDiskSize +
    3194          58 :                   (pMMArcLayer->TopNodeHeader.nElemCount *
    3195          58 :                    pMMArcLayer->MMNode.nSizeNodeHeader);
    3196             : 
    3197          58 :     if (MMInitFlush(&FlushTMP, pMMArcLayer->MMNode.pF, MM_1MB, &pBuffer,
    3198             :                     DiskOffset, 0))
    3199             :     {
    3200           0 :         if (pBuffer)
    3201           0 :             VSIFree(pBuffer);
    3202           0 :         return 1;
    3203             :     }
    3204             : 
    3205          58 :     FlushTMP.pBlockWhereToSaveOrRead = (void *)pBuffer;
    3206         209 :     for (iElem = 0; iElem < pMMArcLayer->TopNodeHeader.nElemCount; iElem++)
    3207             :     {
    3208             :         // Arcs count
    3209         151 :         FlushTMP.SizeOfBlockToBeSaved =
    3210             :             sizeof(pMMArcLayer->MMNode.pNodeHeader[iElem].nArcsCount);
    3211         151 :         hMiraMonLayer->OffsetCheck += FlushTMP.SizeOfBlockToBeSaved;
    3212         151 :         FlushTMP.pBlockToBeSaved =
    3213         151 :             (void *)&pMMArcLayer->MMNode.pNodeHeader[iElem].nArcsCount;
    3214         151 :         if (MMAppendBlockToBuffer(&FlushTMP))
    3215             :         {
    3216           0 :             if (pBuffer)
    3217           0 :                 VSIFree(pBuffer);
    3218           0 :             return 1;
    3219             :         }
    3220             :         // Node type
    3221         151 :         FlushTMP.SizeOfBlockToBeSaved =
    3222             :             sizeof(pMMArcLayer->MMNode.pNodeHeader[iElem].cNodeType);
    3223         151 :         hMiraMonLayer->OffsetCheck += FlushTMP.SizeOfBlockToBeSaved;
    3224         151 :         FlushTMP.pBlockToBeSaved =
    3225         151 :             (void *)&pMMArcLayer->MMNode.pNodeHeader[iElem].cNodeType;
    3226         151 :         if (MMAppendBlockToBuffer(&FlushTMP))
    3227             :         {
    3228           0 :             if (pBuffer)
    3229           0 :                 VSIFree(pBuffer);
    3230           0 :             return 1;
    3231             :         }
    3232         151 :         FlushTMP.SizeOfBlockToBeSaved = 1;
    3233         151 :         hMiraMonLayer->OffsetCheck += FlushTMP.SizeOfBlockToBeSaved;
    3234         151 :         FlushTMP.pBlockToBeSaved = (void *)nullptr;
    3235         151 :         if (MMAppendBlockToBuffer(&FlushTMP))
    3236             :         {
    3237           0 :             if (pBuffer)
    3238           0 :                 VSIFree(pBuffer);
    3239           0 :             return 1;
    3240             :         }
    3241             : 
    3242             :         // Offset: offset of the first arc to the node
    3243         151 :         if (MMAppendIntegerDependingOnVersion(
    3244             :                 hMiraMonLayer, &FlushTMP, &nUL32,
    3245         151 :                 pMMArcLayer->MMNode.pNodeHeader[iElem].nOffset + nOffsetDiff))
    3246             :         {
    3247           0 :             if (pBuffer)
    3248           0 :                 VSIFree(pBuffer);
    3249           0 :             return 1;
    3250             :         }
    3251             :     }
    3252          58 :     FlushTMP.SizeOfBlockToBeSaved = 0;
    3253          58 :     if (MMAppendBlockToBuffer(&FlushTMP))
    3254             :     {
    3255           0 :         if (pBuffer)
    3256           0 :             VSIFree(pBuffer);
    3257           0 :         return 1;
    3258             :     }
    3259             : 
    3260          58 :     if (pBuffer)
    3261          58 :         VSIFree(pBuffer);
    3262          58 :     return 0;
    3263             : }
    3264             : 
    3265          44 : int MMReadPHPolygonSection(struct MiraMonVectLayerInfo *hMiraMonLayer)
    3266             : {
    3267             :     MM_INTERNAL_FID iElem;
    3268             :     struct MM_FLUSH_INFO FlushTMP;
    3269          44 :     char *pBuffer = nullptr;
    3270             :     MM_FILE_OFFSET nBlockSize;
    3271             :     struct MiraMonPolygonLayer *pMMPolygonLayer;
    3272             : 
    3273          44 :     if (!hMiraMonLayer)
    3274           0 :         return 1;
    3275             : 
    3276          44 :     pMMPolygonLayer = &hMiraMonLayer->MMPolygon;
    3277             : 
    3278          44 :     if (MMCheckSize_t(hMiraMonLayer->TopHeader.nElemCount,
    3279          88 :                       pMMPolygonLayer->nPHElementSize) ||
    3280          44 :         MMCheckSize_t(hMiraMonLayer->MMPolygon.TopArcHeader.nElemCount,
    3281          44 :                       hMiraMonLayer->MMPolygon.nPSElementSize))
    3282             :     {
    3283           0 :         return 1;
    3284             :     }
    3285          44 :     nBlockSize =
    3286          44 :         hMiraMonLayer->TopHeader.nElemCount * (pMMPolygonLayer->nPHElementSize);
    3287             : 
    3288          44 :     if (MMInitFlush(&FlushTMP, pMMPolygonLayer->pF, nBlockSize, &pBuffer,
    3289          44 :                     hMiraMonLayer->nHeaderDiskSize +
    3290          44 :                         (hMiraMonLayer->MMPolygon.TopArcHeader.nElemCount *
    3291          44 :                          hMiraMonLayer->MMPolygon.nPSElementSize),
    3292             :                     0))
    3293             :     {
    3294           0 :         if (pBuffer)
    3295           0 :             VSIFree(pBuffer);
    3296           0 :         return 1;
    3297             :     }
    3298          44 :     FlushTMP.pBlockWhereToSaveOrRead = (void *)pBuffer;
    3299          44 :     if (MMReadFlush(&FlushTMP))
    3300             :     {
    3301           0 :         if (pBuffer)
    3302           0 :             VSIFree(pBuffer);
    3303           0 :         return 1;
    3304             :     }
    3305             : 
    3306         175 :     for (iElem = 0; iElem < hMiraMonLayer->TopHeader.nElemCount; iElem++)
    3307             :     {
    3308             :         // Bounding box
    3309         131 :         FlushTMP.pBlockToBeSaved =
    3310         131 :             (void *)&(pMMPolygonLayer->pPolHeader[iElem].dfBB.dfMinX);
    3311         131 :         FlushTMP.SizeOfBlockToBeSaved =
    3312             :             sizeof(pMMPolygonLayer->pPolHeader[iElem].dfBB.dfMinX);
    3313         131 :         if (MMReadBlockFromBuffer(&FlushTMP))
    3314             :         {
    3315           0 :             if (pBuffer)
    3316           0 :                 VSIFree(pBuffer);
    3317           0 :             return 1;
    3318             :         }
    3319         131 :         FlushTMP.pBlockToBeSaved =
    3320         131 :             (void *)&pMMPolygonLayer->pPolHeader[iElem].dfBB.dfMaxX;
    3321         131 :         FlushTMP.SizeOfBlockToBeSaved =
    3322             :             sizeof(pMMPolygonLayer->pPolHeader[iElem].dfBB.dfMaxX);
    3323         131 :         if (MMReadBlockFromBuffer(&FlushTMP))
    3324             :         {
    3325           0 :             if (pBuffer)
    3326           0 :                 VSIFree(pBuffer);
    3327           0 :             return 1;
    3328             :         }
    3329         131 :         FlushTMP.pBlockToBeSaved =
    3330         131 :             (void *)&pMMPolygonLayer->pPolHeader[iElem].dfBB.dfMinY;
    3331         131 :         FlushTMP.SizeOfBlockToBeSaved =
    3332             :             sizeof(pMMPolygonLayer->pPolHeader[iElem].dfBB.dfMinY);
    3333         131 :         if (MMReadBlockFromBuffer(&FlushTMP))
    3334             :         {
    3335           0 :             if (pBuffer)
    3336           0 :                 VSIFree(pBuffer);
    3337           0 :             return 1;
    3338             :         }
    3339         131 :         FlushTMP.pBlockToBeSaved =
    3340         131 :             (void *)&pMMPolygonLayer->pPolHeader[iElem].dfBB.dfMaxY;
    3341         131 :         FlushTMP.SizeOfBlockToBeSaved =
    3342             :             sizeof(pMMPolygonLayer->pPolHeader[iElem].dfBB.dfMaxY);
    3343         131 :         if (MMReadBlockFromBuffer(&FlushTMP))
    3344             :         {
    3345           0 :             if (pBuffer)
    3346           0 :                 VSIFree(pBuffer);
    3347           0 :             return 1;
    3348             :         }
    3349             : 
    3350             :         // Arcs count: number of arcs of the polygon
    3351         131 :         if (MMReadGUInt64DependingOnVersion(
    3352             :                 hMiraMonLayer, &FlushTMP,
    3353         131 :                 &pMMPolygonLayer->pPolHeader[iElem].nArcsCount))
    3354             :         {
    3355           0 :             if (pBuffer)
    3356           0 :                 VSIFree(pBuffer);
    3357           0 :             return 1;
    3358             :         }
    3359             : 
    3360             :         // External arcs count: number of external arcs of the polygon
    3361         131 :         if (MMReadGUInt64DependingOnVersion(
    3362             :                 hMiraMonLayer, &FlushTMP,
    3363         131 :                 &pMMPolygonLayer->pPolHeader[iElem].nExternalRingsCount))
    3364             :         {
    3365           0 :             if (pBuffer)
    3366           0 :                 VSIFree(pBuffer);
    3367           0 :             return 1;
    3368             :         }
    3369             : 
    3370             :         // Rings count: number of rings of the polygon
    3371         131 :         if (MMReadGUInt64DependingOnVersion(
    3372             :                 hMiraMonLayer, &FlushTMP,
    3373         131 :                 &pMMPolygonLayer->pPolHeader[iElem].nRingsCount))
    3374             :         {
    3375           0 :             if (pBuffer)
    3376           0 :                 VSIFree(pBuffer);
    3377           0 :             return 1;
    3378             :         }
    3379             : 
    3380             :         // Offset: offset of the first vertex of the arc
    3381         131 :         if (MMReadOffsetDependingOnVersion(
    3382             :                 hMiraMonLayer, &FlushTMP,
    3383         131 :                 &pMMPolygonLayer->pPolHeader[iElem].nOffset))
    3384             :         {
    3385           0 :             if (pBuffer)
    3386           0 :                 VSIFree(pBuffer);
    3387           0 :             return 1;
    3388             :         }
    3389             : 
    3390             :         // Perimeter of the arc
    3391         131 :         FlushTMP.SizeOfBlockToBeSaved =
    3392             :             sizeof(pMMPolygonLayer->pPolHeader[iElem].dfPerimeter);
    3393         131 :         FlushTMP.pBlockToBeSaved =
    3394         131 :             (void *)&pMMPolygonLayer->pPolHeader[iElem].dfPerimeter;
    3395         131 :         if (MMReadBlockFromBuffer(&FlushTMP))
    3396             :         {
    3397           0 :             if (pBuffer)
    3398           0 :                 VSIFree(pBuffer);
    3399           0 :             return 1;
    3400             :         }
    3401             : 
    3402             :         // Area of the arc
    3403         131 :         FlushTMP.SizeOfBlockToBeSaved =
    3404             :             sizeof(pMMPolygonLayer->pPolHeader[iElem].dfArea);
    3405         131 :         FlushTMP.pBlockToBeSaved =
    3406         131 :             (void *)&pMMPolygonLayer->pPolHeader[iElem].dfArea;
    3407         131 :         if (MMReadBlockFromBuffer(&FlushTMP))
    3408             :         {
    3409           0 :             if (pBuffer)
    3410           0 :                 VSIFree(pBuffer);
    3411           0 :             return 1;
    3412             :         }
    3413             :     }
    3414             : 
    3415          44 :     if (pBuffer)
    3416          44 :         VSIFree(pBuffer);
    3417          44 :     return 0;
    3418             : }
    3419             : 
    3420          27 : int MMWritePHPolygonSection(struct MiraMonVectLayerInfo *hMiraMonLayer,
    3421             :                             MM_FILE_OFFSET DiskOffset)
    3422             : {
    3423             :     MM_INTERNAL_FID iElem;
    3424             :     struct MM_FLUSH_INFO FlushTMP;
    3425          27 :     char *pBuffer = nullptr;
    3426             :     uint32_t nUL32;
    3427             :     MM_FILE_OFFSET nOffsetDiff;
    3428             :     struct MiraMonPolygonLayer *pMMPolygonLayer;
    3429             : 
    3430          27 :     if (!hMiraMonLayer)
    3431           0 :         return 1;
    3432             : 
    3433          27 :     pMMPolygonLayer = &hMiraMonLayer->MMPolygon;
    3434             : 
    3435          27 :     if (!pMMPolygonLayer->pF)
    3436           0 :         return 0;
    3437             : 
    3438          27 :     if (!hMiraMonLayer->nFinalElemCount)
    3439           0 :         return 0;
    3440             : 
    3441          27 :     nOffsetDiff = DiskOffset + hMiraMonLayer->TopHeader.nElemCount *
    3442          27 :                                    (pMMPolygonLayer->nPHElementSize);
    3443             : 
    3444          27 :     if (MMInitFlush(&FlushTMP, pMMPolygonLayer->pF, MM_1MB, &pBuffer,
    3445             :                     DiskOffset, 0))
    3446             :     {
    3447           0 :         if (pBuffer)
    3448           0 :             VSIFree(pBuffer);
    3449           0 :         return 1;
    3450             :     }
    3451             : 
    3452          27 :     FlushTMP.pBlockWhereToSaveOrRead = (void *)pBuffer;
    3453          95 :     for (iElem = 0; iElem < hMiraMonLayer->nFinalElemCount; iElem++)
    3454             :     {
    3455             :         // Bounding box
    3456          68 :         FlushTMP.SizeOfBlockToBeSaved =
    3457             :             sizeof(pMMPolygonLayer->pPolHeader[iElem].dfBB.dfMinX);
    3458          68 :         FlushTMP.pBlockToBeSaved =
    3459          68 :             (void *)&pMMPolygonLayer->pPolHeader[iElem].dfBB.dfMinX;
    3460          68 :         hMiraMonLayer->OffsetCheck += FlushTMP.SizeOfBlockToBeSaved;
    3461          68 :         if (MMAppendBlockToBuffer(&FlushTMP))
    3462             :         {
    3463           0 :             if (pBuffer)
    3464           0 :                 VSIFree(pBuffer);
    3465           0 :             return 1;
    3466             :         }
    3467          68 :         FlushTMP.pBlockToBeSaved =
    3468          68 :             (void *)&pMMPolygonLayer->pPolHeader[iElem].dfBB.dfMaxX;
    3469          68 :         hMiraMonLayer->OffsetCheck += FlushTMP.SizeOfBlockToBeSaved;
    3470          68 :         if (MMAppendBlockToBuffer(&FlushTMP))
    3471             :         {
    3472           0 :             if (pBuffer)
    3473           0 :                 VSIFree(pBuffer);
    3474           0 :             return 1;
    3475             :         }
    3476          68 :         FlushTMP.pBlockToBeSaved =
    3477          68 :             (void *)&pMMPolygonLayer->pPolHeader[iElem].dfBB.dfMinY;
    3478          68 :         hMiraMonLayer->OffsetCheck += FlushTMP.SizeOfBlockToBeSaved;
    3479          68 :         if (MMAppendBlockToBuffer(&FlushTMP))
    3480             :         {
    3481           0 :             if (pBuffer)
    3482           0 :                 VSIFree(pBuffer);
    3483           0 :             return 1;
    3484             :         }
    3485          68 :         FlushTMP.pBlockToBeSaved =
    3486          68 :             (void *)&pMMPolygonLayer->pPolHeader[iElem].dfBB.dfMaxY;
    3487          68 :         hMiraMonLayer->OffsetCheck += FlushTMP.SizeOfBlockToBeSaved;
    3488          68 :         if (MMAppendBlockToBuffer(&FlushTMP))
    3489             :         {
    3490           0 :             if (pBuffer)
    3491           0 :                 VSIFree(pBuffer);
    3492           0 :             return 1;
    3493             :         }
    3494             : 
    3495             :         // Arcs count: number of the arcs of the polygon
    3496          68 :         if (MMAppendIntegerDependingOnVersion(
    3497             :                 hMiraMonLayer, &FlushTMP, &nUL32,
    3498          68 :                 pMMPolygonLayer->pPolHeader[iElem].nArcsCount))
    3499             :         {
    3500           0 :             if (pBuffer)
    3501           0 :                 VSIFree(pBuffer);
    3502           0 :             return 1;
    3503             :         }
    3504             : 
    3505             :         // External arcs count: number of external arcs of the polygon
    3506          68 :         if (MMAppendIntegerDependingOnVersion(
    3507             :                 hMiraMonLayer, &FlushTMP, &nUL32,
    3508          68 :                 pMMPolygonLayer->pPolHeader[iElem].nExternalRingsCount))
    3509             :         {
    3510           0 :             if (pBuffer)
    3511           0 :                 VSIFree(pBuffer);
    3512           0 :             return 1;
    3513             :         }
    3514             : 
    3515             :         // Rings count: number of rings of the polygon
    3516          68 :         if (MMAppendIntegerDependingOnVersion(
    3517             :                 hMiraMonLayer, &FlushTMP, &nUL32,
    3518          68 :                 pMMPolygonLayer->pPolHeader[iElem].nRingsCount))
    3519             :         {
    3520           0 :             if (pBuffer)
    3521           0 :                 VSIFree(pBuffer);
    3522           0 :             return 1;
    3523             :         }
    3524             : 
    3525             :         // Offset: offset of the first vertex of the arc
    3526          68 :         if (MMAppendIntegerDependingOnVersion(
    3527             :                 hMiraMonLayer, &FlushTMP, &nUL32,
    3528          68 :                 pMMPolygonLayer->pPolHeader[iElem].nOffset + nOffsetDiff))
    3529             :         {
    3530           0 :             if (pBuffer)
    3531           0 :                 VSIFree(pBuffer);
    3532           0 :             return 1;
    3533             :         }
    3534             : 
    3535             :         // Perimeter of the arc
    3536          68 :         FlushTMP.SizeOfBlockToBeSaved =
    3537             :             sizeof(pMMPolygonLayer->pPolHeader[iElem].dfPerimeter);
    3538          68 :         hMiraMonLayer->OffsetCheck += FlushTMP.SizeOfBlockToBeSaved;
    3539          68 :         FlushTMP.pBlockToBeSaved =
    3540          68 :             (void *)&pMMPolygonLayer->pPolHeader[iElem].dfPerimeter;
    3541          68 :         if (MMAppendBlockToBuffer(&FlushTMP))
    3542             :         {
    3543           0 :             if (pBuffer)
    3544           0 :                 VSIFree(pBuffer);
    3545           0 :             return 1;
    3546             :         }
    3547             : 
    3548             :         // Area of the arc
    3549          68 :         FlushTMP.SizeOfBlockToBeSaved =
    3550             :             sizeof(pMMPolygonLayer->pPolHeader[iElem].dfArea);
    3551          68 :         hMiraMonLayer->OffsetCheck += FlushTMP.SizeOfBlockToBeSaved;
    3552          68 :         FlushTMP.pBlockToBeSaved =
    3553          68 :             (void *)&pMMPolygonLayer->pPolHeader[iElem].dfArea;
    3554          68 :         if (MMAppendBlockToBuffer(&FlushTMP))
    3555             :         {
    3556           0 :             if (pBuffer)
    3557           0 :                 VSIFree(pBuffer);
    3558           0 :             return 1;
    3559             :         }
    3560             :     }
    3561          27 :     FlushTMP.SizeOfBlockToBeSaved = 0;
    3562          27 :     if (MMAppendBlockToBuffer(&FlushTMP))
    3563             :     {
    3564           0 :         if (pBuffer)
    3565           0 :             VSIFree(pBuffer);
    3566           0 :         return 1;
    3567             :     }
    3568             : 
    3569          27 :     if (pBuffer)
    3570          27 :         VSIFree(pBuffer);
    3571          27 :     return 0;
    3572             : }
    3573             : 
    3574             : /* -------------------------------------------------------------------- */
    3575             : /*      Feature Functions                                               */
    3576             : /* -------------------------------------------------------------------- */
    3577          85 : int MMInitFeature(struct MiraMonFeature *hMMFeature)
    3578             : {
    3579          85 :     memset(hMMFeature, 0, sizeof(*hMMFeature));
    3580             : 
    3581          85 :     hMMFeature->nMaxMRecords = MM_INIT_NUMBER_OF_RECORDS;
    3582          85 :     if (MMCheckSize_t(hMMFeature->nMaxMRecords,
    3583             :                       sizeof(*(hMMFeature->pRecords))))
    3584           0 :         return 1;
    3585             : 
    3586          85 :     if (!hMMFeature->nMaxMRecords)
    3587           0 :         return 0;  // No elements nothing to do.
    3588             : 
    3589          85 :     if ((hMMFeature->pRecords = VSICalloc((size_t)hMMFeature->nMaxMRecords,
    3590             :                                           sizeof(*(hMMFeature->pRecords)))) ==
    3591             :         nullptr)
    3592           0 :         return 1;
    3593             : 
    3594          85 :     hMMFeature->pRecords[0].nMaxField = MM_INIT_NUMBER_OF_FIELDS;
    3595          85 :     hMMFeature->pRecords[0].nNumField = 0;
    3596          85 :     if (MMCheckSize_t(hMMFeature->pRecords[0].nMaxField,
    3597             :                       sizeof(*(hMMFeature->pRecords[0].pField))))
    3598           0 :         return 1;
    3599          85 :     if (nullptr == (hMMFeature->pRecords[0].pField =
    3600          85 :                         VSICalloc((size_t)hMMFeature->pRecords[0].nMaxField,
    3601             :                                   sizeof(*(hMMFeature->pRecords[0].pField)))))
    3602           0 :         return 1;
    3603             : 
    3604          85 :     return 0;
    3605             : }
    3606             : 
    3607             : // Conserves all allocated memory but resets the information
    3608         565 : void MMResetFeatureGeometry(struct MiraMonFeature *hMMFeature)
    3609             : {
    3610         565 :     if (hMMFeature->pNCoordRing)
    3611             :     {
    3612         420 :         memset(hMMFeature->pNCoordRing, 0,
    3613         420 :                (size_t)hMMFeature->nMaxpNCoordRing *
    3614             :                    sizeof(*(hMMFeature->pNCoordRing)));
    3615             :     }
    3616         565 :     if (hMMFeature->pCoord)
    3617             :     {
    3618         420 :         memset(hMMFeature->pCoord, 0,
    3619         420 :                (size_t)hMMFeature->nMaxpCoord * sizeof(*(hMMFeature->pCoord)));
    3620             :     }
    3621         565 :     hMMFeature->nICoord = 0;
    3622         565 :     if (hMMFeature->pZCoord)
    3623             :     {
    3624         281 :         memset(hMMFeature->pZCoord, 0,
    3625         281 :                (size_t)hMMFeature->nMaxpZCoord *
    3626             :                    sizeof(*(hMMFeature->pZCoord)));
    3627             :     }
    3628         565 :     hMMFeature->nNRings = 0;
    3629         565 :     hMMFeature->nIRing = 0;
    3630             : 
    3631         565 :     if (hMMFeature->flag_VFG)
    3632             :     {
    3633         330 :         memset(hMMFeature->flag_VFG, 0,
    3634         330 :                (size_t)hMMFeature->nMaxVFG * sizeof(*(hMMFeature->flag_VFG)));
    3635             :     }
    3636         565 : }
    3637             : 
    3638             : // Preserves all allocated memory but initializes it to zero.
    3639         562 : void MMResetFeatureRecord(struct MiraMonFeature *hMMFeature)
    3640             : {
    3641             :     MM_EXT_DBF_N_MULTIPLE_RECORDS nIRecord;
    3642             :     MM_EXT_DBF_N_FIELDS nIField;
    3643             : 
    3644         562 :     if (!hMMFeature->pRecords)
    3645         352 :         return;
    3646             : 
    3647         450 :     for (nIRecord = 0; nIRecord < hMMFeature->nMaxMRecords; nIRecord++)
    3648             :     {
    3649         240 :         if (!hMMFeature->pRecords[nIRecord].pField)
    3650          25 :             continue;
    3651        4565 :         for (nIField = 0; nIField < hMMFeature->pRecords[nIRecord].nMaxField;
    3652        4350 :              nIField++)
    3653             :         {
    3654        4350 :             if (hMMFeature->pRecords[nIRecord].pField[nIField].pDinValue)
    3655         912 :                 *(hMMFeature->pRecords[nIRecord].pField[nIField].pDinValue) =
    3656             :                     '\0';
    3657        4350 :             hMMFeature->pRecords[nIRecord].pField[nIField].bIsValid = 0;
    3658             :         }
    3659         215 :         hMMFeature->pRecords[nIRecord].nNumField = 0;
    3660             :     }
    3661         210 :     hMMFeature->nNumMRecords = 0;
    3662             : }
    3663             : 
    3664             : // Destroys all allocated memory
    3665         206 : void MMDestroyFeature(struct MiraMonFeature *hMMFeature)
    3666             : {
    3667         206 :     if (hMMFeature->pCoord)
    3668             :     {
    3669          67 :         VSIFree(hMMFeature->pCoord);
    3670          67 :         hMMFeature->pCoord = nullptr;
    3671             :     }
    3672         206 :     if (hMMFeature->pZCoord)
    3673             :     {
    3674          67 :         VSIFree(hMMFeature->pZCoord);
    3675          67 :         hMMFeature->pZCoord = nullptr;
    3676             :     }
    3677         206 :     if (hMMFeature->pNCoordRing)
    3678             :     {
    3679          67 :         VSIFree(hMMFeature->pNCoordRing);
    3680          67 :         hMMFeature->pNCoordRing = nullptr;
    3681             :     }
    3682             : 
    3683         206 :     if (hMMFeature->flag_VFG)
    3684             :     {
    3685          27 :         VSIFree(hMMFeature->flag_VFG);
    3686          27 :         hMMFeature->flag_VFG = nullptr;
    3687             :     }
    3688             : 
    3689         206 :     if (hMMFeature->pRecords)
    3690             :     {
    3691             :         MM_EXT_DBF_N_MULTIPLE_RECORDS nIRecord;
    3692             :         MM_EXT_DBF_N_FIELDS nIField;
    3693             : 
    3694         264 :         for (nIRecord = 0; nIRecord < hMMFeature->nMaxMRecords; nIRecord++)
    3695             :         {
    3696         179 :             if (!hMMFeature->pRecords[nIRecord].pField)
    3697          75 :                 continue;
    3698         104 :             for (nIField = 0;
    3699        2314 :                  nIField < hMMFeature->pRecords[nIRecord].nMaxField; nIField++)
    3700             :             {
    3701        2210 :                 if (hMMFeature->pRecords[nIRecord].pField[nIField].pDinValue)
    3702         422 :                     VSIFree(hMMFeature->pRecords[nIRecord]
    3703         422 :                                 .pField[nIField]
    3704         422 :                                 .pDinValue);
    3705             :             }
    3706         104 :             VSIFree(hMMFeature->pRecords[nIRecord].pField);
    3707             :         }
    3708          85 :         VSIFree(hMMFeature->pRecords);
    3709          85 :         hMMFeature->pRecords = nullptr;
    3710             :     }
    3711             : 
    3712         206 :     hMMFeature->nNRings = 0;
    3713         206 :     hMMFeature->nNumMRecords = 0;
    3714         206 :     hMMFeature->nMaxMRecords = 0;
    3715         206 : }
    3716             : 
    3717             : // Creates a MiraMon polygon, multipolygon, or linestring (arc) feature.
    3718          90 : static int MMCreateFeaturePolOrArc(struct MiraMonVectLayerInfo *hMiraMonLayer,
    3719             :                                    struct MiraMonFeature *hMMFeature)
    3720             : {
    3721          90 :     double *pZ = nullptr;
    3722             :     struct MM_POINT_2D *pCoord, *pCoordReal;
    3723             :     MM_POLYGON_RINGS_COUNT nIPart;
    3724             :     MM_N_VERTICES_TYPE nIVertice;
    3725             :     double dtempx, dtempy;
    3726             :     MM_POLYGON_RINGS_COUNT nExternalRingsCount;
    3727          90 :     struct MM_PH *pCurrentPolHeader = nullptr;
    3728             :     struct MM_AH *pCurrentArcHeader;
    3729             :     // To access how many points have been stored in the last stringline
    3730          90 :     struct MM_AH *pLastArcHeader = nullptr;
    3731          90 :     struct MM_NH *pCurrentNodeHeader, *pCurrentNodeHeaderPlus1 = nullptr;
    3732             :     uint32_t UnsignedLongNumber;
    3733             :     struct MiraMonArcLayer *pMMArc;
    3734             :     struct MiraMonNodeLayer *pMMNode;
    3735             :     struct MM_TH *pArcTopHeader;
    3736             :     struct MM_TH *pNodeTopHeader;
    3737          90 :     char VFG = 0;
    3738             :     MM_FILE_OFFSET nOffsetTmp;
    3739          90 :     struct MM_ZD *pZDesc = nullptr;
    3740             :     struct MM_FLUSH_INFO *pFlushAL, *pFlushNL, *pFlushZL, *pFlushPS, *pFlushPAL;
    3741          90 :     MM_N_VERTICES_TYPE nPolVertices = 0;
    3742             :     MM_BOOLEAN bReverseArc;
    3743          90 :     int prevCoord = -1;
    3744          90 :     MM_BOOLEAN bPolZeroJustCreated = FALSE;
    3745             : 
    3746          90 :     if (!hMiraMonLayer)
    3747           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    3748             : 
    3749          90 :     if (!hMMFeature)
    3750           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    3751             : 
    3752             :     // Setting pointer to 3D structure (if exists).
    3753          90 :     if (hMiraMonLayer->TopHeader.bIs3d)
    3754          90 :         pZ = hMMFeature->pZCoord;
    3755             : 
    3756             :     // Setting pointers to arc/node structures.
    3757          90 :     if (hMiraMonLayer->bIsPolygon)
    3758             :     {
    3759          41 :         pMMArc = &hMiraMonLayer->MMPolygon.MMArc;
    3760          41 :         pArcTopHeader = &hMiraMonLayer->MMPolygon.TopArcHeader;
    3761             : 
    3762          41 :         pMMNode = &hMiraMonLayer->MMPolygon.MMArc.MMNode;
    3763          41 :         pNodeTopHeader = &hMiraMonLayer->MMPolygon.MMArc.TopNodeHeader;
    3764             :     }
    3765             :     else
    3766             :     {
    3767          49 :         pMMArc = &hMiraMonLayer->MMArc;
    3768          49 :         pArcTopHeader = &hMiraMonLayer->TopHeader;
    3769             : 
    3770          49 :         pMMNode = &hMiraMonLayer->MMArc.MMNode;
    3771          49 :         pNodeTopHeader = &hMiraMonLayer->MMArc.TopNodeHeader;
    3772             :     }
    3773             : 
    3774             :     // Setting pointers to polygon structures
    3775          90 :     if (hMiraMonLayer->bIsPolygon)
    3776             :     {
    3777          41 :         if (MMResizePolHeaderPointer(&hMiraMonLayer->MMPolygon.pPolHeader,
    3778          41 :                                      &hMiraMonLayer->MMPolygon.nMaxPolHeader,
    3779             :                                      hMiraMonLayer->TopHeader.nElemCount,
    3780             :                                      MM_INCR_NUMBER_OF_POLYGONS, 0))
    3781             :         {
    3782           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
    3783             :                      "Memory error in MiraMon "
    3784             :                      "driver (MMResizePolHeaderPointer())");
    3785           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    3786             :         }
    3787             : 
    3788          41 :         pCurrentPolHeader = hMiraMonLayer->MMPolygon.pPolHeader +
    3789          41 :                             hMiraMonLayer->TopHeader.nElemCount;
    3790          41 :         MMInitBoundingBox(&pCurrentPolHeader->dfBB);
    3791             : 
    3792          41 :         pCurrentPolHeader->dfPerimeter = 0;
    3793          41 :         pCurrentPolHeader->dfArea = 0L;
    3794             :     }
    3795             : 
    3796             :     // Setting flushes to all sections described in
    3797             :     // format specifications document.
    3798          90 :     pFlushAL = &pMMArc->FlushAL;
    3799          90 :     pFlushNL = &pMMNode->FlushNL;
    3800          90 :     pFlushZL = &pMMArc->pZSection.FlushZL;
    3801          90 :     pFlushPS = &hMiraMonLayer->MMPolygon.FlushPS;
    3802          90 :     pFlushPAL = &hMiraMonLayer->MMPolygon.FlushPAL;
    3803             : 
    3804          90 :     pFlushNL->pBlockWhereToSaveOrRead = (void *)pMMNode->pNL;
    3805          90 :     pFlushAL->pBlockWhereToSaveOrRead = (void *)pMMArc->pAL;
    3806          90 :     if (hMiraMonLayer->TopHeader.bIs3d)
    3807          90 :         pFlushZL->pBlockWhereToSaveOrRead = (void *)pMMArc->pZSection.pZL;
    3808          90 :     if (hMiraMonLayer->bIsPolygon)
    3809             :     {
    3810          41 :         pFlushPS->pBlockWhereToSaveOrRead =
    3811          41 :             (void *)hMiraMonLayer->MMPolygon.pPS;
    3812          41 :         pFlushPAL->pBlockWhereToSaveOrRead =
    3813          41 :             (void *)hMiraMonLayer->MMPolygon.pPAL;
    3814             :     }
    3815             : 
    3816             :     // Creation of the MiraMon extended database
    3817          90 :     if (!hMiraMonLayer->bIsPolygon)
    3818             :     {
    3819          49 :         if (hMiraMonLayer->TopHeader.nElemCount == 0)
    3820             :         {
    3821          31 :             CPLDebugOnly("MiraMon", "Creating MiraMon database");
    3822          31 :             if (MMCreateMMDB(hMiraMonLayer, hMMFeature->pCoord))
    3823           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    3824          31 :             CPLDebugOnly("MiraMon", "MiraMon database created. "
    3825             :                                     "Creating features...");
    3826             :         }
    3827             :     }
    3828             :     else
    3829             :     {  // Universal polygon has been created
    3830          41 :         if (hMiraMonLayer->TopHeader.nElemCount == 1)
    3831             :         {
    3832          27 :             CPLDebugOnly("MiraMon", "Creating MiraMon database");
    3833          27 :             if (MMCreateMMDB(hMiraMonLayer, hMMFeature->pCoord))
    3834           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    3835          27 :             CPLDebugOnly("MiraMon", "MiraMon database created. "
    3836             :                                     "Creating features...");
    3837             : 
    3838             :             // Universal polygon have a record with ID_GRAFIC=0 and blancs
    3839          27 :             if (MMAddPolygonRecordToMMDB(hMiraMonLayer, nullptr, 0, 0, nullptr))
    3840             :             {
    3841             :                 // Rare case where polygon zero creates the database
    3842             :                 // but some error occurs in the creation of the polygon zero.
    3843             :                 // The database must be destroyed and created again
    3844             :                 // next time the polygon zero is created.
    3845           0 :                 MMCloseMMBD_XP(hMiraMonLayer);
    3846           0 :                 MMDestroyMMDB(hMiraMonLayer);
    3847           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    3848             :             }
    3849          27 :             bPolZeroJustCreated = TRUE;
    3850             :         }
    3851             :     }
    3852             : 
    3853             :     // Checking if its possible continue writing the file due
    3854             :     // to version limitations.
    3855          90 :     if (hMiraMonLayer->LayerVersion == MM_32BITS_VERSION)
    3856             :     {
    3857             :         MM_FILE_OFFSET nNodeOffset, nArcOffset;
    3858             :         MM_INTERNAL_FID nArcElemCount, nNodeElemCount;
    3859          76 :         GInt32 nLastZCount = 0;
    3860          76 :         MM_FILE_OFFSET nLastOffsetZ = 0;
    3861          76 :         MM_INTERNAL_FID nLastElemCount = 0;
    3862          76 :         nNodeOffset = pFlushNL->TotalSavedBytes + pFlushNL->nNumBytes;
    3863          76 :         nArcOffset = pMMArc->nOffsetArc;
    3864             : 
    3865          76 :         nArcElemCount = pArcTopHeader->nElemCount;
    3866          76 :         nNodeElemCount = pNodeTopHeader->nElemCount;
    3867         164 :         for (nIPart = 0; nIPart < hMMFeature->nNRings; nIPart++,
    3868          88 :             nArcElemCount++,
    3869          88 :             nNodeElemCount += (hMiraMonLayer->bIsPolygon ? 1 : 2))
    3870             :         {
    3871             :             // There is space for the element that is going to be written?
    3872             :             // Polygon or arc
    3873          88 :             if (MMCheckVersionForFID(hMiraMonLayer,
    3874             :                                      hMiraMonLayer->TopHeader.nElemCount))
    3875             :             {
    3876           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
    3877             :                          "Error in MMCheckVersionForFID() (1)");
    3878           0 :                 return MM_STOP_WRITING_FEATURES;
    3879             :             }
    3880             : 
    3881             :             // Arc if there is no polygon
    3882          88 :             if (MMCheckVersionForFID(hMiraMonLayer, nArcElemCount))
    3883             :             {
    3884           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
    3885             :                          "Error in MMCheckVersionForFID() (2)");
    3886           0 :                 return MM_STOP_WRITING_FEATURES;
    3887             :             }
    3888             : 
    3889             :             // Nodes
    3890          88 :             if (MMCheckVersionForFID(hMiraMonLayer, nNodeElemCount))
    3891             :             {
    3892           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
    3893             :                          "Error in MMCheckVersionForFID() (3)");
    3894           0 :                 return MM_STOP_WRITING_FEATURES;
    3895             :             }
    3896             : 
    3897             :             // There is space for the last node(s) that is(are) going to be written?
    3898          88 :             if (!hMiraMonLayer->bIsPolygon)
    3899             :             {
    3900          41 :                 if (MMCheckVersionForFID(hMiraMonLayer, nNodeElemCount + 1))
    3901             :                 {
    3902           0 :                     CPLError(CE_Failure, CPLE_NotSupported,
    3903             :                              "Error in MMCheckVersionForFID() (4)");
    3904           0 :                     return MM_STOP_WRITING_FEATURES;
    3905             :                 }
    3906             :             }
    3907             : 
    3908             :             // Checking offsets
    3909             :             // AL: check the last point
    3910          88 :             if (MMCheckVersionOffset(hMiraMonLayer, nArcOffset))
    3911             :             {
    3912           0 :                 CPLDebugOnly("MiraMon", "Error in MMCheckVersionOffset() (0)");
    3913           0 :                 return MM_STOP_WRITING_FEATURES;
    3914             :             }
    3915             :             // Setting next offset
    3916          88 :             nArcOffset +=
    3917          88 :                 (hMMFeature->pNCoordRing[nIPart]) * pMMArc->nALElementSize;
    3918             : 
    3919             :             // NL: check the last node
    3920          88 :             if (hMiraMonLayer->bIsPolygon)
    3921          47 :                 nNodeOffset += (hMMFeature->nNRings) * MM_SIZE_OF_NL_32BITS;
    3922             :             else
    3923          41 :                 nNodeOffset += (2 * hMMFeature->nNRings) * MM_SIZE_OF_NL_32BITS;
    3924             : 
    3925          88 :             if (MMCheckVersionOffset(hMiraMonLayer, nNodeOffset))
    3926             :             {
    3927           0 :                 CPLDebugOnly("MiraMon", "Error in MMCheckVersionOffset() (1)");
    3928           0 :                 return MM_STOP_WRITING_FEATURES;
    3929             :             }
    3930             :             // Setting next offset
    3931          88 :             nNodeOffset += MM_SIZE_OF_NL_32BITS;
    3932             : 
    3933          88 :             if (!hMiraMonLayer->bIsPolygon)
    3934             :             {
    3935          41 :                 if (MMCheckVersionOffset(hMiraMonLayer, nNodeOffset))
    3936             :                 {
    3937           0 :                     CPLDebugOnly("MiraMon",
    3938             :                                  "Error in MMCheckVersionOffset() (2)");
    3939           0 :                     return MM_STOP_WRITING_FEATURES;
    3940             :                 }
    3941             :                 // Setting next offset
    3942          41 :                 nNodeOffset += MM_SIZE_OF_NL_32BITS;
    3943             :             }
    3944             : 
    3945             :             // Where 3D part is going to start
    3946          88 :             if (hMiraMonLayer->TopHeader.bIs3d)
    3947             :             {
    3948          88 :                 if (nArcElemCount == 0)
    3949             :                 {
    3950          54 :                     if (MMCheckVersionFor3DOffset(hMiraMonLayer,
    3951             :                                                   nArcElemCount + 1, 0, 0))
    3952           0 :                         return MM_STOP_WRITING_FEATURES;
    3953             :                 }
    3954             :                 else
    3955             :                 {
    3956          34 :                     pZDesc = pMMArc->pZSection.pZDescription;
    3957          34 :                     if (!pZDesc)
    3958             :                     {
    3959           0 :                         CPLError(CE_Failure, CPLE_ObjectNull,
    3960             :                                  "Error: pZDescription should not be nullptr");
    3961           0 :                         return MM_STOP_WRITING_FEATURES;
    3962             :                     }
    3963             : 
    3964          34 :                     if (nIPart == 0)
    3965             :                     {
    3966          22 :                         nLastZCount = pZDesc[nArcElemCount - 1].nZCount;
    3967          22 :                         nLastOffsetZ = pZDesc[nArcElemCount - 1].nOffsetZ;
    3968             :                     }
    3969             : 
    3970          34 :                     if (nLastZCount < 0)
    3971             :                     {
    3972             :                         // One altitude was written on last element
    3973          13 :                         if (MMCheckVersionFor3DOffset(
    3974             :                                 hMiraMonLayer, nArcElemCount + 1, nArcOffset,
    3975             :                                 nLastOffsetZ + sizeof(*pZ)))
    3976           0 :                             return MM_STOP_WRITING_FEATURES;
    3977             : 
    3978             :                         // For the next iteration in this multipart feature
    3979          13 :                         nLastOffsetZ += sizeof(*pZ);
    3980             :                     }
    3981             :                     else
    3982             :                     {
    3983             :                         // One for each vertice altitude was written on last element
    3984          21 :                         if (nIPart == 0)
    3985             :                         {
    3986           9 :                             nLastElemCount = (pMMArc->pArcHeader +
    3987           9 :                                               pArcTopHeader->nElemCount - 1)
    3988             :                                                  ->nElemCount;
    3989             :                         }
    3990             :                         else
    3991             :                         {
    3992          12 :                             nLastElemCount += hMMFeature->pNCoordRing[nIPart];
    3993             :                         }
    3994             : 
    3995          21 :                         if (MMCheckVersionFor3DOffset(
    3996             :                                 hMiraMonLayer, nArcElemCount + 1, nArcOffset,
    3997          21 :                                 nLastOffsetZ + sizeof(*pZ) * nLastElemCount))
    3998           0 :                             return MM_STOP_WRITING_FEATURES;
    3999             : 
    4000             :                         // For the next iteration in this multipart feature
    4001          21 :                         nLastOffsetZ += sizeof(*pZ) * nLastElemCount;
    4002             :                     }
    4003             :                 }
    4004             :             }
    4005             :         }
    4006             :     }
    4007             : 
    4008             :     // Going through parts of the feature.
    4009          90 :     nExternalRingsCount = 0;
    4010          90 :     pCoord = hMMFeature->pCoord;
    4011             : 
    4012          90 :     if (!pCoord)
    4013             :     {
    4014           0 :         if (bPolZeroJustCreated)
    4015             :         {
    4016             :             // Rare case where polygon zero creates the database
    4017             :             // but some error occurs in the creation of the polygon zero.
    4018             :             // The database must be destroyed and created again
    4019             :             // next time the polygon zero is created.
    4020           0 :             MMCloseMMBD_XP(hMiraMonLayer);
    4021           0 :             MMDestroyMMDB(hMiraMonLayer);
    4022             :         }
    4023           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    4024             :     }
    4025             : 
    4026             :     // Doing real job
    4027         192 :     for (nIPart = 0; nIPart < hMMFeature->nNRings; nIPart++,
    4028         102 :         pArcTopHeader->nElemCount++,
    4029         102 :         pNodeTopHeader->nElemCount += (hMiraMonLayer->bIsPolygon ? 1 : 2))
    4030             :     {
    4031             :         // Resize structures if necessary
    4032         102 :         if (MMResizeArcHeaderPointer(
    4033         102 :                 &pMMArc->pArcHeader, &pMMArc->nMaxArcHeader,
    4034         102 :                 pArcTopHeader->nElemCount + 1, MM_INCR_NUMBER_OF_ARCS, 0))
    4035             :         {
    4036           0 :             CPLDebugOnly("MiraMon", "Error in MMResizeArcHeaderPointer()");
    4037           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
    4038             :                      "Memory error in MiraMon "
    4039             :                      "driver (MMCreateFeaturePolOrArc())");
    4040           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    4041             :         }
    4042         102 :         if (MMResizeNodeHeaderPointer(
    4043         102 :                 &pMMNode->pNodeHeader, &pMMNode->nMaxNodeHeader,
    4044         102 :                 hMiraMonLayer->bIsPolygon ? pNodeTopHeader->nElemCount + 1
    4045          49 :                                           : pNodeTopHeader->nElemCount + 2,
    4046             :                 MM_INCR_NUMBER_OF_NODES, 0))
    4047             :         {
    4048           0 :             CPLDebugOnly("MiraMon", "Error in MMResizeNodeHeaderPointer()");
    4049           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
    4050             :                      "Memory error in MiraMon "
    4051             :                      "driver (MMCreateFeaturePolOrArc())");
    4052           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    4053             :         }
    4054             : 
    4055         102 :         if (hMiraMonLayer->TopHeader.bIs3d)
    4056             :         {
    4057         102 :             if (MMResizeZSectionDescrPointer(
    4058             :                     &pMMArc->pZSection.pZDescription,
    4059             :                     &pMMArc->pZSection.nMaxZDescription, pMMArc->nMaxArcHeader,
    4060             :                     MM_INCR_NUMBER_OF_ARCS, 0))
    4061             :             {
    4062           0 :                 CPLDebugOnly("MiraMon",
    4063             :                              "Error in MMResizeZSectionDescrPointer()");
    4064           0 :                 CPLError(CE_Failure, CPLE_OutOfMemory,
    4065             :                          "Memory error in MiraMon "
    4066             :                          "driver (MMCreateFeaturePolOrArc())");
    4067           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4068             :             }
    4069         102 :             pZDesc = pMMArc->pZSection.pZDescription;
    4070             :         }
    4071             : 
    4072             :         // Setting pointers to current headers
    4073         102 :         pCurrentArcHeader = pMMArc->pArcHeader + pArcTopHeader->nElemCount;
    4074         102 :         MMInitBoundingBox(&pCurrentArcHeader->dfBB);
    4075             : 
    4076         102 :         pCurrentNodeHeader = pMMNode->pNodeHeader + pNodeTopHeader->nElemCount;
    4077         102 :         if (!hMiraMonLayer->bIsPolygon)
    4078          49 :             pCurrentNodeHeaderPlus1 = pCurrentNodeHeader + 1;
    4079             : 
    4080             :         // Initializing feature information (section AH/PH)
    4081         102 :         pCurrentArcHeader->nElemCount = hMMFeature->pNCoordRing[nIPart];
    4082         102 :         pCurrentArcHeader->dfLength = 0.0;
    4083         102 :         pCurrentArcHeader->nOffset =
    4084         102 :             pFlushAL->TotalSavedBytes + pFlushAL->nNumBytes;
    4085             : 
    4086             :         // Dumping vertices and calculating stuff that
    4087             :         // MiraMon needs (longitude/perimeter, area)
    4088         102 :         bReverseArc = FALSE;
    4089         102 :         if (hMiraMonLayer->bIsPolygon)
    4090             :         {
    4091          53 :             VFG = hMMFeature->flag_VFG[nIPart];
    4092          53 :             bReverseArc = (VFG & MM_ROTATE_ARC) ? TRUE : FALSE;
    4093             :         }
    4094             : 
    4095         102 :         if (bReverseArc)
    4096             :         {
    4097           1 :             prevCoord = 1;  // to find previous coordinate
    4098           1 :             pCoordReal = pCoord + pCurrentArcHeader->nElemCount - 1;
    4099             :         }
    4100             :         else
    4101             :         {
    4102         101 :             prevCoord = -1;  // to find previous coordinate
    4103         101 :             pCoordReal = pCoord;
    4104             :         }
    4105             : 
    4106         572 :         for (nIVertice = 0; nIVertice < pCurrentArcHeader->nElemCount;
    4107         470 :              nIVertice++, (bReverseArc) ? pCoordReal-- : pCoordReal++)
    4108             :         {
    4109             :             // Writing the arc in the normal way
    4110         470 :             pFlushAL->SizeOfBlockToBeSaved = sizeof(pCoordReal->dfX);
    4111         470 :             pFlushAL->pBlockToBeSaved = (void *)&(pCoord + nIVertice)->dfX;
    4112         470 :             if (MMAppendBlockToBuffer(pFlushAL))
    4113             :             {
    4114           0 :                 CPLDebugOnly("MiraMon", "Error in MMAppendBlockToBuffer() (1)");
    4115           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4116             :             }
    4117             : 
    4118         470 :             pFlushAL->pBlockToBeSaved = (void *)&(pCoord + nIVertice)->dfY;
    4119         470 :             if (MMAppendBlockToBuffer(pFlushAL))
    4120             :             {
    4121           0 :                 CPLDebugOnly("MiraMon", "Error in MMAppendBlockToBuffer() (2)");
    4122           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4123             :             }
    4124             : 
    4125             :             // Calculating stuff using the inverse coordinates if it's needed
    4126         470 :             MMUpdateBoundingBoxXY(&pCurrentArcHeader->dfBB, pCoordReal);
    4127         470 :             if (nIVertice == 0 ||
    4128         368 :                 nIVertice == pCurrentArcHeader->nElemCount - 1)
    4129         204 :                 MMUpdateBoundingBoxXY(&pNodeTopHeader->hBB, pCoordReal);
    4130         470 :             if (nIVertice > 0)
    4131             :             {
    4132         368 :                 dtempx = pCoordReal->dfX - (pCoordReal + prevCoord)->dfX;
    4133         368 :                 dtempy = pCoordReal->dfY - (pCoordReal + prevCoord)->dfY;
    4134         368 :                 pCurrentArcHeader->dfLength +=
    4135         368 :                     sqrt(dtempx * dtempx + dtempy * dtempy);
    4136         368 :                 if (hMiraMonLayer->bIsPolygon && pCurrentPolHeader)
    4137             :                 {
    4138         262 :                     pCurrentPolHeader->dfArea +=
    4139         262 :                         (pCoordReal->dfX * (pCoordReal + prevCoord)->dfY -
    4140         262 :                          (pCoordReal + prevCoord)->dfX * pCoordReal->dfY);
    4141             :                 }
    4142             :             }
    4143             :         }
    4144         102 :         if (bReverseArc)
    4145           1 :             pCoord = pCoordReal + pCurrentArcHeader->nElemCount + 1;
    4146             :         else
    4147         101 :             pCoord += pCurrentArcHeader->nElemCount;
    4148             : 
    4149         102 :         nPolVertices += pCurrentArcHeader->nElemCount;
    4150             : 
    4151             :         // Updating bounding boxes
    4152         102 :         MMUpdateBoundingBox(&pArcTopHeader->hBB, &pCurrentArcHeader->dfBB);
    4153         102 :         if (hMiraMonLayer->bIsPolygon)
    4154          53 :             MMUpdateBoundingBox(&hMiraMonLayer->TopHeader.hBB,
    4155             :                                 &pCurrentArcHeader->dfBB);
    4156             : 
    4157         102 :         pMMArc->nOffsetArc +=
    4158         102 :             (pCurrentArcHeader->nElemCount) * pMMArc->nALElementSize;
    4159             : 
    4160         102 :         pCurrentArcHeader->nFirstIdNode = (2 * pArcTopHeader->nElemCount);
    4161         102 :         if (hMiraMonLayer->bIsPolygon)
    4162             :         {
    4163          53 :             pCurrentArcHeader->nFirstIdNode = pArcTopHeader->nElemCount;
    4164          53 :             pCurrentArcHeader->nLastIdNode = pArcTopHeader->nElemCount;
    4165             :         }
    4166             :         else
    4167             :         {
    4168          49 :             pCurrentArcHeader->nFirstIdNode = (2 * pArcTopHeader->nElemCount);
    4169          49 :             pCurrentArcHeader->nLastIdNode =
    4170          49 :                 (2 * pArcTopHeader->nElemCount + 1);
    4171             :         }
    4172         102 :         if (MMAddArcRecordToMMDB(hMiraMonLayer, hMMFeature,
    4173             :                                  pArcTopHeader->nElemCount, pCurrentArcHeader))
    4174             :         {
    4175           0 :             CPLDebugOnly("MiraMon", "Error in MMAddArcRecordToMMDB()");
    4176           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    4177             :         }
    4178             : 
    4179             :         // Node Stuff: writing NL section
    4180         102 :         pCurrentNodeHeader->nArcsCount = 1;
    4181         102 :         if (hMiraMonLayer->bIsPolygon)
    4182          53 :             pCurrentNodeHeader->cNodeType = MM_RING_NODE;
    4183             :         else
    4184          49 :             pCurrentNodeHeader->cNodeType = MM_FINAL_NODE;
    4185             : 
    4186         102 :         pCurrentNodeHeader->nOffset =
    4187         102 :             pFlushNL->TotalSavedBytes + pFlushNL->nNumBytes;
    4188         102 :         if (MMAppendIntegerDependingOnVersion(hMiraMonLayer, pFlushNL,
    4189             :                                               &UnsignedLongNumber,
    4190             :                                               pArcTopHeader->nElemCount))
    4191             :         {
    4192           0 :             CPLDebugOnly("MiraMon",
    4193             :                          "Error in MMAppendIntegerDependingOnVersion()");
    4194           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    4195             :         }
    4196             : 
    4197             :         // 8bytes alignment
    4198         102 :         nOffsetTmp = pFlushNL->TotalSavedBytes + pFlushNL->nNumBytes;
    4199         102 :         MMGetOffsetAlignedTo8(&nOffsetTmp);
    4200         102 :         if (nOffsetTmp != pFlushNL->TotalSavedBytes + pFlushNL->nNumBytes)
    4201             :         {
    4202          88 :             pFlushNL->SizeOfBlockToBeSaved =
    4203          88 :                 (size_t)(nOffsetTmp -
    4204          88 :                          (pFlushNL->TotalSavedBytes + pFlushNL->nNumBytes));
    4205          88 :             pFlushNL->pBlockToBeSaved = (void *)nullptr;
    4206          88 :             if (MMAppendBlockToBuffer(pFlushNL))
    4207             :             {
    4208           0 :                 CPLDebugOnly("MiraMon", "Error in MMAppendBlockToBuffer() (3)");
    4209           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4210             :             }
    4211             :         }
    4212         102 :         if (MMAddNodeRecordToMMDB(hMiraMonLayer, pNodeTopHeader->nElemCount,
    4213             :                                   pCurrentNodeHeader))
    4214             :         {
    4215           0 :             CPLDebugOnly("MiraMon", "Error in MMAddNodeRecordToMMDB()");
    4216           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    4217             :         }
    4218             : 
    4219         102 :         if (!hMiraMonLayer->bIsPolygon)
    4220             :         {
    4221          49 :             pCurrentNodeHeaderPlus1->nArcsCount = 1;
    4222          49 :             if (hMiraMonLayer->bIsPolygon)
    4223           0 :                 pCurrentNodeHeaderPlus1->cNodeType = MM_RING_NODE;
    4224             :             else
    4225          49 :                 pCurrentNodeHeaderPlus1->cNodeType = MM_FINAL_NODE;
    4226             : 
    4227          49 :             pCurrentNodeHeaderPlus1->nOffset =
    4228          49 :                 pFlushNL->TotalSavedBytes + pFlushNL->nNumBytes;
    4229             : 
    4230          49 :             if (MMAppendIntegerDependingOnVersion(hMiraMonLayer, pFlushNL,
    4231             :                                                   &UnsignedLongNumber,
    4232             :                                                   pArcTopHeader->nElemCount))
    4233             :             {
    4234           0 :                 CPLDebugOnly("MiraMon",
    4235             :                              "Error in MMAppendIntegerDependingOnVersion()");
    4236           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4237             :             }
    4238             : 
    4239             :             // 8bytes alignment
    4240          49 :             nOffsetTmp = pFlushNL->TotalSavedBytes + pFlushNL->nNumBytes;
    4241          49 :             MMGetOffsetAlignedTo8(&nOffsetTmp);
    4242          49 :             if (nOffsetTmp != pFlushNL->TotalSavedBytes + pFlushNL->nNumBytes)
    4243             :             {
    4244          41 :                 pFlushNL->SizeOfBlockToBeSaved =
    4245          41 :                     (size_t)(nOffsetTmp -
    4246          41 :                              (pFlushNL->TotalSavedBytes + pFlushNL->nNumBytes));
    4247          41 :                 pFlushNL->pBlockToBeSaved = (void *)nullptr;
    4248          41 :                 if (MMAppendBlockToBuffer(pFlushNL))
    4249             :                 {
    4250           0 :                     CPLDebugOnly("MiraMon", "Error in MMAppendBlockToBuffer()");
    4251           0 :                     return MM_FATAL_ERROR_WRITING_FEATURES;
    4252             :                 }
    4253             :             }
    4254          49 :             if (MMAddNodeRecordToMMDB(hMiraMonLayer,
    4255          49 :                                       pNodeTopHeader->nElemCount + 1,
    4256             :                                       pCurrentNodeHeaderPlus1))
    4257             :             {
    4258           0 :                 CPLDebugOnly("MiraMon", "Error in MMAddNodeRecordToMMDB()");
    4259           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4260             :             }
    4261             :         }
    4262             : 
    4263             :         // 3D stuff
    4264         102 :         if (hMiraMonLayer->TopHeader.bIs3d && pZDesc)
    4265             :         {
    4266         102 :             pZDesc[pArcTopHeader->nElemCount].dfBBminz =
    4267             :                 STATISTICAL_UNDEF_VALUE;
    4268         102 :             pZDesc[pArcTopHeader->nElemCount].dfBBmaxz =
    4269             :                 -STATISTICAL_UNDEF_VALUE;
    4270             : 
    4271             :             // Number of arc altitudes. If the number of altitudes is
    4272             :             // positive this indicates the number of altitudes for
    4273             :             // each vertex of the arc, and all the altitudes of the
    4274             :             // vertex 0 are written first, then those of the vertex 1,
    4275             :             // etc. If the number of altitudes is negative this
    4276             :             // indicates the number of arc altitudes, understanding
    4277             :             // that all the vertices have the same altitude (it is
    4278             :             // the case of a contour line, for example).
    4279             : 
    4280         161 :             for (nIVertice = 0; nIVertice < pCurrentArcHeader->nElemCount;
    4281          59 :                  nIVertice++, pZ++)
    4282             :             {
    4283         145 :                 pFlushZL->SizeOfBlockToBeSaved = sizeof(*pZ);
    4284         145 :                 pFlushZL->pBlockToBeSaved = (void *)pZ;
    4285         145 :                 if (MMAppendBlockToBuffer(pFlushZL))
    4286             :                 {
    4287           0 :                     CPLDebugOnly("MiraMon", "Error in MMAppendBlockToBuffer()");
    4288           0 :                     return MM_FATAL_ERROR_WRITING_FEATURES;
    4289             :                 }
    4290             : 
    4291         145 :                 if (pZDesc[pArcTopHeader->nElemCount].dfBBminz > *pZ)
    4292         115 :                     pZDesc[pArcTopHeader->nElemCount].dfBBminz = *pZ;
    4293         145 :                 if (pZDesc[pArcTopHeader->nElemCount].dfBBmaxz < *pZ)
    4294         116 :                     pZDesc[pArcTopHeader->nElemCount].dfBBmaxz = *pZ;
    4295             : 
    4296         145 :                 if (pMMArc->pZSection.ZHeader.dfBBminz > *pZ)
    4297          68 :                     pMMArc->pZSection.ZHeader.dfBBminz = *pZ;
    4298         145 :                 if (pMMArc->pZSection.ZHeader.dfBBmaxz < *pZ)
    4299          67 :                     pMMArc->pZSection.ZHeader.dfBBmaxz = *pZ;
    4300             : 
    4301             :                 // Only one altitude (the same for all vertices) is written
    4302         145 :                 if (hMMFeature->bAllZHaveSameValue)
    4303          86 :                     break;
    4304             :             }
    4305         102 :             if (hMMFeature->bAllZHaveSameValue)
    4306             :             {
    4307             :                 // Same altitude for all vertices
    4308          86 :                 pZDesc[pArcTopHeader->nElemCount].nZCount = -1;
    4309             :             }
    4310             :             else
    4311             :             {
    4312             :                 // One different altitude for each vertice
    4313          16 :                 pZDesc[pArcTopHeader->nElemCount].nZCount = 1;
    4314             :             }
    4315             : 
    4316         102 :             if (pArcTopHeader->nElemCount == 0)
    4317          58 :                 pZDesc[pArcTopHeader->nElemCount].nOffsetZ = 0;
    4318             :             else
    4319             :             {
    4320          44 :                 if (pZDesc[pArcTopHeader->nElemCount - 1].nZCount < 0)
    4321             :                 {
    4322          32 :                     pZDesc[pArcTopHeader->nElemCount].nOffsetZ =
    4323          32 :                         pZDesc[pArcTopHeader->nElemCount - 1].nOffsetZ +
    4324             :                         sizeof(*pZ);
    4325             :                 }
    4326             :                 else
    4327             :                 {
    4328          12 :                     pLastArcHeader =
    4329          12 :                         pMMArc->pArcHeader + pArcTopHeader->nElemCount - 1;
    4330             : 
    4331          12 :                     pZDesc[pArcTopHeader->nElemCount].nOffsetZ =
    4332          12 :                         pZDesc[pArcTopHeader->nElemCount - 1].nOffsetZ +
    4333          12 :                         sizeof(*pZ) * (pLastArcHeader->nElemCount);
    4334             :                 }
    4335             :             }
    4336             :         }
    4337             : 
    4338             :         // Exclusive polygon stuff
    4339         102 :         if (hMiraMonLayer->bIsPolygon && pCurrentPolHeader)
    4340             :         {
    4341             :             // PS SECTION
    4342          53 :             if (MMAppendIntegerDependingOnVersion(hMiraMonLayer, pFlushPS,
    4343             :                                                   &UnsignedLongNumber, 0))
    4344             :             {
    4345           0 :                 CPLDebugOnly("MiraMon",
    4346             :                              "Error in MMAppendIntegerDependingOnVersion()");
    4347           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4348             :             }
    4349             : 
    4350          53 :             if (MMAppendIntegerDependingOnVersion(
    4351             :                     hMiraMonLayer, pFlushPS, &UnsignedLongNumber,
    4352             :                     hMiraMonLayer->TopHeader.nElemCount))
    4353             :             {
    4354           0 :                 CPLDebugOnly("MiraMon",
    4355             :                              "Error in MMAppendIntegerDependingOnVersion()");
    4356           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4357             :             }
    4358             : 
    4359             :             // PAL SECTION
    4360             :             // Vertices of rings defining
    4361             :             // holes in polygons are in a counterclockwise direction.
    4362             :             // Holes are at the end of all external rings that contain the holes!!
    4363          53 :             if (VFG & MM_EXTERIOR_ARC_SIDE)
    4364          45 :                 nExternalRingsCount++;
    4365             : 
    4366          53 :             pCurrentPolHeader->nArcsCount++;
    4367             :             //(MM_POLYGON_ARCS_COUNT)hMMFeature->nNRings;
    4368          53 :             if (VFG & MM_EXTERIOR_ARC_SIDE)
    4369             :                 pCurrentPolHeader
    4370          45 :                     ->nExternalRingsCount++;  //= nExternalRingsCount;
    4371             : 
    4372          53 :             if (VFG & MM_END_ARC_IN_RING)
    4373          53 :                 pCurrentPolHeader->nRingsCount++;  //= hMMFeature->nNRings;
    4374          53 :             if (nIPart == 0)
    4375             :             {
    4376          41 :                 pCurrentPolHeader->nOffset =
    4377          41 :                     pFlushPAL->TotalSavedBytes + pFlushPAL->nNumBytes;
    4378             :             }
    4379             : 
    4380          53 :             if (nIPart == hMMFeature->nNRings - 1)
    4381          41 :                 pCurrentPolHeader->dfArea /= 2;
    4382             : 
    4383          53 :             pFlushPAL->SizeOfBlockToBeSaved = 1;
    4384          53 :             pFlushPAL->pBlockToBeSaved = (void *)&VFG;
    4385          53 :             if (MMAppendBlockToBuffer(pFlushPAL))
    4386             :             {
    4387           0 :                 CPLDebugOnly("MiraMon", "Error in MMAppendBlockToBuffer()");
    4388           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4389             :             }
    4390             : 
    4391          53 :             if (MMAppendIntegerDependingOnVersion(hMiraMonLayer, pFlushPAL,
    4392             :                                                   &UnsignedLongNumber,
    4393             :                                                   pArcTopHeader->nElemCount))
    4394             :             {
    4395           0 :                 CPLDebugOnly("MiraMon",
    4396             :                              "Error in MMAppendIntegerDependingOnVersion()");
    4397           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4398             :             }
    4399             : 
    4400             :             // 8bytes alignment
    4401          53 :             if (nIPart == hMMFeature->nNRings - 1)
    4402             :             {
    4403          41 :                 nOffsetTmp = pFlushPAL->TotalSavedBytes + pFlushPAL->nNumBytes;
    4404          41 :                 MMGetOffsetAlignedTo8(&nOffsetTmp);
    4405             : 
    4406          41 :                 if (nOffsetTmp !=
    4407          41 :                     pFlushPAL->TotalSavedBytes + pFlushPAL->nNumBytes)
    4408             :                 {
    4409          41 :                     pFlushPAL->SizeOfBlockToBeSaved =
    4410          41 :                         (size_t)(nOffsetTmp - (pFlushPAL->TotalSavedBytes +
    4411          41 :                                                pFlushPAL->nNumBytes));
    4412          41 :                     pFlushPAL->pBlockToBeSaved = (void *)nullptr;
    4413          41 :                     if (MMAppendBlockToBuffer(pFlushPAL))
    4414             :                     {
    4415           0 :                         CPLDebugOnly("MiraMon",
    4416             :                                      "Error in MMAppendBlockToBuffer()");
    4417           0 :                         return MM_FATAL_ERROR_WRITING_FEATURES;
    4418             :                     }
    4419             :                 }
    4420             :             }
    4421             : 
    4422          53 :             MMUpdateBoundingBox(&pCurrentPolHeader->dfBB,
    4423             :                                 &pCurrentArcHeader->dfBB);
    4424          53 :             pCurrentPolHeader->dfPerimeter += pCurrentArcHeader->dfLength;
    4425             :         }
    4426             :     }
    4427             : 
    4428             :     // Updating element count and if the polygon is multipart.
    4429             :     // MiraMon does not accept multipoints or multilines, only multipolygons.
    4430          90 :     if (hMiraMonLayer->bIsPolygon)
    4431             :     {
    4432          41 :         if (MMAddPolygonRecordToMMDB(hMiraMonLayer, hMMFeature,
    4433             :                                      hMiraMonLayer->TopHeader.nElemCount,
    4434             :                                      nPolVertices, pCurrentPolHeader))
    4435             :         {
    4436           0 :             CPLDebugOnly("MiraMon", "Error in MMAddPolygonRecordToMMDB()");
    4437           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    4438             :         }
    4439          41 :         hMiraMonLayer->TopHeader.nElemCount++;
    4440             : 
    4441          41 :         if (nExternalRingsCount > 1)
    4442           4 :             hMiraMonLayer->TopHeader.bIsMultipolygon = TRUE;
    4443             :     }
    4444             : 
    4445          90 :     return MM_CONTINUE_WRITING_FEATURES;
    4446             : }  // End of de MMCreateFeaturePolOrArc()
    4447             : 
    4448             : // Creates a MiraMon DBF record when not associated with a geometric feature.
    4449          34 : static int MMCreateRecordDBF(struct MiraMonVectLayerInfo *hMiraMonLayer,
    4450             :                              struct MiraMonFeature *hMMFeature)
    4451             : {
    4452             :     int result;
    4453             : 
    4454          34 :     if (!hMiraMonLayer)
    4455           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    4456             : 
    4457          34 :     if (hMiraMonLayer->TopHeader.nElemCount == 0)
    4458             :     {
    4459          17 :         if (MMCreateMMDB(hMiraMonLayer, nullptr))
    4460             :         {
    4461           0 :             MMDestroyMMDB(hMiraMonLayer);
    4462           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    4463             :         }
    4464             :     }
    4465             : 
    4466          34 :     result = MMAddDBFRecordToMMDB(hMiraMonLayer, hMMFeature);
    4467          34 :     if (result == MM_FATAL_ERROR_WRITING_FEATURES ||
    4468             :         result == MM_STOP_WRITING_FEATURES)
    4469           0 :         return result;
    4470             : 
    4471             :     // Everything OK.
    4472          34 :     return MM_CONTINUE_WRITING_FEATURES;
    4473             : }  // End of de MMCreateRecordDBF()
    4474             : 
    4475             : // Creates a MiraMon point feature.
    4476          89 : static int MMCreateFeaturePoint(struct MiraMonVectLayerInfo *hMiraMonLayer,
    4477             :                                 struct MiraMonFeature *hMMFeature)
    4478             : {
    4479          89 :     double *pZ = nullptr;
    4480             :     struct MM_POINT_2D *pCoord;
    4481             :     MM_POLYGON_RINGS_COUNT nIPart;
    4482             :     MM_N_VERTICES_TYPE nIVertice, nCoord;
    4483          89 :     struct MM_ZD *pZDescription = nullptr;
    4484             :     MM_INTERNAL_FID nElemCount;
    4485             :     int result;
    4486             : 
    4487          89 :     if (!hMiraMonLayer)
    4488           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    4489             : 
    4490          89 :     if (!hMMFeature)
    4491           0 :         return MM_STOP_WRITING_FEATURES;
    4492             : 
    4493          89 :     if (hMiraMonLayer->TopHeader.bIs3d)
    4494          89 :         pZ = hMMFeature->pZCoord;
    4495             : 
    4496          89 :     nElemCount = hMiraMonLayer->TopHeader.nElemCount;
    4497         178 :     for (nIPart = 0, pCoord = hMMFeature->pCoord; nIPart < hMMFeature->nNRings;
    4498          89 :          nIPart++, nElemCount++)
    4499             :     {
    4500          89 :         nCoord = hMMFeature->pNCoordRing[nIPart];
    4501             : 
    4502             :         // Checking if its possible continue writing the file due
    4503             :         // to version limitations.
    4504          89 :         if (MMCheckVersionForFID(hMiraMonLayer,
    4505          89 :                                  hMiraMonLayer->TopHeader.nElemCount + nCoord))
    4506             :         {
    4507           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    4508             :                      "Error in MMCheckVersionForFID() (5)");
    4509           0 :             return MM_STOP_WRITING_FEATURES;
    4510             :         }
    4511             : 
    4512          89 :         if (hMiraMonLayer->TopHeader.bIs3d)
    4513             :         {
    4514          89 :             if (nElemCount == 0)
    4515             :             {
    4516          34 :                 if (MMCheckVersionFor3DOffset(hMiraMonLayer, (nElemCount + 1),
    4517             :                                               0, 0))
    4518           0 :                     return MM_STOP_WRITING_FEATURES;
    4519             :             }
    4520             :             else
    4521             :             {
    4522          55 :                 pZDescription = hMiraMonLayer->MMPoint.pZSection.pZDescription;
    4523          55 :                 if (!pZDescription)
    4524             :                 {
    4525           0 :                     CPLError(CE_Failure, CPLE_ObjectNull,
    4526             :                              "Error: pZDescription should not be nullptr");
    4527           0 :                     return MM_STOP_WRITING_FEATURES;
    4528             :                 }
    4529             : 
    4530          55 :                 if (MMCheckVersionFor3DOffset(
    4531             :                         hMiraMonLayer, nElemCount + 1, 0,
    4532          55 :                         pZDescription[nElemCount - 1].nOffsetZ + sizeof(*pZ)))
    4533           0 :                     return MM_STOP_WRITING_FEATURES;
    4534             :             }
    4535             :         }
    4536             : 
    4537             :         // Doing real job
    4538             :         // Memory issues
    4539          89 :         if (hMiraMonLayer->TopHeader.bIs3d && pZ)
    4540             :         {
    4541          89 :             if (MMResizeZSectionDescrPointer(
    4542             :                     &hMiraMonLayer->MMPoint.pZSection.pZDescription,
    4543             :                     &hMiraMonLayer->MMPoint.pZSection.nMaxZDescription,
    4544             :                     nElemCount, MM_INCR_NUMBER_OF_POINTS, 0))
    4545             :             {
    4546           0 :                 CPLError(CE_Failure, CPLE_OutOfMemory,
    4547             :                          "Memory error in MiraMon "
    4548             :                          "driver (MMCreateFeaturePoint())");
    4549           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4550             :             }
    4551             : 
    4552          89 :             pZDescription = hMiraMonLayer->MMPoint.pZSection.pZDescription;
    4553          89 :             if (!pZDescription)
    4554             :             {
    4555           0 :                 CPLError(CE_Failure, CPLE_ObjectNull,
    4556             :                          "Error: pZDescription should not be nullptr");
    4557           0 :                 return MM_STOP_WRITING_FEATURES;
    4558             :             }
    4559             : 
    4560          89 :             pZDescription[nElemCount].dfBBminz = *pZ;
    4561          89 :             pZDescription[nElemCount].dfBBmaxz = *pZ;
    4562             : 
    4563          89 :             if (hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBminz > *pZ)
    4564          41 :                 hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBminz = *pZ;
    4565          89 :             if (hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBmaxz < *pZ)
    4566          38 :                 hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBmaxz = *pZ;
    4567             : 
    4568             :             // Specification ask for a negative number.
    4569          89 :             pZDescription[nElemCount].nZCount = -1;
    4570          89 :             if (nElemCount == 0)
    4571          34 :                 pZDescription[nElemCount].nOffsetZ = 0;
    4572             :             else
    4573          55 :                 pZDescription[nElemCount].nOffsetZ =
    4574          55 :                     pZDescription[nElemCount - 1].nOffsetZ + sizeof(*pZ);
    4575             :         }
    4576             : 
    4577             :         // Flush settings
    4578          89 :         hMiraMonLayer->MMPoint.FlushTL.pBlockWhereToSaveOrRead =
    4579          89 :             (void *)hMiraMonLayer->MMPoint.pTL;
    4580          89 :         if (hMiraMonLayer->TopHeader.bIs3d)
    4581          89 :             hMiraMonLayer->MMPoint.pZSection.FlushZL.pBlockWhereToSaveOrRead =
    4582          89 :                 (void *)hMiraMonLayer->MMPoint.pZSection.pZL;
    4583             : 
    4584             :         // Dump point or points (MiraMon does not have multiple points)
    4585         178 :         for (nIVertice = 0; nIVertice < nCoord; nIVertice++, pCoord++)
    4586             :         {
    4587             :             // Updating the bounding box of the layer
    4588          89 :             MMUpdateBoundingBoxXY(&hMiraMonLayer->TopHeader.hBB, pCoord);
    4589             : 
    4590             :             // Adding the point at the memory block
    4591          89 :             hMiraMonLayer->MMPoint.FlushTL.SizeOfBlockToBeSaved =
    4592             :                 sizeof(pCoord->dfX);
    4593          89 :             hMiraMonLayer->MMPoint.FlushTL.pBlockToBeSaved =
    4594          89 :                 (void *)&pCoord->dfX;
    4595          89 :             if (MMAppendBlockToBuffer(&hMiraMonLayer->MMPoint.FlushTL))
    4596           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4597          89 :             hMiraMonLayer->MMPoint.FlushTL.pBlockToBeSaved =
    4598          89 :                 (void *)&pCoord->dfY;
    4599          89 :             if (MMAppendBlockToBuffer(&hMiraMonLayer->MMPoint.FlushTL))
    4600           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4601             : 
    4602             :             // Adding the 3D part, if exists, at the memory block
    4603          89 :             if (hMiraMonLayer->TopHeader.bIs3d && pZ)
    4604             :             {
    4605          89 :                 hMiraMonLayer->MMPoint.pZSection.FlushZL.SizeOfBlockToBeSaved =
    4606             :                     sizeof(*pZ);
    4607          89 :                 hMiraMonLayer->MMPoint.pZSection.FlushZL.pBlockToBeSaved =
    4608             :                     (void *)pZ;
    4609          89 :                 if (MMAppendBlockToBuffer(
    4610             :                         &hMiraMonLayer->MMPoint.pZSection.FlushZL))
    4611           0 :                     return MM_FATAL_ERROR_WRITING_FEATURES;
    4612             : 
    4613          89 :                 if (!pZDescription)
    4614             :                 {
    4615           0 :                     CPLError(CE_Failure, CPLE_ObjectNull,
    4616             :                              "Error: pZDescription should not be nullptr");
    4617           0 :                     return MM_STOP_WRITING_FEATURES;
    4618             :                 }
    4619             : 
    4620          89 :                 if (pZDescription[nElemCount].dfBBminz > *pZ)
    4621           0 :                     pZDescription[nElemCount].dfBBminz = *pZ;
    4622          89 :                 if (pZDescription[nElemCount].dfBBmaxz < *pZ)
    4623           0 :                     pZDescription[nElemCount].dfBBmaxz = *pZ;
    4624             : 
    4625          89 :                 if (hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBminz > *pZ)
    4626           0 :                     hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBminz = *pZ;
    4627          89 :                 if (hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBmaxz < *pZ)
    4628           0 :                     hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBmaxz = *pZ;
    4629             : 
    4630          89 :                 pZ++;
    4631             :             }
    4632             :         }
    4633             : 
    4634          89 :         if (hMiraMonLayer->TopHeader.nElemCount == 0)
    4635             :         {
    4636          34 :             if (MMCreateMMDB(hMiraMonLayer, hMMFeature->pCoord))
    4637           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4638             :         }
    4639             : 
    4640          89 :         result = MMAddPointRecordToMMDB(hMiraMonLayer, hMMFeature, nElemCount);
    4641          89 :         if (result == MM_FATAL_ERROR_WRITING_FEATURES ||
    4642             :             result == MM_STOP_WRITING_FEATURES)
    4643           0 :             return result;
    4644             :     }
    4645             :     // Updating nElemCount at the header of the layer
    4646          89 :     hMiraMonLayer->TopHeader.nElemCount = nElemCount;
    4647             : 
    4648             :     // Everything OK.
    4649          89 :     return MM_CONTINUE_WRITING_FEATURES;
    4650             : }  // End of de MMCreateFeaturePoint()
    4651             : 
    4652             : // Checks whether a given Feature ID (FID) exceeds the maximum allowed
    4653             : // index for 2 GB vectors in a specific MiraMon layer.
    4654         804 : int MMCheckVersionForFID(struct MiraMonVectLayerInfo *hMiraMonLayer,
    4655             :                          MM_INTERNAL_FID FID)
    4656             : {
    4657         804 :     if (!hMiraMonLayer)
    4658           0 :         return 1;
    4659             : 
    4660         804 :     if (hMiraMonLayer->LayerVersion != MM_32BITS_VERSION)
    4661          56 :         return 0;
    4662             : 
    4663         748 :     if (FID >= MAXIMUM_OBJECT_INDEX_IN_2GB_VECTORS)
    4664           0 :         return 1;
    4665         748 :     return 0;
    4666             : }
    4667             : 
    4668             : // Checks whether a given offset exceeds the maximum allowed
    4669             : // index for 2 GB vectors in a specific MiraMon layer.
    4670         217 : int MMCheckVersionOffset(struct MiraMonVectLayerInfo *hMiraMonLayer,
    4671             :                          MM_FILE_OFFSET OffsetToCheck)
    4672             : {
    4673         217 :     if (!hMiraMonLayer)
    4674           0 :         return 1;
    4675             : 
    4676             :     // Checking if the final version is 1.1 or 2.0
    4677         217 :     if (hMiraMonLayer->LayerVersion != MM_32BITS_VERSION)
    4678           0 :         return 0;
    4679             : 
    4680             :     // User decided that if necessary, output version can be 2.0
    4681         217 :     if (OffsetToCheck < MAXIMUM_OFFSET_IN_2GB_VECTORS)
    4682         217 :         return 0;
    4683             : 
    4684           0 :     return 1;
    4685             : }
    4686             : 
    4687             : // Checks whether a given offset in 3D section exceeds the maximum allowed
    4688             : // index for 2 GB vectors in a specific MiraMon layer.
    4689         177 : int MMCheckVersionFor3DOffset(struct MiraMonVectLayerInfo *hMiraMonLayer,
    4690             :                               MM_INTERNAL_FID nElemCount,
    4691             :                               MM_FILE_OFFSET nOffsetAL,
    4692             :                               MM_FILE_OFFSET nZLOffset)
    4693             : {
    4694             :     MM_FILE_OFFSET LastOffset;
    4695             : 
    4696         177 :     if (!hMiraMonLayer)
    4697           0 :         return 1;
    4698             : 
    4699             :     // Checking if the final version is 1.1 or 2.0
    4700         177 :     if (hMiraMonLayer->LayerVersion != MM_32BITS_VERSION)
    4701           6 :         return 0;
    4702             : 
    4703             :     // User decided that if necessary, output version can be 2.0
    4704         171 :     if (hMiraMonLayer->bIsPoint)
    4705          83 :         LastOffset = MM_HEADER_SIZE_32_BITS + nElemCount * MM_SIZE_OF_TL;
    4706             :     else  // Arc case
    4707             :     {
    4708          88 :         LastOffset = MM_HEADER_SIZE_32_BITS +
    4709          88 :                      nElemCount * MM_SIZE_OF_AH_32BITS + +nOffsetAL;
    4710             :     }
    4711             : 
    4712         171 :     LastOffset += MM_SIZE_OF_ZH;
    4713         171 :     LastOffset += nElemCount * MM_SIZE_OF_ZD_32_BITS;
    4714         171 :     LastOffset += nZLOffset;
    4715             : 
    4716         171 :     if (LastOffset < MAXIMUM_OFFSET_IN_2GB_VECTORS)
    4717         171 :         return 0;
    4718             : 
    4719           0 :     return 1;
    4720             : }
    4721             : 
    4722             : // Adds a feature in a MiraMon layer.
    4723         213 : int MMAddFeature(struct MiraMonVectLayerInfo *hMiraMonLayer,
    4724             :                  struct MiraMonFeature *hMiraMonFeature)
    4725             : {
    4726             :     int re;
    4727         213 :     MM_INTERNAL_FID previousFID = 0;
    4728             : 
    4729         213 :     if (!hMiraMonLayer)
    4730           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    4731             : 
    4732         213 :     if (!hMiraMonLayer->bIsBeenInit)
    4733             :     {
    4734           0 :         if (MMInitLayerByType(hMiraMonLayer))
    4735             :         {
    4736           0 :             CPLDebugOnly("MiraMon", "Error in MMInitLayerByType()");
    4737           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    4738             :         }
    4739           0 :         hMiraMonLayer->bIsBeenInit = 1;
    4740             :     }
    4741             : 
    4742         213 :     if (hMiraMonFeature)
    4743         213 :         previousFID = hMiraMonLayer->TopHeader.nElemCount;
    4744             : 
    4745         213 :     if (hMiraMonLayer->bIsPoint)
    4746             :     {
    4747          89 :         re = MMCreateFeaturePoint(hMiraMonLayer, hMiraMonFeature);
    4748          89 :         if (hMiraMonFeature)
    4749             :         {
    4750          89 :             hMiraMonFeature->nReadFeatures =
    4751          89 :                 hMiraMonLayer->TopHeader.nElemCount - previousFID;
    4752             :         }
    4753          89 :         return re;
    4754             :     }
    4755         124 :     if (hMiraMonLayer->bIsArc || hMiraMonLayer->bIsPolygon)
    4756             :     {
    4757          90 :         re = MMCreateFeaturePolOrArc(hMiraMonLayer, hMiraMonFeature);
    4758          90 :         if (hMiraMonFeature)
    4759             :         {
    4760          90 :             hMiraMonFeature->nReadFeatures =
    4761          90 :                 hMiraMonLayer->TopHeader.nElemCount - previousFID;
    4762             :         }
    4763          90 :         return re;
    4764             :     }
    4765          34 :     if (hMiraMonLayer->bIsDBF)
    4766             :     {
    4767             :         // Adding a record to DBF file
    4768          34 :         re = MMCreateRecordDBF(hMiraMonLayer, hMiraMonFeature);
    4769          34 :         if (hMiraMonFeature)
    4770             :         {
    4771          34 :             hMiraMonFeature->nReadFeatures =
    4772          34 :                 hMiraMonLayer->TopHeader.nElemCount - previousFID;
    4773             :         }
    4774          34 :         return re;
    4775             :     }
    4776             : 
    4777           0 :     return MM_CONTINUE_WRITING_FEATURES;
    4778             : }
    4779             : 
    4780             : /* -------------------------------------------------------------------- */
    4781             : /*      Tools used by MiraMon.                                          */
    4782             : /* -------------------------------------------------------------------- */
    4783             : 
    4784         320 : void MMInitBoundingBox(struct MMBoundingBox *dfBB)
    4785             : {
    4786         320 :     if (!dfBB)
    4787           0 :         return;
    4788         320 :     dfBB->dfMinX = STATISTICAL_UNDEF_VALUE;
    4789         320 :     dfBB->dfMaxX = -STATISTICAL_UNDEF_VALUE;
    4790         320 :     dfBB->dfMinY = STATISTICAL_UNDEF_VALUE;
    4791         320 :     dfBB->dfMaxY = -STATISTICAL_UNDEF_VALUE;
    4792             : }
    4793             : 
    4794         208 : void MMUpdateBoundingBox(struct MMBoundingBox *dfBBToBeAct,
    4795             :                          struct MMBoundingBox *dfBBWithData)
    4796             : {
    4797         208 :     if (!dfBBToBeAct)
    4798           0 :         return;
    4799             : 
    4800         208 :     if (dfBBToBeAct->dfMinX > dfBBWithData->dfMinX)
    4801         133 :         dfBBToBeAct->dfMinX = dfBBWithData->dfMinX;
    4802             : 
    4803         208 :     if (dfBBToBeAct->dfMinY > dfBBWithData->dfMinY)
    4804         148 :         dfBBToBeAct->dfMinY = dfBBWithData->dfMinY;
    4805             : 
    4806         208 :     if (dfBBToBeAct->dfMaxX < dfBBWithData->dfMaxX)
    4807         147 :         dfBBToBeAct->dfMaxX = dfBBWithData->dfMaxX;
    4808             : 
    4809         208 :     if (dfBBToBeAct->dfMaxY < dfBBWithData->dfMaxY)
    4810         145 :         dfBBToBeAct->dfMaxY = dfBBWithData->dfMaxY;
    4811             : }
    4812             : 
    4813         763 : void MMUpdateBoundingBoxXY(struct MMBoundingBox *dfBB,
    4814             :                            struct MM_POINT_2D *pCoord)
    4815             : {
    4816         763 :     if (!pCoord)
    4817           0 :         return;
    4818             : 
    4819         763 :     if (pCoord->dfX < dfBB->dfMinX)
    4820         269 :         dfBB->dfMinX = pCoord->dfX;
    4821             : 
    4822         763 :     if (pCoord->dfY < dfBB->dfMinY)
    4823         294 :         dfBB->dfMinY = pCoord->dfY;
    4824             : 
    4825         763 :     if (pCoord->dfX > dfBB->dfMaxX)
    4826         398 :         dfBB->dfMaxX = pCoord->dfX;
    4827             : 
    4828         763 :     if (pCoord->dfY > dfBB->dfMaxY)
    4829         358 :         dfBB->dfMaxY = pCoord->dfY;
    4830             : }
    4831             : 
    4832             : /* -------------------------------------------------------------------- */
    4833             : /*      Resize structures for reuse                                     */
    4834             : /* -------------------------------------------------------------------- */
    4835        1398 : int MMResizeMiraMonFieldValue(struct MiraMonFieldValue **pFieldValue,
    4836             :                               MM_EXT_DBF_N_MULTIPLE_RECORDS *nMax,
    4837             :                               MM_EXT_DBF_N_MULTIPLE_RECORDS nNum,
    4838             :                               MM_EXT_DBF_N_MULTIPLE_RECORDS nIncr,
    4839             :                               MM_EXT_DBF_N_MULTIPLE_RECORDS nProposedMax)
    4840             : {
    4841             :     MM_EXT_DBF_N_MULTIPLE_RECORDS nPrevMax;
    4842             :     MM_EXT_DBF_N_MULTIPLE_RECORDS nNewMax;
    4843             :     void *pTmp;
    4844             : 
    4845        1398 :     if (nNum < *nMax)
    4846        1379 :         return 0;
    4847             : 
    4848          19 :     nPrevMax = *nMax;
    4849          19 :     nNewMax = CPL_MAX(nNum + nIncr, nProposedMax);
    4850          19 :     if (MMCheckSize_t(nNewMax, sizeof(**pFieldValue)))
    4851             :     {
    4852           0 :         return 1;
    4853             :     }
    4854          19 :     if ((pTmp = VSIRealloc(*pFieldValue,
    4855          19 :                            (size_t)nNewMax * sizeof(**pFieldValue))) == nullptr)
    4856             :     {
    4857           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    4858             :                  "Memory error in MiraMon "
    4859             :                  "driver (MMResizeMiraMonFieldValue())");
    4860           0 :         return 1;
    4861             :     }
    4862          19 :     *nMax = nNewMax;
    4863          19 :     *pFieldValue = pTmp;
    4864             : 
    4865          19 :     memset((*pFieldValue) + nPrevMax, 0,
    4866          19 :            (size_t)(*nMax - nPrevMax) * sizeof(**pFieldValue));
    4867          19 :     return 0;
    4868             : }
    4869             : 
    4870         352 : int MMResizeMiraMonPolygonArcs(struct MM_PAL_MEM **pFID,
    4871             :                                MM_POLYGON_ARCS_COUNT *nMax,
    4872             :                                MM_POLYGON_ARCS_COUNT nNum,
    4873             :                                MM_POLYGON_ARCS_COUNT nIncr,
    4874             :                                MM_POLYGON_ARCS_COUNT nProposedMax)
    4875             : {
    4876             :     MM_POLYGON_ARCS_COUNT nPrevMax;
    4877             :     MM_POLYGON_ARCS_COUNT nNewMax;
    4878             :     void *pTmp;
    4879             : 
    4880         352 :     if (nNum < *nMax)
    4881          32 :         return 0;
    4882             : 
    4883         320 :     nPrevMax = *nMax;
    4884         320 :     nNewMax = CPL_MAX(nNum + nIncr, nProposedMax);
    4885         320 :     if (MMCheckSize_t(nNewMax, sizeof(**pFID)))
    4886             :     {
    4887           0 :         return 1;
    4888             :     }
    4889         320 :     if (nNewMax == 0 && *pFID)
    4890           0 :         return 0;
    4891         320 :     if ((pTmp = VSIRealloc(*pFID, (size_t)nNewMax * sizeof(**pFID))) == nullptr)
    4892             :     {
    4893           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    4894             :                  "Memory error in MiraMon "
    4895             :                  "driver (MMResizeMiraMonPolygonArcs())");
    4896           0 :         return 1;
    4897             :     }
    4898         320 :     *nMax = nNewMax;
    4899         320 :     *pFID = pTmp;
    4900             : 
    4901         320 :     memset((*pFID) + nPrevMax, 0, (size_t)(*nMax - nPrevMax) * sizeof(**pFID));
    4902         320 :     return 0;
    4903             : }
    4904             : 
    4905          88 : int MMResizeMiraMonRecord(struct MiraMonRecord **pMiraMonRecord,
    4906             :                           MM_EXT_DBF_N_MULTIPLE_RECORDS *nMax,
    4907             :                           MM_EXT_DBF_N_MULTIPLE_RECORDS nNum,
    4908             :                           MM_EXT_DBF_N_MULTIPLE_RECORDS nIncr,
    4909             :                           MM_EXT_DBF_N_MULTIPLE_RECORDS nProposedMax)
    4910             : {
    4911             :     MM_EXT_DBF_N_MULTIPLE_RECORDS nPrevMax;
    4912             :     MM_EXT_DBF_N_MULTIPLE_RECORDS nNewMax;
    4913             :     void *pTmp;
    4914             : 
    4915          88 :     if (nNum < *nMax)
    4916          72 :         return 0;
    4917             : 
    4918          16 :     nPrevMax = *nMax;
    4919          16 :     nNewMax = CPL_MAX(nNum + nIncr, nProposedMax);
    4920          16 :     if (MMCheckSize_t(nNewMax, sizeof(**pMiraMonRecord)))
    4921             :     {
    4922           0 :         return 1;
    4923             :     }
    4924          16 :     if (nNewMax == 0 && *pMiraMonRecord)
    4925           0 :         return 0;
    4926          16 :     if ((pTmp = VSIRealloc(*pMiraMonRecord,
    4927          16 :                            (size_t)nNewMax * sizeof(**pMiraMonRecord))) ==
    4928             :         nullptr)
    4929             :     {
    4930           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    4931             :                  "Memory error in MiraMon "
    4932             :                  "driver (MMResizeMiraMonRecord())");
    4933           0 :         return 1;
    4934             :     }
    4935          16 :     *nMax = nNewMax;
    4936          16 :     *pMiraMonRecord = pTmp;
    4937             : 
    4938          16 :     memset((*pMiraMonRecord) + nPrevMax, 0,
    4939          16 :            (size_t)(*nMax - nPrevMax) * sizeof(**pMiraMonRecord));
    4940          16 :     return 0;
    4941             : }
    4942             : 
    4943         191 : int MMResizeZSectionDescrPointer(struct MM_ZD **pZDescription, GUInt64 *nMax,
    4944             :                                  GUInt64 nNum, GUInt64 nIncr,
    4945             :                                  GUInt64 nProposedMax)
    4946             : {
    4947             :     GUInt64 nNewMax, nPrevMax;
    4948             :     void *pTmp;
    4949             : 
    4950         191 :     if (nNum < *nMax)
    4951         133 :         return 0;
    4952             : 
    4953          58 :     nPrevMax = *nMax;
    4954          58 :     nNewMax = CPL_MAX(nNum + nIncr, nProposedMax);
    4955          58 :     if (MMCheckSize_t(nNewMax, sizeof(**pZDescription)))
    4956             :     {
    4957           0 :         return 1;
    4958             :     }
    4959          58 :     if (nNewMax == 0 && *pZDescription)
    4960           0 :         return 0;
    4961          58 :     if ((pTmp = VSIRealloc(*pZDescription,
    4962             :                            (size_t)nNewMax * sizeof(**pZDescription))) ==
    4963             :         nullptr)
    4964             :     {
    4965           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    4966             :                  "Memory error in MiraMon "
    4967             :                  "driver (MMResizeZSectionDescrPointer())");
    4968           0 :         return 1;
    4969             :     }
    4970          58 :     *nMax = nNewMax;
    4971          58 :     *pZDescription = pTmp;
    4972             : 
    4973          58 :     memset((*pZDescription) + nPrevMax, 0,
    4974          58 :            (size_t)(*nMax - nPrevMax) * sizeof(**pZDescription));
    4975          58 :     return 0;
    4976             : }
    4977             : 
    4978         102 : int MMResizeNodeHeaderPointer(struct MM_NH **pNodeHeader, GUInt64 *nMax,
    4979             :                               GUInt64 nNum, GUInt64 nIncr, GUInt64 nProposedMax)
    4980             : {
    4981             :     GUInt64 nNewMax, nPrevMax;
    4982             :     void *pTmp;
    4983             : 
    4984         102 :     if (nNum < *nMax)
    4985         102 :         return 0;
    4986             : 
    4987           0 :     nPrevMax = *nMax;
    4988           0 :     nNewMax = CPL_MAX(nNum + nIncr, nProposedMax);
    4989           0 :     if (MMCheckSize_t(nNewMax, sizeof(**pNodeHeader)))
    4990             :     {
    4991           0 :         return 1;
    4992             :     }
    4993           0 :     if (nNewMax == 0 && *pNodeHeader)
    4994           0 :         return 0;
    4995           0 :     if ((pTmp = VSIRealloc(*pNodeHeader,
    4996             :                            (size_t)nNewMax * sizeof(**pNodeHeader))) == nullptr)
    4997             :     {
    4998           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    4999             :                  "Memory error in MiraMon "
    5000             :                  "driver (MMResizeNodeHeaderPointer())");
    5001           0 :         return 1;
    5002             :     }
    5003           0 :     *nMax = nNewMax;
    5004           0 :     *pNodeHeader = pTmp;
    5005             : 
    5006           0 :     memset((*pNodeHeader) + nPrevMax, 0,
    5007           0 :            (size_t)(*nMax - nPrevMax) * sizeof(**pNodeHeader));
    5008           0 :     return 0;
    5009             : }
    5010             : 
    5011         102 : int MMResizeArcHeaderPointer(struct MM_AH **pArcHeader, GUInt64 *nMax,
    5012             :                              GUInt64 nNum, GUInt64 nIncr, GUInt64 nProposedMax)
    5013             : {
    5014             :     GUInt64 nNewMax, nPrevMax;
    5015             :     void *pTmp;
    5016             : 
    5017         102 :     if (nNum < *nMax)
    5018         102 :         return 0;
    5019             : 
    5020           0 :     nPrevMax = *nMax;
    5021           0 :     nNewMax = CPL_MAX(nNum + nIncr, nProposedMax);
    5022           0 :     if (MMCheckSize_t(nNewMax, sizeof(**pArcHeader)))
    5023             :     {
    5024           0 :         return 1;
    5025             :     }
    5026           0 :     if (nNewMax == 0 && *pArcHeader)
    5027           0 :         return 0;
    5028           0 :     if ((pTmp = VSIRealloc(*pArcHeader,
    5029             :                            (size_t)nNewMax * sizeof(**pArcHeader))) == nullptr)
    5030             :     {
    5031           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    5032             :                  "Memory error in MiraMon "
    5033             :                  "driver (MMResizeArcHeaderPointer())");
    5034           0 :         return 1;
    5035             :     }
    5036           0 :     *nMax = nNewMax;
    5037           0 :     *pArcHeader = pTmp;
    5038             : 
    5039           0 :     memset((*pArcHeader) + nPrevMax, 0,
    5040           0 :            (size_t)(*nMax - nPrevMax) * sizeof(**pArcHeader));
    5041           0 :     return 0;
    5042             : }
    5043             : 
    5044          41 : int MMResizePolHeaderPointer(struct MM_PH **pPolHeader, GUInt64 *nMax,
    5045             :                              GUInt64 nNum, GUInt64 nIncr, GUInt64 nProposedMax)
    5046             : {
    5047             :     GUInt64 nNewMax, nPrevMax;
    5048             :     void *pTmp;
    5049             : 
    5050          41 :     if (nNum < *nMax)
    5051          41 :         return 0;
    5052             : 
    5053           0 :     nPrevMax = *nMax;
    5054           0 :     nNewMax = CPL_MAX(nNum + nIncr, nProposedMax);
    5055           0 :     if (MMCheckSize_t(nNewMax, sizeof(**pPolHeader)))
    5056             :     {
    5057           0 :         return 1;
    5058             :     }
    5059           0 :     if (nNewMax == 0 && *pPolHeader)
    5060           0 :         return 0;
    5061           0 :     if ((pTmp = VSIRealloc(*pPolHeader,
    5062             :                            (size_t)nNewMax * sizeof(**pPolHeader))) == nullptr)
    5063             :     {
    5064           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    5065             :                  "Memory error in MiraMon "
    5066             :                  "driver (MMResizePolHeaderPointer())");
    5067           0 :         return 1;
    5068             :     }
    5069           0 :     *nMax = nNewMax;
    5070           0 :     *pPolHeader = pTmp;
    5071             : 
    5072           0 :     memset((*pPolHeader) + nPrevMax, 0,
    5073           0 :            (size_t)(*nMax - nPrevMax) * sizeof(**pPolHeader));
    5074           0 :     return 0;
    5075             : }
    5076             : 
    5077        2747 : int MMResize_MM_N_VERTICES_TYPE_Pointer(MM_N_VERTICES_TYPE **pVrt,
    5078             :                                         MM_N_VERTICES_TYPE *nMax,
    5079             :                                         MM_N_VERTICES_TYPE nNum,
    5080             :                                         MM_N_VERTICES_TYPE nIncr,
    5081             :                                         MM_N_VERTICES_TYPE nProposedMax)
    5082             : {
    5083             :     MM_N_VERTICES_TYPE nNewMax, nPrevMax;
    5084             :     void *pTmp;
    5085             : 
    5086        2747 :     if (nNum < *nMax)
    5087        1234 :         return 0;
    5088             : 
    5089        1513 :     nPrevMax = *nMax;
    5090        1513 :     nNewMax = CPL_MAX(nNum + nIncr, nProposedMax);
    5091        1513 :     if (MMCheckSize_t(nNewMax, sizeof(**pVrt)))
    5092             :     {
    5093           0 :         return 1;
    5094             :     }
    5095        1513 :     if (nNewMax == 0 && *pVrt)
    5096           0 :         return 0;
    5097        1513 :     if ((pTmp = VSIRealloc(*pVrt, (size_t)nNewMax * sizeof(**pVrt))) == nullptr)
    5098             :     {
    5099           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    5100             :                  "Memory error in MiraMon "
    5101             :                  "driver (MMResize_MM_N_VERTICES_TYPE_Pointer())");
    5102           0 :         return 1;
    5103             :     }
    5104        1513 :     *nMax = nNewMax;
    5105        1513 :     *pVrt = pTmp;
    5106             : 
    5107        1513 :     memset((*pVrt) + nPrevMax, 0, (size_t)(*nMax - nPrevMax) * sizeof(**pVrt));
    5108        1513 :     return 0;
    5109             : }
    5110             : 
    5111         399 : int MMResizeVFGPointer(char **pInt, MM_INTERNAL_FID *nMax, MM_INTERNAL_FID nNum,
    5112             :                        MM_INTERNAL_FID nIncr, MM_INTERNAL_FID nProposedMax)
    5113             : {
    5114             :     MM_N_VERTICES_TYPE nNewMax, nPrevMax;
    5115             :     void *pTmp;
    5116             : 
    5117         399 :     if (nNum < *nMax)
    5118          58 :         return 0;
    5119             : 
    5120         341 :     nPrevMax = *nMax;
    5121         341 :     nNewMax = CPL_MAX(nNum + nIncr, nProposedMax);
    5122         341 :     if (MMCheckSize_t(nNewMax, sizeof(**pInt)))
    5123             :     {
    5124           0 :         return 1;
    5125             :     }
    5126         341 :     if (nNewMax == 0 && *pInt)
    5127           0 :         return 0;
    5128         341 :     if ((pTmp = VSIRealloc(*pInt, (size_t)nNewMax * sizeof(**pInt))) == nullptr)
    5129             :     {
    5130           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    5131             :                  "Memory error in MiraMon "
    5132             :                  "driver (MMResizeVFGPointer())");
    5133           0 :         return 1;
    5134             :     }
    5135         341 :     *nMax = nNewMax;
    5136         341 :     *pInt = pTmp;
    5137             : 
    5138         341 :     memset((*pInt) + nPrevMax, 0, (size_t)(*nMax - nPrevMax) * sizeof(**pInt));
    5139         341 :     return 0;
    5140             : }
    5141             : 
    5142        2760 : int MMResizeMM_POINT2DPointer(struct MM_POINT_2D **pPoint2D,
    5143             :                               MM_N_VERTICES_TYPE *nMax, MM_N_VERTICES_TYPE nNum,
    5144             :                               MM_N_VERTICES_TYPE nIncr,
    5145             :                               MM_N_VERTICES_TYPE nProposedMax)
    5146             : {
    5147             :     MM_N_VERTICES_TYPE nNewMax, nPrevMax;
    5148             :     void *pTmp;
    5149             : 
    5150        2760 :     if (nNum < *nMax)
    5151        2367 :         return 0;
    5152             : 
    5153         393 :     nPrevMax = *nMax;
    5154         393 :     nNewMax = CPL_MAX(nNum + nIncr, nProposedMax);
    5155         393 :     if (MMCheckSize_t(nNewMax, sizeof(**pPoint2D)))
    5156             :     {
    5157           0 :         return 1;
    5158             :     }
    5159         393 :     if (nNewMax == 0 && *pPoint2D)
    5160           0 :         return 0;
    5161         393 :     if ((pTmp = VSIRealloc(*pPoint2D, (size_t)nNewMax * sizeof(**pPoint2D))) ==
    5162             :         nullptr)
    5163             :     {
    5164           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    5165             :                  "Memory error in MiraMon "
    5166             :                  "driver (MMResizeMM_POINT2DPointer())");
    5167           0 :         return 1;
    5168             :     }
    5169         393 :     *nMax = nNewMax;
    5170         393 :     *pPoint2D = pTmp;
    5171             : 
    5172         393 :     memset((*pPoint2D) + nPrevMax, 0,
    5173         393 :            (size_t)(*nMax - nPrevMax) * sizeof(**pPoint2D));
    5174         393 :     return 0;
    5175             : }
    5176             : 
    5177        1787 : int MMResizeDoublePointer(MM_COORD_TYPE **pDouble, MM_N_VERTICES_TYPE *nMax,
    5178             :                           MM_N_VERTICES_TYPE nNum, MM_N_VERTICES_TYPE nIncr,
    5179             :                           MM_N_VERTICES_TYPE nProposedMax)
    5180             : {
    5181             :     MM_N_VERTICES_TYPE nNewMax, nPrevMax;
    5182             :     void *pTmp;
    5183             : 
    5184        1787 :     if (nNum < *nMax)
    5185        1619 :         return 0;
    5186             : 
    5187         168 :     nPrevMax = *nMax;
    5188         168 :     nNewMax = CPL_MAX(nNum + nIncr, nProposedMax);
    5189         168 :     if (MMCheckSize_t(nNewMax, sizeof(**pDouble)))
    5190             :     {
    5191           0 :         return 1;
    5192             :     }
    5193         168 :     if (nNewMax == 0 && *pDouble)
    5194           0 :         return 0;
    5195         168 :     if ((pTmp = VSIRealloc(*pDouble, (size_t)nNewMax * sizeof(**pDouble))) ==
    5196             :         nullptr)
    5197             :     {
    5198           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    5199             :                  "Memory error in MiraMon "
    5200             :                  "driver (MMResizeDoublePointer())");
    5201           0 :         return 1;
    5202             :     }
    5203         168 :     *nMax = nNewMax;
    5204         168 :     *pDouble = pTmp;
    5205             : 
    5206         168 :     memset((*pDouble) + nPrevMax, 0,
    5207         168 :            (size_t)(*nMax - nPrevMax) * sizeof(**pDouble));
    5208         168 :     return 0;
    5209             : }
    5210             : 
    5211       23553 : int MMResizeStringToOperateIfNeeded(struct MiraMonVectLayerInfo *hMiraMonLayer,
    5212             :                                     MM_EXT_DBF_N_FIELDS nNewSize)
    5213             : {
    5214       23553 :     if (!hMiraMonLayer)
    5215           0 :         return 1;
    5216             : 
    5217       23553 :     if (nNewSize >= hMiraMonLayer->nNumStringToOperate)
    5218             :     {
    5219             :         char *p;
    5220         453 :         if (MMCheckSize_t(nNewSize, 1))
    5221           0 :             return 1;
    5222         453 :         p = (char *)VSICalloc(1, (size_t)nNewSize);
    5223         453 :         if (!p)
    5224             :         {
    5225           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
    5226             :                      "Memory error in MiraMon "
    5227             :                      "driver (MMResizeStringToOperateIfNeeded())");
    5228           0 :             return 1;
    5229             :         }
    5230         453 :         VSIFree(hMiraMonLayer->szStringToOperate);
    5231         453 :         hMiraMonLayer->szStringToOperate = p;
    5232         453 :         hMiraMonLayer->nNumStringToOperate = nNewSize;
    5233             :     }
    5234       23553 :     return 0;
    5235             : }
    5236             : 
    5237             : /* -------------------------------------------------------------------- */
    5238             : /*      Metadata Functions                                              */
    5239             : /* -------------------------------------------------------------------- */
    5240             : 
    5241             : #define LineReturn "\r\n"
    5242             : 
    5243             : // Converts a string from UTF-8 to ANSI to be written in a REL 4 file
    5244         759 : static void MMWrite_ANSI_MetadataKeyDescriptor(
    5245             :     struct MiraMonVectorMetaData *hMMMD, VSILFILE *pF, const char *pszEng,
    5246             :     const char *pszCat, const char *pszEsp, const char *pszCurrentEncoding)
    5247             : {
    5248         759 :     if (!EQUAL(pszCurrentEncoding, CPL_ENC_ISO8859_1))
    5249             :     {
    5250          99 :         char *pszString = nullptr;
    5251             : 
    5252          99 :         switch (hMMMD->nMMLanguage)
    5253             :         {
    5254           2 :             case MM_CAT_LANGUAGE:
    5255             :                 pszString =
    5256           2 :                     CPLRecode(pszCat, pszCurrentEncoding, CPL_ENC_ISO8859_1);
    5257           2 :                 break;
    5258           2 :             case MM_SPA_LANGUAGE:
    5259             :                 pszString =
    5260           2 :                     CPLRecode(pszEsp, pszCurrentEncoding, CPL_ENC_ISO8859_1);
    5261           2 :                 break;
    5262          95 :             default:
    5263             :             case MM_ENG_LANGUAGE:
    5264             :                 pszString =
    5265          95 :                     CPLRecode(pszEng, pszCurrentEncoding, CPL_ENC_ISO8859_1);
    5266          95 :                 break;
    5267             :         }
    5268          99 :         if (pszString)
    5269             :         {
    5270          99 :             VSIFPrintfL(pF, "%s", KEY_descriptor);
    5271          99 :             VSIFPrintfL(pF, "=");
    5272          99 :             VSIFPrintfL(pF, "%s", pszString);
    5273          99 :             VSIFPrintfL(pF, "%s", LineReturn);
    5274          99 :             CPLFree(pszString);
    5275             :         }
    5276             :     }
    5277             :     else
    5278             :     {
    5279             :         const char *pszString;
    5280         660 :         switch (hMMMD->nMMLanguage)
    5281             :         {
    5282           1 :             case MM_CAT_LANGUAGE:
    5283           1 :                 pszString = pszCat;
    5284           1 :                 break;
    5285           1 :             case MM_SPA_LANGUAGE:
    5286           1 :                 pszString = pszEsp;
    5287           1 :                 break;
    5288         658 :             default:
    5289             :             case MM_ENG_LANGUAGE:
    5290         658 :                 pszString = pszEng;
    5291         658 :                 break;
    5292             :         }
    5293         660 :         if (pszString)
    5294             :         {
    5295         660 :             VSIFPrintfL(pF, "%s", KEY_descriptor);
    5296         660 :             VSIFPrintfL(pF, "=");
    5297         660 :             VSIFPrintfL(pF, "%s", pszString);
    5298         660 :             VSIFPrintfL(pF, "%s", LineReturn);
    5299             :         }
    5300             :     }
    5301         759 : }
    5302             : 
    5303             : /*
    5304             :     Writes a MiraMon REL 4 metadata file. Next sections are included:
    5305             :     VERSION, METADADES, IDENTIFICATION, EXTENT, OVERVIEW,
    5306             :     TAULA_PRINCIPAL and GEOMETRIA_I_TOPOLOGIA
    5307             : 
    5308             :     Please, consult the meaning of all them at:
    5309             :     https://www.miramon.cat/help/eng/GeMPlus/ClausREL.htm
    5310             : 
    5311             :     This file must be written in ANSI encoding; therefore, some
    5312             :     conversions are performed for strings that may originally
    5313             :     be in UTF-8.
    5314             : */
    5315         177 : static int MMWriteMetadataFile(struct MiraMonVectorMetaData *hMMMD)
    5316             : {
    5317             :     char aMessage[MM_MESSAGE_LENGTH],
    5318             :         aFileIdentifier[MM_MAX_LEN_LAYER_IDENTIFIER], aMMIDSRS[MM_MAX_ID_SNY];
    5319             :     char *pszChaiCP1252;
    5320             :     MM_EXT_DBF_N_FIELDS nIField;
    5321             :     VSILFILE *pF;
    5322             :     time_t currentTime;
    5323             :     char aTimeString[200];
    5324             : 
    5325         177 :     if (!hMMMD->aLayerName)
    5326           0 :         return 0;
    5327             : 
    5328         177 :     if (nullptr == (pF = VSIFOpenL(hMMMD->aLayerName, "wb")))
    5329             :     {
    5330           0 :         CPLError(CE_Failure, CPLE_OpenFailed, "The file %s must exist.",
    5331             :                  hMMMD->aLayerName);
    5332           0 :         return 1;
    5333             :     }
    5334             : 
    5335             :     // Writing MiraMon version section
    5336         177 :     VSIFPrintfL(pF, "[%s]" LineReturn, SECTION_VERSIO);
    5337             : 
    5338         177 :     VSIFPrintfL(pF, "%s=%u" LineReturn, KEY_Vers, (unsigned)MM_VERS);
    5339         177 :     VSIFPrintfL(pF, "%s=%u" LineReturn, KEY_SubVers, (unsigned)MM_SUBVERS);
    5340             : 
    5341         177 :     VSIFPrintfL(pF, "%s=%u" LineReturn, KEY_VersMetaDades,
    5342             :                 (unsigned)MM_VERS_METADADES);
    5343         177 :     VSIFPrintfL(pF, "%s=%u" LineReturn, KEY_SubVersMetaDades,
    5344             :                 (unsigned)MM_SUBVERS_METADADES);
    5345             : 
    5346             :     // Writing METADADES section
    5347         177 :     VSIFPrintfL(pF, "\r\n[%s]" LineReturn, SECTION_METADADES);
    5348         177 :     CPLStrlcpy(aMessage, hMMMD->aLayerName, sizeof(aMessage));
    5349         177 :     MMGenerateFileIdentifierFromMetadataFileName(aMessage, aFileIdentifier);
    5350             : 
    5351         177 :     pszChaiCP1252 = CPLRecode(aFileIdentifier, CPL_ENC_UTF8, "CP1252");
    5352         177 :     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_FileIdentifier,
    5353             :                 pszChaiCP1252 ? pszChaiCP1252 : aFileIdentifier);
    5354         177 :     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_language, KEY_Value_eng);
    5355         177 :     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_MDIdiom, KEY_Value_eng);
    5356         177 :     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_characterSet,
    5357             :                 KEY_Value_characterSet);
    5358             : 
    5359             :     // Writing IDENTIFICATION section
    5360         177 :     VSIFPrintfL(pF, LineReturn "[%s]" LineReturn, SECTION_IDENTIFICATION);
    5361         177 :     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_code,
    5362             :                 pszChaiCP1252 ? pszChaiCP1252 : aFileIdentifier);
    5363         177 :     VSIFPrintfL(pF, "%s=" LineReturn, KEY_codeSpace);
    5364         177 :     CPLFree(pszChaiCP1252);  // Not needed
    5365         177 :     if (hMMMD->szLayerTitle && !MMIsEmptyString(hMMMD->szLayerTitle))
    5366             :     {
    5367         177 :         pszChaiCP1252 = CPLRecode(hMMMD->szLayerTitle, CPL_ENC_UTF8, "CP1252");
    5368         177 :         if (hMMMD->ePlainLT == MM_LayerType_Point)
    5369          34 :             VSIFPrintfL(pF, "%s=%s (pnt)" LineReturn, KEY_DatasetTitle,
    5370             :                         pszChaiCP1252 ? pszChaiCP1252 : hMMMD->szLayerTitle);
    5371         177 :         if (hMMMD->ePlainLT == MM_LayerType_Arc)
    5372          58 :             VSIFPrintfL(pF, "%s=%s (arc)" LineReturn, KEY_DatasetTitle,
    5373             :                         pszChaiCP1252 ? pszChaiCP1252 : hMMMD->szLayerTitle);
    5374         177 :         if (hMMMD->ePlainLT == MM_LayerType_Pol)
    5375          27 :             VSIFPrintfL(pF, "%s=%s (pol)" LineReturn, KEY_DatasetTitle,
    5376             :                         pszChaiCP1252 ? pszChaiCP1252 : hMMMD->szLayerTitle);
    5377         177 :         CPLFree(pszChaiCP1252);
    5378             :     }
    5379         177 :     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_language, KEY_Value_eng);
    5380             : 
    5381         177 :     if (hMMMD->ePlainLT != MM_LayerType_Node &&
    5382         119 :         hMMMD->ePlainLT != MM_LayerType_Pol)
    5383             :     {
    5384             :         // SPATIAL_REFERENCE_SYSTEM:HORIZONTAL
    5385          92 :         VSIFPrintfL(pF, LineReturn "[%s:%s]" LineReturn,
    5386             :                     SECTION_SPATIAL_REFERENCE_SYSTEM, SECTION_HORIZONTAL);
    5387         113 :         if (!ReturnMMIDSRSFromEPSGCodeSRS(hMMMD->pSRS, aMMIDSRS) &&
    5388          21 :             !MMIsEmptyString(aMMIDSRS))
    5389          21 :             VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_HorizontalSystemIdentifier,
    5390             :                         aMMIDSRS);
    5391             :         else
    5392             :         {
    5393          71 :             CPLError(CE_Warning, CPLE_NotSupported,
    5394             :                      "The MiraMon driver cannot assign any HRS.");
    5395             :             // Horizontal Reference System
    5396          71 :             VSIFPrintfL(pF, "%s=plane" LineReturn,
    5397             :                         KEY_HorizontalSystemIdentifier);
    5398          71 :             VSIFPrintfL(pF, "%s=local" LineReturn,
    5399             :                         KEY_HorizontalSystemDefinition);
    5400          71 :             if (hMMMD->pXUnit)
    5401           0 :                 VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_unitats, hMMMD->pXUnit);
    5402          71 :             if (hMMMD->pYUnit)
    5403             :             {
    5404           0 :                 if (!hMMMD->pXUnit || strcasecmp(hMMMD->pXUnit, hMMMD->pYUnit))
    5405           0 :                     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_unitatsY,
    5406             :                                 hMMMD->pYUnit);
    5407             :             }
    5408             :         }
    5409             : 
    5410             :         // SPATIAL_REFERENCE_SYSTEM:VERTICAL
    5411             :         // Llegim les unitats del Sist. ref. vertical
    5412          92 :         if (hMMMD->pZUnit)
    5413             :         {
    5414           0 :             VSIFPrintfL(pF, LineReturn "[%s:%s]" LineReturn,
    5415             :                         SECTION_SPATIAL_REFERENCE_SYSTEM, SECTION_VERTICAL);
    5416           0 :             VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_unitats, hMMMD->pZUnit);
    5417             :         }
    5418             :     }
    5419             : 
    5420         177 :     if (hMMMD->ePlainLT == MM_LayerType_Pol && hMMMD->aArcFile)
    5421             :     {
    5422             :         // Writing OVERVIEW:ASPECTES_TECNICS in polygon metadata file.
    5423             :         // ArcSource=fitx_pol.arc
    5424          27 :         pszChaiCP1252 = CPLRecode(hMMMD->aArcFile, CPL_ENC_UTF8, "CP1252");
    5425          27 :         VSIFPrintfL(pF, LineReturn "[%s]" LineReturn,
    5426             :                     SECTION_OVVW_ASPECTES_TECNICS);
    5427          27 :         VSIFPrintfL(pF, "%s=\"%s\"" LineReturn, KEY_ArcSource, pszChaiCP1252);
    5428          27 :         CPLFree(pszChaiCP1252);
    5429             :     }
    5430         150 :     else if (hMMMD->ePlainLT == MM_LayerType_Arc && hMMMD->aArcFile)
    5431             :     {
    5432          27 :         pszChaiCP1252 = CPLRecode(hMMMD->aArcFile, CPL_ENC_UTF8, "CP1252");
    5433             :         // Writing OVERVIEW:ASPECTES_TECNICS in arc metadata file.
    5434             :         // Ciclat1=fitx_arc.pol
    5435          27 :         VSIFPrintfL(pF, LineReturn "[%s]" LineReturn,
    5436             :                     SECTION_OVVW_ASPECTES_TECNICS);
    5437          27 :         VSIFPrintfL(pF, "Ciclat1=\"%s\"" LineReturn, pszChaiCP1252);
    5438          27 :         CPLFree(pszChaiCP1252);
    5439             :     }
    5440             : 
    5441             :     // Writing EXTENT section
    5442         177 :     VSIFPrintfL(pF, LineReturn "[%s]" LineReturn, SECTION_EXTENT);
    5443         177 :     VSIFPrintfL(pF, "%s=0" LineReturn, KEY_toler_env);
    5444             : 
    5445         177 :     if (hMMMD->hBB.dfMinX != MM_UNDEFINED_STATISTICAL_VALUE &&
    5446         177 :         hMMMD->hBB.dfMaxX != -MM_UNDEFINED_STATISTICAL_VALUE &&
    5447         177 :         hMMMD->hBB.dfMinY != MM_UNDEFINED_STATISTICAL_VALUE &&
    5448         177 :         hMMMD->hBB.dfMaxY != -MM_UNDEFINED_STATISTICAL_VALUE)
    5449             :     {
    5450         177 :         VSIFPrintfL(pF, "%s=%lf" LineReturn, KEY_MinX, hMMMD->hBB.dfMinX);
    5451         177 :         VSIFPrintfL(pF, "%s=%lf" LineReturn, KEY_MaxX, hMMMD->hBB.dfMaxX);
    5452         177 :         VSIFPrintfL(pF, "%s=%lf" LineReturn, KEY_MinY, hMMMD->hBB.dfMinY);
    5453         177 :         VSIFPrintfL(pF, "%s=%lf" LineReturn, KEY_MaxY, hMMMD->hBB.dfMaxY);
    5454             :     }
    5455             : 
    5456             :     // Writing OVERVIEW section
    5457         177 :     VSIFPrintfL(pF, LineReturn "[%s]" LineReturn, SECTION_OVERVIEW);
    5458             : 
    5459         177 :     currentTime = time(nullptr);
    5460             : 
    5461             :     struct tm ltime;
    5462         177 :     VSILocalTime(&currentTime, &ltime);
    5463         177 :     snprintf(aTimeString, sizeof(aTimeString), "%04d%02d%02d %02d%02d%02d%02d",
    5464         177 :              ltime.tm_year + 1900, ltime.tm_mon + 1, ltime.tm_mday,
    5465             :              ltime.tm_hour, ltime.tm_min, ltime.tm_sec, 0);
    5466         177 :     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_CreationDate, aTimeString);
    5467         177 :     VSIFPrintfL(pF, LineReturn);
    5468             : 
    5469             :     // Writing TAULA_PRINCIPAL section
    5470         177 :     VSIFPrintfL(pF, "[%s]" LineReturn, SECTION_TAULA_PRINCIPAL);
    5471         177 :     VSIFPrintfL(pF, "IdGrafic=%s" LineReturn, szMMNomCampIdGraficDefecte);
    5472         177 :     VSIFPrintfL(pF, "TipusRelacio=RELACIO_1_1_DICC" LineReturn);
    5473             : 
    5474         177 :     VSIFPrintfL(pF, LineReturn);
    5475         177 :     VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5476             :                 szMMNomCampIdGraficDefecte);
    5477         177 :     VSIFPrintfL(pF, "visible=0" LineReturn);
    5478         177 :     VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5479             : 
    5480         177 :     MMWrite_ANSI_MetadataKeyDescriptor(
    5481             :         hMMMD, pF, szInternalGraphicIdentifierEng,
    5482             :         szInternalGraphicIdentifierCat, szInternalGraphicIdentifierSpa,
    5483             :         CPL_ENC_ISO8859_1);
    5484             : 
    5485         177 :     if (hMMMD->ePlainLT == MM_LayerType_Arc)
    5486             :     {
    5487          58 :         VSIFPrintfL(pF, LineReturn);
    5488          58 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5489             :                     szMMNomCampNVertexsDefecte);
    5490          58 :         VSIFPrintfL(pF, "visible=0" LineReturn);
    5491          58 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5492          58 :         MMWrite_ANSI_MetadataKeyDescriptor(
    5493             :             hMMMD, pF, szNumberOfVerticesEng, szNumberOfVerticesCat,
    5494             :             szNumberOfVerticesSpa, CPL_ENC_ISO8859_1);
    5495             : 
    5496          58 :         VSIFPrintfL(pF, LineReturn);
    5497          58 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5498             :                     szMMNomCampLongitudArcDefecte);
    5499          58 :         MMWrite_ANSI_MetadataKeyDescriptor(hMMMD, pF, szLengthOfAarcEng,
    5500             :                                            szLengthOfAarcCat, szLengthOfAarcSpa,
    5501             :                                            CPL_ENC_ISO8859_1);
    5502             : 
    5503          58 :         VSIFPrintfL(pF, LineReturn);
    5504          58 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5505             :                     szMMNomCampNodeIniDefecte);
    5506          58 :         VSIFPrintfL(pF, "visible=0" LineReturn);
    5507          58 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5508          58 :         MMWrite_ANSI_MetadataKeyDescriptor(hMMMD, pF, szInitialNodeEng,
    5509             :                                            szInitialNodeCat, szInitialNodeSpa,
    5510             :                                            CPL_ENC_ISO8859_1);
    5511             : 
    5512          58 :         VSIFPrintfL(pF, LineReturn);
    5513          58 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5514             :                     szMMNomCampNodeFiDefecte);
    5515          58 :         VSIFPrintfL(pF, "visible=0" LineReturn);
    5516          58 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5517          58 :         MMWrite_ANSI_MetadataKeyDescriptor(hMMMD, pF, szFinalNodeEng,
    5518             :                                            szFinalNodeCat, szFinalNodeSpa,
    5519             :                                            CPL_ENC_ISO8859_1);
    5520             : 
    5521          58 :         VSIFPrintfL(pF, LineReturn);
    5522          58 :         VSIFPrintfL(pF, "[GEOMETRIA_I_TOPOLOGIA]" LineReturn);
    5523          58 :         VSIFPrintfL(pF, "NomCampNVertexs=%s" LineReturn,
    5524             :                     szMMNomCampNVertexsDefecte);
    5525          58 :         VSIFPrintfL(pF, "NomCampLongitudArc=%s" LineReturn,
    5526             :                     szMMNomCampLongitudArcDefecte);
    5527          58 :         VSIFPrintfL(pF, "NomCampNodeIni=%s" LineReturn,
    5528             :                     szMMNomCampNodeIniDefecte);
    5529          58 :         VSIFPrintfL(pF, "NomCampNodeFi=%s" LineReturn,
    5530             :                     szMMNomCampNodeFiDefecte);
    5531             :     }
    5532         119 :     else if (hMMMD->ePlainLT == MM_LayerType_Node)
    5533             :     {
    5534          58 :         VSIFPrintfL(pF, LineReturn);
    5535          58 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5536             :                     szMMNomCampArcsANodeDefecte);
    5537          58 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5538          58 :         MMWrite_ANSI_MetadataKeyDescriptor(
    5539             :             hMMMD, pF, szNumberOfArcsToNodeEng, szNumberOfArcsToNodeCat,
    5540             :             szNumberOfArcsToNodeSpa, CPL_ENC_ISO8859_1);
    5541             : 
    5542          58 :         VSIFPrintfL(pF, LineReturn);
    5543          58 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5544             :                     szMMNomCampTipusNodeDefecte);
    5545          58 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5546          58 :         MMWrite_ANSI_MetadataKeyDescriptor(hMMMD, pF, szNodeTypeEng,
    5547             :                                            szNodeTypeCat, szNodeTypeSpa,
    5548             :                                            CPL_ENC_ISO8859_1);
    5549             : 
    5550          58 :         VSIFPrintfL(pF, LineReturn);
    5551          58 :         VSIFPrintfL(pF, "[GEOMETRIA_I_TOPOLOGIA]" LineReturn);
    5552          58 :         VSIFPrintfL(pF, "NomCampArcsANode=%s" LineReturn,
    5553             :                     szMMNomCampArcsANodeDefecte);
    5554          58 :         VSIFPrintfL(pF, "NomCampTipusNode=%s" LineReturn,
    5555             :                     szMMNomCampTipusNodeDefecte);
    5556             :     }
    5557          61 :     else if (hMMMD->ePlainLT == MM_LayerType_Pol)
    5558             :     {
    5559          27 :         VSIFPrintfL(pF, LineReturn);
    5560          27 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5561             :                     szMMNomCampNVertexsDefecte);
    5562          27 :         VSIFPrintfL(pF, "visible=0" LineReturn);
    5563          27 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5564          27 :         MMWrite_ANSI_MetadataKeyDescriptor(
    5565             :             hMMMD, pF, szNumberOfVerticesEng, szNumberOfVerticesCat,
    5566             :             szNumberOfVerticesSpa, CPL_ENC_ISO8859_1);
    5567             : 
    5568          27 :         VSIFPrintfL(pF, LineReturn);
    5569          27 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5570             :                     szMMNomCampPerimetreDefecte);
    5571          27 :         MMWrite_ANSI_MetadataKeyDescriptor(
    5572             :             hMMMD, pF, szPerimeterOfThePolygonEng, szPerimeterOfThePolygonCat,
    5573             :             szPerimeterOfThePolygonSpa, CPL_ENC_ISO8859_1);
    5574             : 
    5575          27 :         VSIFPrintfL(pF, LineReturn);
    5576          27 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5577             :                     szMMNomCampAreaDefecte);
    5578          27 :         MMWrite_ANSI_MetadataKeyDescriptor(
    5579             :             hMMMD, pF, szAreaOfThePolygonEng, szAreaOfThePolygonCat,
    5580             :             szAreaOfThePolygonSpa, CPL_ENC_ISO8859_1);
    5581             : 
    5582          27 :         VSIFPrintfL(pF, LineReturn);
    5583          27 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5584             :                     szMMNomCampNArcsDefecte);
    5585          27 :         VSIFPrintfL(pF, "visible=0" LineReturn);
    5586          27 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5587          27 :         MMWrite_ANSI_MetadataKeyDescriptor(hMMMD, pF, szNumberOfArcsEng,
    5588             :                                            szNumberOfArcsCat, szNumberOfArcsSpa,
    5589             :                                            CPL_ENC_ISO8859_1);
    5590             : 
    5591          27 :         VSIFPrintfL(pF, LineReturn);
    5592          27 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5593             :                     szMMNomCampNPoligonsDefecte);
    5594          27 :         VSIFPrintfL(pF, "visible=0" LineReturn);
    5595          27 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5596          27 :         MMWrite_ANSI_MetadataKeyDescriptor(
    5597             :             hMMMD, pF, szNumberOfElementaryPolygonsEng,
    5598             :             szNumberOfElementaryPolygonsCat, szNumberOfElementaryPolygonsSpa,
    5599             :             CPL_ENC_ISO8859_1);
    5600             : 
    5601          27 :         VSIFPrintfL(pF, LineReturn);
    5602          27 :         VSIFPrintfL(pF, "[GEOMETRIA_I_TOPOLOGIA]" LineReturn);
    5603          27 :         VSIFPrintfL(pF, "NomCampNVertexs=%s" LineReturn,
    5604             :                     szMMNomCampNVertexsDefecte);
    5605          27 :         VSIFPrintfL(pF, "NomCampPerimetre=%s" LineReturn,
    5606             :                     szMMNomCampPerimetreDefecte);
    5607          27 :         VSIFPrintfL(pF, "NomCampArea=%s" LineReturn, szMMNomCampAreaDefecte);
    5608          27 :         VSIFPrintfL(pF, "NomCampNArcs=%s" LineReturn, szMMNomCampNArcsDefecte);
    5609          27 :         VSIFPrintfL(pF, "NomCampNPoligons=%s" LineReturn,
    5610             :                     szMMNomCampNPoligonsDefecte);
    5611             :     }
    5612             : 
    5613         177 :     if (hMMMD->pLayerDB && hMMMD->pLayerDB->nNFields > 0)
    5614             :     {
    5615             :         // For each field of the databes
    5616         586 :         for (nIField = 0; nIField < hMMMD->pLayerDB->nNFields; nIField++)
    5617             :         {
    5618         495 :             VSIFPrintfL(pF, LineReturn "[%s:%s]" LineReturn,
    5619             :                         SECTION_TAULA_PRINCIPAL,
    5620         495 :                         hMMMD->pLayerDB->pFields[nIField].pszFieldName);
    5621             : 
    5622         495 :             if (!MMIsEmptyString(
    5623         594 :                     hMMMD->pLayerDB->pFields[nIField].pszFieldDescription) &&
    5624          99 :                 !MMIsEmptyString(
    5625          99 :                     hMMMD->pLayerDB->pFields[nIField].pszFieldName))
    5626             :             {
    5627          99 :                 MMWrite_ANSI_MetadataKeyDescriptor(
    5628             :                     hMMMD, pF,
    5629          99 :                     hMMMD->pLayerDB->pFields[nIField].pszFieldDescription,
    5630          99 :                     hMMMD->pLayerDB->pFields[nIField].pszFieldDescription,
    5631          99 :                     hMMMD->pLayerDB->pFields[nIField].pszFieldDescription,
    5632             :                     CPL_ENC_UTF8);
    5633             :             }
    5634             : 
    5635             :             // Exception in a particular case: "altura" is a catalan word that means
    5636             :             // "height". Its unit by default will be "m" instead of "unknown".
    5637             :             // The same goes for "z", which easily means height.
    5638         495 :             if (EQUAL("altura",
    5639         495 :                       hMMMD->pLayerDB->pFields[nIField].pszFieldName) ||
    5640         495 :                 EQUAL("z", hMMMD->pLayerDB->pFields[nIField].pszFieldName))
    5641             :             {
    5642           0 :                 VSIFPrintfL(pF, "unitats=m" LineReturn);
    5643             :             }
    5644             :             else
    5645             :             {
    5646             :                 // By default units of field values will not be shown.
    5647         495 :                 VSIFPrintfL(pF, "MostrarUnitats=0" LineReturn);
    5648             :             }
    5649             :         }
    5650             :     }
    5651         177 :     VSIFCloseL(pF);
    5652         177 :     return 0;
    5653             : }
    5654             : 
    5655             : // Writes metadata files for MiraMon vector layers
    5656         194 : static int MMWriteVectorMetadataFile(struct MiraMonVectLayerInfo *hMiraMonLayer,
    5657             :                                      int layerPlainType, int layerMainPlainType)
    5658             : {
    5659             :     struct MiraMonVectorMetaData hMMMD;
    5660             : 
    5661         194 :     if (!hMiraMonLayer)
    5662           0 :         return 1;
    5663             : 
    5664             :     // MiraMon writes a REL file of each .pnt, .arc, .nod or .pol
    5665         194 :     memset(&hMMMD, 0, sizeof(hMMMD));
    5666         194 :     hMMMD.ePlainLT = layerPlainType;
    5667         194 :     hMMMD.pSRS = hMiraMonLayer->pSRS;
    5668         194 :     hMMMD.pZUnit = hMiraMonLayer->pZUnit;
    5669         194 :     hMMMD.nMMLanguage = hMiraMonLayer->nMMLanguage;
    5670             : 
    5671         194 :     hMMMD.szLayerTitle = hMiraMonLayer->szLayerTitle;
    5672         194 :     if (layerPlainType == MM_LayerType_Point)
    5673             :     {
    5674          34 :         hMMMD.aLayerName = hMiraMonLayer->MMPoint.pszREL_LayerName;
    5675          34 :         if (MMIsEmptyString(hMMMD.aLayerName))
    5676           0 :             return 0;  // If no file, no error. Just continue.
    5677          34 :         memcpy(&hMMMD.hBB, &hMiraMonLayer->TopHeader.hBB, sizeof(hMMMD.hBB));
    5678          34 :         hMMMD.pLayerDB = hMiraMonLayer->pLayerDB;
    5679          34 :         return MMWriteMetadataFile(&hMMMD);
    5680             :     }
    5681         160 :     else if (layerPlainType == MM_LayerType_Arc)
    5682             :     {
    5683             :         int nResult;
    5684             : 
    5685             :         // Arcs and not polygons
    5686          58 :         if (layerMainPlainType == MM_LayerType_Arc)
    5687             :         {
    5688          31 :             hMMMD.aLayerName = hMiraMonLayer->MMArc.pszREL_LayerName;
    5689          31 :             if (MMIsEmptyString(hMMMD.aLayerName))
    5690           0 :                 return 0;  // If no file, no error. Just continue.
    5691          31 :             memcpy(&hMMMD.hBB, &hMiraMonLayer->TopHeader.hBB,
    5692             :                    sizeof(hMMMD.hBB));
    5693          31 :             hMMMD.pLayerDB = hMiraMonLayer->pLayerDB;
    5694             :         }
    5695             :         // Arcs and polygons
    5696             :         else
    5697             :         {
    5698             :             // Arc from polygon
    5699          27 :             hMMMD.aLayerName = hMiraMonLayer->MMPolygon.MMArc.pszREL_LayerName;
    5700          27 :             if (MMIsEmptyString(hMMMD.aLayerName))
    5701           0 :                 return 0;  // If no file, no error. Just continue.
    5702             : 
    5703          27 :             memcpy(&hMMMD.hBB, &hMiraMonLayer->MMPolygon.TopArcHeader.hBB,
    5704             :                    sizeof(hMMMD.hBB));
    5705          27 :             hMMMD.pLayerDB = nullptr;
    5706          27 :             hMMMD.aArcFile = CPLStrdup(
    5707          27 :                 CPLGetFilename(hMiraMonLayer->MMPolygon.pszLayerName));
    5708             :         }
    5709          58 :         nResult = MMWriteMetadataFile(&hMMMD);
    5710          58 :         VSIFree(hMMMD.aArcFile);
    5711          58 :         return nResult;
    5712             :     }
    5713         102 :     else if (layerPlainType == MM_LayerType_Pol)
    5714             :     {
    5715             :         int nResult;
    5716             : 
    5717          27 :         hMMMD.aLayerName = hMiraMonLayer->MMPolygon.pszREL_LayerName;
    5718             : 
    5719          27 :         if (MMIsEmptyString(hMMMD.aLayerName))
    5720           0 :             return 0;  // If no file, no error. Just continue.
    5721             : 
    5722          27 :         memcpy(&hMMMD.hBB, &hMiraMonLayer->TopHeader.hBB, sizeof(hMMMD.hBB));
    5723          27 :         hMMMD.pLayerDB = hMiraMonLayer->pLayerDB;
    5724          27 :         hMMMD.aArcFile = CPLStrdup(
    5725          27 :             CPLGetFilename(hMiraMonLayer->MMPolygon.MMArc.pszLayerName));
    5726          27 :         nResult = MMWriteMetadataFile(&hMMMD);
    5727          27 :         VSIFree(hMMMD.aArcFile);
    5728          27 :         return nResult;
    5729             :     }
    5730          75 :     else if (layerPlainType == MM_LayerType_Node)
    5731             :     {
    5732             :         // Node from arc
    5733          58 :         if (layerMainPlainType == MM_LayerType_Arc)
    5734             :         {
    5735          31 :             hMMMD.aLayerName = hMiraMonLayer->MMArc.MMNode.pszREL_LayerName;
    5736          31 :             if (MMIsEmptyString(hMMMD.aLayerName))
    5737           0 :                 return 0;  // If no file, no error. Just continue.
    5738          31 :             memcpy(&hMMMD.hBB, &hMiraMonLayer->MMArc.TopNodeHeader.hBB,
    5739             :                    sizeof(hMMMD.hBB));
    5740             :         }
    5741             :         else  // Node from polygon
    5742             :         {
    5743          27 :             hMMMD.aLayerName =
    5744          27 :                 hMiraMonLayer->MMPolygon.MMArc.MMNode.pszREL_LayerName;
    5745          27 :             if (MMIsEmptyString(hMMMD.aLayerName))
    5746           0 :                 return 0;  // If no file, no error. Just continue.
    5747          27 :             memcpy(&hMMMD.hBB,
    5748          27 :                    &hMiraMonLayer->MMPolygon.MMArc.TopNodeHeader.hBB,
    5749             :                    sizeof(hMMMD.hBB));
    5750             :         }
    5751          58 :         hMMMD.pLayerDB = nullptr;
    5752          58 :         return MMWriteMetadataFile(&hMMMD);
    5753             :     }
    5754          17 :     return 0;
    5755             : }
    5756             : 
    5757         109 : int MMWriteVectorMetadata(struct MiraMonVectLayerInfo *hMiraMonLayer)
    5758             : {
    5759         109 :     if (!hMiraMonLayer)
    5760           0 :         return 1;
    5761             : 
    5762         109 :     if (hMiraMonLayer->bIsPoint)
    5763          34 :         return MMWriteVectorMetadataFile(hMiraMonLayer, MM_LayerType_Point,
    5764             :                                          MM_LayerType_Point);
    5765          75 :     if (hMiraMonLayer->bIsArc && !hMiraMonLayer->bIsPolygon)
    5766             :     {
    5767          31 :         if (MMWriteVectorMetadataFile(hMiraMonLayer, MM_LayerType_Node,
    5768             :                                       MM_LayerType_Arc))
    5769           0 :             return 1;
    5770          31 :         return MMWriteVectorMetadataFile(hMiraMonLayer, MM_LayerType_Arc,
    5771             :                                          MM_LayerType_Arc);
    5772             :     }
    5773          44 :     if (hMiraMonLayer->bIsPolygon)
    5774             :     {
    5775          27 :         if (MMWriteVectorMetadataFile(hMiraMonLayer, MM_LayerType_Node,
    5776             :                                       MM_LayerType_Pol))
    5777           0 :             return 1;
    5778          27 :         if (MMWriteVectorMetadataFile(hMiraMonLayer, MM_LayerType_Arc,
    5779             :                                       MM_LayerType_Pol))
    5780           0 :             return 1;
    5781          27 :         return MMWriteVectorMetadataFile(hMiraMonLayer, MM_LayerType_Pol,
    5782             :                                          MM_LayerType_Pol);
    5783             :     }
    5784          17 :     if (hMiraMonLayer->bIsDBF)
    5785             :     {
    5786          17 :         return MMWriteVectorMetadataFile(hMiraMonLayer, MM_LayerType_Unknown,
    5787             :                                          MM_LayerType_Unknown);
    5788             :     }
    5789           0 :     return 0;
    5790             : }
    5791             : 
    5792             : /* -------------------------------------------------------------------- */
    5793             : /*      MiraMon database functions                                      */
    5794             : /* -------------------------------------------------------------------- */
    5795             : 
    5796             : // Initializes a MiraMon database associated with a vector layer:
    5797             : // Sets the usual fields that MiraMon needs and after them, adds
    5798             : // all fields of the input layer
    5799         194 : static int MMInitMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    5800             :                       struct MMAdmDatabase *pMMAdmDB)
    5801             : {
    5802         194 :     if (!hMiraMonLayer || !pMMAdmDB)
    5803           0 :         return 1;
    5804             : 
    5805         194 :     if (MMIsEmptyString(pMMAdmDB->pszExtDBFLayerName))
    5806           0 :         return 0;  // No file, no error. Just continue
    5807             : 
    5808         194 :     strcpy(pMMAdmDB->pMMBDXP->ReadingMode, "wb+");
    5809         194 :     if (FALSE == MM_CreateAndOpenDBFFile(pMMAdmDB->pMMBDXP,
    5810         194 :                                          pMMAdmDB->pszExtDBFLayerName))
    5811             :     {
    5812           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
    5813             :                  "Error pMMAdmDB: Cannot create or open file %s.",
    5814           0 :                  pMMAdmDB->pszExtDBFLayerName);
    5815           0 :         return 1;
    5816             :     }
    5817             : 
    5818         194 :     VSIFSeekL(pMMAdmDB->pMMBDXP->pfDataBase,
    5819         194 :               pMMAdmDB->pMMBDXP->FirstRecordOffset, SEEK_SET);
    5820             : 
    5821         194 :     if (MMInitFlush(&pMMAdmDB->FlushRecList, pMMAdmDB->pMMBDXP->pfDataBase,
    5822             :                     MM_1MB, &pMMAdmDB->pRecList,
    5823         194 :                     pMMAdmDB->pMMBDXP->FirstRecordOffset, 0))
    5824           0 :         return 1;
    5825             : 
    5826         194 :     pMMAdmDB->nNumRecordOnCourse =
    5827         194 :         (GUInt64)pMMAdmDB->pMMBDXP->BytesPerRecord + 1;
    5828         194 :     if (MMCheckSize_t(pMMAdmDB->nNumRecordOnCourse, 1))
    5829           0 :         return 1;
    5830         194 :     pMMAdmDB->szRecordOnCourse =
    5831         194 :         VSICalloc(1, (size_t)pMMAdmDB->nNumRecordOnCourse);
    5832         194 :     if (!pMMAdmDB->szRecordOnCourse)
    5833             :     {
    5834           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    5835             :                  "Memory error in MiraMon "
    5836             :                  "driver (MMInitMMDB())");
    5837           0 :         return 1;
    5838             :     }
    5839         194 :     return 0;
    5840             : }
    5841             : 
    5842             : // Creates a MiraMon database associated with a vector layer.
    5843             : // It determines the number of fields and initializes the database header
    5844             : // accordingly. Depending on the layer type (point, arc, polygon, or generic),
    5845             : // it defines the fields and initializes the corresponding MiraMon database
    5846             : // structures.
    5847         109 : int MMCreateMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    5848             :                  struct MM_POINT_2D *pFirstCoord)
    5849             : {
    5850         109 :     struct MM_DATA_BASE_XP *pBD_XP = nullptr, *pBD_XP_Aux = nullptr;
    5851             :     struct MM_FIELD MMField;
    5852             :     size_t nIFieldLayer;
    5853         109 :     MM_EXT_DBF_N_FIELDS nIField = 0;
    5854             :     MM_EXT_DBF_N_FIELDS nNFields;
    5855             : 
    5856         109 :     if (!hMiraMonLayer)
    5857           0 :         return 1;
    5858             : 
    5859             :     // If the SRS is unknown, we attempt to deduce the appropriate number
    5860             :     // of decimals to be used in the reserved fields as LONG_ARC, PERIMETRE,
    5861             :     // or AREA using the coordinate values. It's not 100% reliable, but it's a
    5862             :     // good approximation.
    5863         109 :     if (hMiraMonLayer->nSRSType == MM_SRS_LAYER_IS_UNKNOWN_TYPE && pFirstCoord)
    5864             :     {
    5865          71 :         if (pFirstCoord->dfX < -360 || pFirstCoord->dfX > 360)
    5866           8 :             hMiraMonLayer->nSRSType = MM_SRS_LAYER_IS_PROJECTED_TYPE;
    5867             :         else
    5868          63 :             hMiraMonLayer->nSRSType = MM_SRS_LAYER_IS_GEOGRAPHIC_TYPE;
    5869             :     }
    5870             : 
    5871         109 :     if (hMiraMonLayer->bIsPoint)
    5872             :     {
    5873          34 :         if (hMiraMonLayer->pLayerDB)
    5874          34 :             nNFields =
    5875          34 :                 MM_PRIVATE_POINT_DB_FIELDS + hMiraMonLayer->pLayerDB->nNFields;
    5876             :         else
    5877           0 :             nNFields = MM_PRIVATE_POINT_DB_FIELDS;
    5878             : 
    5879             :         // Before allocating new memory, there might be some previously allocated but unused memory.
    5880             :         // Let's free that memory first.
    5881          34 :         if (hMiraMonLayer->MMPoint.MMAdmDB.pMMBDXP)
    5882           0 :             MM_ReleaseDBFHeader(&hMiraMonLayer->MMPoint.MMAdmDB.pMMBDXP);
    5883             : 
    5884          34 :         pBD_XP = hMiraMonLayer->MMPoint.MMAdmDB.pMMBDXP =
    5885          34 :             MM_CreateDBFHeader(nNFields, hMiraMonLayer->nCharSet);
    5886             : 
    5887          34 :         if (!pBD_XP)
    5888           0 :             return 1;
    5889             : 
    5890          34 :         if (0 == (nIField = (MM_EXT_DBF_N_FIELDS)MM_DefineFirstPointFieldsDB_XP(
    5891             :                       pBD_XP)))
    5892           0 :             return 1;
    5893             :     }
    5894          75 :     else if (hMiraMonLayer->bIsArc && !hMiraMonLayer->bIsPolygon)
    5895             :     {
    5896          31 :         if (hMiraMonLayer->pLayerDB)
    5897          30 :             nNFields =
    5898          30 :                 MM_PRIVATE_ARC_DB_FIELDS + hMiraMonLayer->pLayerDB->nNFields;
    5899             :         else
    5900           1 :             nNFields = MM_PRIVATE_ARC_DB_FIELDS;
    5901             : 
    5902             :         // Before allocating new memory, there might be some previously allocated but unused memory.
    5903             :         // Let's free that memory first.
    5904          31 :         if (hMiraMonLayer->MMArc.MMAdmDB.pMMBDXP)
    5905           0 :             MM_ReleaseDBFHeader(&hMiraMonLayer->MMArc.MMAdmDB.pMMBDXP);
    5906             : 
    5907          31 :         pBD_XP = hMiraMonLayer->MMArc.MMAdmDB.pMMBDXP =
    5908          31 :             MM_CreateDBFHeader(nNFields, hMiraMonLayer->nCharSet);
    5909             : 
    5910          31 :         if (!pBD_XP)
    5911           0 :             return 1;
    5912             : 
    5913          31 :         if (0 == (nIField = (MM_EXT_DBF_N_FIELDS)MM_DefineFirstArcFieldsDB_XP(
    5914             :                       pBD_XP,
    5915          31 :                       hMiraMonLayer->nSRSType == MM_SRS_LAYER_IS_PROJECTED_TYPE
    5916             :                           ? 3
    5917             :                           : 9)))
    5918           0 :             return 1;
    5919             : 
    5920             :         // Before allocating new memory, there might be some previously allocated but unused memory.
    5921             :         // Let's free that memory first.
    5922          31 :         if (hMiraMonLayer->MMArc.MMNode.MMAdmDB.pMMBDXP)
    5923           0 :             MM_ReleaseDBFHeader(&hMiraMonLayer->MMArc.MMNode.MMAdmDB.pMMBDXP);
    5924             : 
    5925          31 :         pBD_XP_Aux = hMiraMonLayer->MMArc.MMNode.MMAdmDB.pMMBDXP =
    5926          31 :             MM_CreateDBFHeader(3, hMiraMonLayer->nCharSet);
    5927             : 
    5928          31 :         if (!pBD_XP_Aux)
    5929           0 :             return 1;
    5930             : 
    5931          31 :         if (0 == MM_DefineFirstNodeFieldsDB_XP(pBD_XP_Aux))
    5932           0 :             return 1;
    5933             :     }
    5934          44 :     else if (hMiraMonLayer->bIsPolygon)
    5935             :     {
    5936          27 :         if (hMiraMonLayer->pLayerDB)
    5937          27 :             nNFields = MM_PRIVATE_POLYGON_DB_FIELDS +
    5938          27 :                        hMiraMonLayer->pLayerDB->nNFields;
    5939             :         else
    5940           0 :             nNFields = MM_PRIVATE_POLYGON_DB_FIELDS;
    5941             : 
    5942             :         // Before allocating new memory, there might be some previously allocated but unused memory.
    5943             :         // Let's free that memory first.
    5944          27 :         if (hMiraMonLayer->MMPolygon.MMAdmDB.pMMBDXP)
    5945           0 :             MM_ReleaseDBFHeader(&hMiraMonLayer->MMPolygon.MMAdmDB.pMMBDXP);
    5946             : 
    5947          27 :         pBD_XP = hMiraMonLayer->MMPolygon.MMAdmDB.pMMBDXP =
    5948          27 :             MM_CreateDBFHeader(nNFields, hMiraMonLayer->nCharSet);
    5949             : 
    5950          27 :         if (!pBD_XP)
    5951           0 :             return 1;
    5952             : 
    5953          27 :         if (0 ==
    5954          54 :             (nIField = (MM_EXT_DBF_N_FIELDS)MM_DefineFirstPolygonFieldsDB_XP(
    5955             :                  pBD_XP,
    5956          27 :                  hMiraMonLayer->nSRSType == MM_SRS_LAYER_IS_PROJECTED_TYPE ? 3
    5957             :                                                                            : 9,
    5958          27 :                  hMiraMonLayer->nSRSType == MM_SRS_LAYER_IS_PROJECTED_TYPE
    5959             :                      ? 3
    5960             :                      : 12)))
    5961           0 :             return 1;
    5962             : 
    5963             :         // Before allocating new memory, there might be some previously allocated but unused memory.
    5964             :         // Let's free that memory first.
    5965          27 :         if (hMiraMonLayer->MMPolygon.MMArc.MMAdmDB.pMMBDXP)
    5966           0 :             MM_ReleaseDBFHeader(
    5967             :                 &hMiraMonLayer->MMPolygon.MMArc.MMAdmDB.pMMBDXP);
    5968             : 
    5969          27 :         pBD_XP_Aux = hMiraMonLayer->MMPolygon.MMArc.MMAdmDB.pMMBDXP =
    5970          27 :             MM_CreateDBFHeader(5, hMiraMonLayer->nCharSet);
    5971             : 
    5972          27 :         if (!pBD_XP_Aux)
    5973           0 :             return 1;
    5974             : 
    5975          27 :         if (0 == MM_DefineFirstArcFieldsDB_XP(
    5976             :                      pBD_XP_Aux,
    5977          27 :                      hMiraMonLayer->nSRSType == MM_SRS_LAYER_IS_PROJECTED_TYPE
    5978             :                          ? 3
    5979             :                          : 9))
    5980           0 :             return 1;
    5981             : 
    5982             :         // Before allocating new memory, there might be some previously allocated but unused memory.
    5983             :         // Let's free that memory first.
    5984          27 :         if (hMiraMonLayer->MMPolygon.MMArc.MMNode.MMAdmDB.pMMBDXP)
    5985           0 :             MM_ReleaseDBFHeader(
    5986             :                 &hMiraMonLayer->MMPolygon.MMArc.MMNode.MMAdmDB.pMMBDXP);
    5987             : 
    5988          27 :         pBD_XP_Aux = hMiraMonLayer->MMPolygon.MMArc.MMNode.MMAdmDB.pMMBDXP =
    5989          27 :             MM_CreateDBFHeader(3, hMiraMonLayer->nCharSet);
    5990             : 
    5991          27 :         if (!pBD_XP_Aux)
    5992           0 :             return 1;
    5993             : 
    5994          27 :         if (0 == MM_DefineFirstNodeFieldsDB_XP(pBD_XP_Aux))
    5995           0 :             return 1;
    5996             :     }
    5997          17 :     else if (hMiraMonLayer->bIsDBF)
    5998             :     {
    5999             :         // Creating only a DBF
    6000          17 :         if (hMiraMonLayer->pLayerDB)
    6001          17 :             nNFields = hMiraMonLayer->pLayerDB->nNFields;
    6002             :         else
    6003           0 :             nNFields = 0;
    6004             : 
    6005          17 :         pBD_XP = hMiraMonLayer->MMAdmDBWriting.pMMBDXP =
    6006          17 :             MM_CreateDBFHeader(nNFields, hMiraMonLayer->nCharSet);
    6007             : 
    6008          17 :         if (!pBD_XP)
    6009           0 :             return 1;
    6010             :     }
    6011             :     else
    6012           0 :         return 0;
    6013             : 
    6014             :     // After private MiraMon fields, other fields are added.
    6015             :     // If names are no compatible, some changes are done.
    6016         109 :     if (hMiraMonLayer->pLayerDB)
    6017             :     {
    6018         684 :         for (nIFieldLayer = 0; nIField < nNFields; nIField++, nIFieldLayer++)
    6019             :         {
    6020         576 :             MM_InitializeField(&MMField);
    6021         576 :             CPLStrlcpy(
    6022             :                 MMField.FieldName,
    6023         576 :                 hMiraMonLayer->pLayerDB->pFields[nIFieldLayer].pszFieldName,
    6024             :                 MM_MAX_LON_FIELD_NAME_DBF);
    6025             : 
    6026         576 :             CPLStrlcpy(MMField.FieldDescription[0],
    6027         576 :                        hMiraMonLayer->pLayerDB->pFields[nIFieldLayer]
    6028         576 :                            .pszFieldDescription,
    6029             :                        MM_MAX_BYTES_FIELD_DESC);
    6030             : 
    6031         576 :             MMField.BytesPerField =
    6032         576 :                 hMiraMonLayer->pLayerDB->pFields[nIFieldLayer].nFieldSize;
    6033         576 :             switch (hMiraMonLayer->pLayerDB->pFields[nIFieldLayer].eFieldType)
    6034             :             {
    6035         283 :                 case MM_Numeric:
    6036         283 :                     MMField.FieldType = 'N';
    6037         283 :                     if (hMiraMonLayer->pLayerDB->pFields[nIFieldLayer]
    6038         283 :                             .bIs64BitInteger)
    6039          79 :                         MMField.Is64 = 1;
    6040         283 :                     if (MMField.BytesPerField == 0)
    6041           0 :                         MMField.BytesPerField = MM_MAX_AMPLADA_CAMP_N_DBF;
    6042         283 :                     break;
    6043         192 :                 case MM_Character:
    6044         192 :                     MMField.FieldType = 'C';
    6045         192 :                     if (MMField.BytesPerField == 0)
    6046           0 :                         MMField.BytesPerField = MM_MAX_AMPLADA_CAMP_C_DBF;
    6047         192 :                     break;
    6048          68 :                 case MM_Data:
    6049          68 :                     MMField.FieldType = 'D';
    6050          68 :                     if (MMField.BytesPerField == 0)
    6051           0 :                         MMField.BytesPerField = MM_MAX_AMPLADA_CAMP_D_DBF;
    6052          68 :                     break;
    6053          33 :                 case MM_Logic:
    6054          33 :                     MMField.FieldType = 'L';
    6055          33 :                     if (MMField.BytesPerField == 0)
    6056           0 :                         MMField.BytesPerField = 1;
    6057          33 :                     break;
    6058           0 :                 default:
    6059           0 :                     MMField.FieldType = 'C';
    6060           0 :                     if (MMField.BytesPerField == 0)
    6061           0 :                         MMField.BytesPerField = MM_MAX_AMPLADA_CAMP_C_DBF;
    6062             :             };
    6063             : 
    6064         576 :             MMField.DecimalsIfFloat =
    6065         576 :                 (MM_BYTE)hMiraMonLayer->pLayerDB->pFields[nIFieldLayer]
    6066         576 :                     .nNumberOfDecimals;
    6067             : 
    6068         576 :             MM_DuplicateFieldDBXP(pBD_XP->pField + nIField, &MMField);
    6069         576 :             MM_ModifyFieldNameAndDescriptorIfPresentBD_XP(
    6070         576 :                 pBD_XP->pField + nIField, pBD_XP, FALSE, 0);
    6071         576 :             if (pBD_XP->pField[nIField].FieldType == 'F')
    6072           0 :                 pBD_XP->pField[nIField].FieldType = 'N';
    6073             :         }
    6074             :     }
    6075             : 
    6076         109 :     if (hMiraMonLayer->bIsPoint)
    6077             :     {
    6078          34 :         if (MMInitMMDB(hMiraMonLayer, &hMiraMonLayer->MMPoint.MMAdmDB))
    6079           0 :             return 1;
    6080             :     }
    6081          75 :     else if (hMiraMonLayer->bIsArc && !hMiraMonLayer->bIsPolygon)
    6082             :     {
    6083          31 :         if (MMInitMMDB(hMiraMonLayer, &hMiraMonLayer->MMArc.MMAdmDB))
    6084           0 :             return 1;
    6085             : 
    6086          31 :         if (MMInitMMDB(hMiraMonLayer, &hMiraMonLayer->MMArc.MMNode.MMAdmDB))
    6087           0 :             return 1;
    6088             :     }
    6089          44 :     else if (hMiraMonLayer->bIsPolygon)
    6090             :     {
    6091          27 :         if (MMInitMMDB(hMiraMonLayer, &hMiraMonLayer->MMPolygon.MMAdmDB))
    6092           0 :             return 1;
    6093             : 
    6094          27 :         if (MMInitMMDB(hMiraMonLayer, &hMiraMonLayer->MMPolygon.MMArc.MMAdmDB))
    6095           0 :             return 1;
    6096             : 
    6097          27 :         if (MMInitMMDB(hMiraMonLayer,
    6098             :                        &hMiraMonLayer->MMPolygon.MMArc.MMNode.MMAdmDB))
    6099           0 :             return 1;
    6100             :     }
    6101          17 :     else if (hMiraMonLayer->bIsDBF)
    6102             :     {
    6103          17 :         if (MMInitMMDB(hMiraMonLayer, &hMiraMonLayer->MMAdmDBWriting))
    6104           0 :             return 1;
    6105             :     }
    6106         109 :     return 0;
    6107             : }
    6108             : 
    6109             : // Checks and fits the width of a specific field in a MiraMon database
    6110             : // associated with a vector layer. It examines the length of the provided
    6111             : // value and resizes the field width, if necessary, to accommodate the new
    6112             : // value. If the new width exceeds the current width of the field,
    6113             : // it updates the database structure, including the field width and
    6114             : // the size of the record. Additionally, it reallocates memory if needed
    6115             : // for the record handling buffer.
    6116             : 
    6117             : static int
    6118        2977 : MMTestAndFixValueToRecordDBXP(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6119             :                               struct MMAdmDatabase *pMMAdmDB,
    6120             :                               MM_EXT_DBF_N_FIELDS nIField, char *szValue)
    6121             : {
    6122             :     struct MM_FIELD *camp;
    6123             :     MM_BYTES_PER_FIELD_TYPE_DBF nNewWidth;
    6124             : 
    6125        2977 :     if (!hMiraMonLayer || !pMMAdmDB || !pMMAdmDB->pMMBDXP ||
    6126        2977 :         !pMMAdmDB->pMMBDXP->pField || !pMMAdmDB->pMMBDXP->pfDataBase)
    6127           0 :         return 1;
    6128             : 
    6129        2977 :     camp = pMMAdmDB->pMMBDXP->pField + nIField;
    6130             : 
    6131        2977 :     if (!szValue)
    6132         282 :         return 0;
    6133             : 
    6134        2695 :     nNewWidth = (MM_BYTES_PER_FIELD_TYPE_DBF)strlen(szValue);
    6135        2695 :     if (MMResizeStringToOperateIfNeeded(hMiraMonLayer, nNewWidth + 1))
    6136           0 :         return 1;
    6137             : 
    6138        2695 :     if (nNewWidth > camp->BytesPerField)
    6139             :     {
    6140         117 :         if (MM_WriteNRecordsMMBD_XPFile(pMMAdmDB->pMMBDXP))
    6141           0 :             return 1;
    6142             : 
    6143             :         // Flushing all to be flushed
    6144         117 :         pMMAdmDB->FlushRecList.SizeOfBlockToBeSaved = 0;
    6145         117 :         if (MMAppendBlockToBuffer(&pMMAdmDB->FlushRecList))
    6146           0 :             return 1;
    6147             : 
    6148         117 :         if (MM_ChangeDBFWidthField(
    6149             :                 pMMAdmDB->pMMBDXP, nIField, nNewWidth,
    6150         117 :                 pMMAdmDB->pMMBDXP->pField[nIField].DecimalsIfFloat))
    6151           0 :             return 1;
    6152             : 
    6153             :         // The record on course also has to change its size.
    6154         117 :         if ((GUInt64)pMMAdmDB->pMMBDXP->BytesPerRecord + 1 >=
    6155         117 :             pMMAdmDB->nNumRecordOnCourse)
    6156             :         {
    6157             :             void *pTmp;
    6158         117 :             if (nullptr == (pTmp = VSIRealloc(
    6159         117 :                                 pMMAdmDB->szRecordOnCourse,
    6160         117 :                                 (size_t)pMMAdmDB->pMMBDXP->BytesPerRecord + 1)))
    6161             :             {
    6162           0 :                 CPLError(CE_Failure, CPLE_OutOfMemory,
    6163             :                          "Memory error in MiraMon "
    6164             :                          "driver (MMTestAndFixValueToRecordDBXP())");
    6165           0 :                 return 1;
    6166             :             }
    6167         117 :             pMMAdmDB->szRecordOnCourse = pTmp;
    6168             :         }
    6169             : 
    6170             :         // File has changed its size, so it has to be updated
    6171             :         // at the Flush tool
    6172         117 :         VSIFSeekL(pMMAdmDB->pMMBDXP->pfDataBase, 0, SEEK_END);
    6173         117 :         pMMAdmDB->FlushRecList.OffsetWhereToFlush =
    6174         117 :             VSIFTellL(pMMAdmDB->pMMBDXP->pfDataBase);
    6175             :     }
    6176        2695 :     return 0;
    6177             : }
    6178             : 
    6179             : static int
    6180        3460 : MMWriteValueToszStringToOperate(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6181             :                                 const struct MM_FIELD *camp, const void *valor,
    6182             :                                 MM_BOOLEAN is_64)
    6183             : {
    6184        3460 :     if (!hMiraMonLayer)
    6185           0 :         return 1;
    6186             : 
    6187        3460 :     if (!camp)
    6188           0 :         return 0;
    6189             : 
    6190        3460 :     if (MMResizeStringToOperateIfNeeded(hMiraMonLayer,
    6191        3460 :                                         camp->BytesPerField + 10))
    6192           0 :         return 1;
    6193             : 
    6194        3460 :     if (!valor)
    6195           0 :         *hMiraMonLayer->szStringToOperate = '\0';
    6196             :     else
    6197             :     {
    6198        3460 :         if (camp->FieldType == 'N')
    6199             :         {
    6200        2862 :             if (!is_64)
    6201             :             {
    6202         972 :                 snprintf(hMiraMonLayer->szStringToOperate,
    6203         972 :                          (size_t)hMiraMonLayer->nNumStringToOperate, "%*.*f",
    6204         972 :                          camp->BytesPerField, camp->DecimalsIfFloat,
    6205             :                          *(const double *)valor);
    6206             :             }
    6207             :             else
    6208             :             {
    6209        1890 :                 snprintf(hMiraMonLayer->szStringToOperate,
    6210        1890 :                          (size_t)hMiraMonLayer->nNumStringToOperate, "%*lld",
    6211             :                          camp->BytesPerField, *(const GInt64 *)valor);
    6212             :             }
    6213             :         }
    6214             :         else
    6215             :         {
    6216         598 :             snprintf(hMiraMonLayer->szStringToOperate,
    6217         598 :                      (size_t)hMiraMonLayer->nNumStringToOperate, "%-*s",
    6218             :                      camp->BytesPerField, (const char *)valor);
    6219             :         }
    6220             :     }
    6221             : 
    6222        3460 :     return 0;
    6223             : }
    6224             : 
    6225         559 : int MMWritePreformatedNumberValueToRecordDBXP(
    6226             :     struct MiraMonVectLayerInfo *hMiraMonLayer, char *registre,
    6227             :     const struct MM_FIELD *camp, const char *valor)
    6228             : {
    6229         559 :     if (!hMiraMonLayer)
    6230           0 :         return 1;
    6231             : 
    6232         559 :     if (!camp)
    6233           0 :         return 0;
    6234             : 
    6235         559 :     if (MMResizeStringToOperateIfNeeded(hMiraMonLayer,
    6236         559 :                                         camp->BytesPerField + 10))
    6237           0 :         return 1;
    6238             : 
    6239         559 :     if (!valor)
    6240           0 :         memset(hMiraMonLayer->szStringToOperate, 0, camp->BytesPerField);
    6241             :     else
    6242             :     {
    6243         559 :         snprintf(hMiraMonLayer->szStringToOperate,
    6244         559 :                  (size_t)hMiraMonLayer->nNumStringToOperate, "%*s",
    6245             :                  camp->BytesPerField, valor);
    6246             :     }
    6247             : 
    6248         559 :     memcpy(registre + camp->AccumulatedBytes, hMiraMonLayer->szStringToOperate,
    6249         559 :            camp->BytesPerField);
    6250         559 :     return 0;
    6251             : }
    6252             : 
    6253        2135 : int MMWriteValueToRecordDBXP(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6254             :                              char *registre, const struct MM_FIELD *camp,
    6255             :                              const void *valor, MM_BOOLEAN is_64)
    6256             : {
    6257        2135 :     if (!hMiraMonLayer)
    6258           0 :         return 1;
    6259             : 
    6260        2135 :     if (!camp)
    6261           0 :         return 0;
    6262             : 
    6263        2135 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, camp, valor, is_64))
    6264           0 :         return 1;
    6265             : 
    6266        2135 :     memcpy(registre + camp->AccumulatedBytes, hMiraMonLayer->szStringToOperate,
    6267        2135 :            camp->BytesPerField);
    6268        2135 :     return 0;
    6269             : }
    6270             : 
    6271         213 : static int MMAddFeatureRecordToMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6272             :                                     struct MiraMonFeature *hMMFeature,
    6273             :                                     struct MMAdmDatabase *pMMAdmDB,
    6274             :                                     char *pszRecordOnCourse,
    6275             :                                     struct MM_FLUSH_INFO *pFlushRecList,
    6276             :                                     MM_EXT_DBF_N_RECORDS *nNumRecords,
    6277             :                                     MM_EXT_DBF_N_FIELDS nNumPrivateMMField)
    6278             : {
    6279             :     MM_EXT_DBF_N_MULTIPLE_RECORDS nIRecord;
    6280             :     MM_EXT_DBF_N_FIELDS nIField;
    6281         213 :     struct MM_DATA_BASE_XP *pBD_XP = nullptr;
    6282             : 
    6283         213 :     if (!hMiraMonLayer)
    6284           0 :         return 1;
    6285             : 
    6286         213 :     if (!hMMFeature)
    6287           0 :         return 1;
    6288             : 
    6289         213 :     pBD_XP = pMMAdmDB->pMMBDXP;
    6290         453 :     for (nIRecord = 0; nIRecord < hMMFeature->nNumMRecords; nIRecord++)
    6291             :     {
    6292        1892 :         for (nIField = 0; nIField < hMMFeature->pRecords[nIRecord].nNumField;
    6293        1652 :              nIField++)
    6294             :         {
    6295             :             // A field with no valid value is written as blank
    6296        1652 :             if (!hMMFeature->pRecords[nIRecord].pField[nIField].bIsValid)
    6297             :             {
    6298         283 :                 memset(
    6299         283 :                     pszRecordOnCourse +
    6300         283 :                         pBD_XP->pField[nIField + nNumPrivateMMField]
    6301         283 :                             .AccumulatedBytes,
    6302             :                     ' ',
    6303         283 :                     pBD_XP->pField[nIField + nNumPrivateMMField].BytesPerField);
    6304             : 
    6305         283 :                 continue;
    6306             :             }
    6307        1369 :             if (pBD_XP->pField[nIField + nNumPrivateMMField].FieldType == 'C' ||
    6308         983 :                 pBD_XP->pField[nIField + nNumPrivateMMField].FieldType == 'L' ||
    6309         880 :                 pBD_XP->pField[nIField + nNumPrivateMMField].FieldType == 'D')
    6310             :             {
    6311         598 :                 if (MMWriteValueToRecordDBXP(hMiraMonLayer, pszRecordOnCourse,
    6312         598 :                                              pBD_XP->pField + nIField +
    6313             :                                                  nNumPrivateMMField,
    6314         598 :                                              hMMFeature->pRecords[nIRecord]
    6315         598 :                                                  .pField[nIField]
    6316         598 :                                                  .pDinValue,
    6317             :                                              FALSE))
    6318           0 :                     return 1;
    6319             :             }
    6320         771 :             else if (pBD_XP->pField[nIField + nNumPrivateMMField].FieldType ==
    6321         771 :                          'N' &&
    6322         771 :                      !pBD_XP->pField[nIField + nNumPrivateMMField].Is64)
    6323             :             {
    6324         559 :                 if (MMWritePreformatedNumberValueToRecordDBXP(
    6325             :                         hMiraMonLayer, pszRecordOnCourse,
    6326         559 :                         pBD_XP->pField + nIField + nNumPrivateMMField,
    6327         559 :                         hMMFeature->pRecords[nIRecord]
    6328         559 :                             .pField[nIField]
    6329         559 :                             .pDinValue))
    6330           0 :                     return 1;
    6331             :             }
    6332         212 :             else if (pBD_XP->pField[nIField + nNumPrivateMMField].FieldType ==
    6333             :                      'N')
    6334             :             {
    6335         212 :                 if (pBD_XP->pField[nIField + nNumPrivateMMField].Is64)
    6336             :                 {
    6337         212 :                     if (MMWriteValueToRecordDBXP(
    6338             :                             hMiraMonLayer, pszRecordOnCourse,
    6339         212 :                             pBD_XP->pField + nIField + nNumPrivateMMField,
    6340         212 :                             &hMMFeature->pRecords[nIRecord]
    6341         212 :                                  .pField[nIField]
    6342             :                                  .iValue,
    6343             :                             TRUE))
    6344           0 :                         return 1;
    6345             :                 }
    6346             :             }
    6347             :         }
    6348             : 
    6349         240 :         if (MMAppendBlockToBuffer(pFlushRecList))
    6350           0 :             return 1;
    6351             : 
    6352         240 :         (*nNumRecords)++;
    6353             :     }
    6354         213 :     return 0;
    6355             : }
    6356             : 
    6357             : // Adds feature records to a MiraMon database associated with a vector layer.
    6358        1652 : static int MMDetectAndFixDBFWidthChange(
    6359             :     struct MiraMonVectLayerInfo *hMiraMonLayer,
    6360             :     struct MiraMonFeature *hMMFeature, struct MMAdmDatabase *pMMAdmDB,
    6361             :     MM_EXT_DBF_N_FIELDS nNumPrivateMMField,
    6362             :     MM_EXT_DBF_N_MULTIPLE_RECORDS nIRecord, MM_EXT_DBF_N_FIELDS nIField)
    6363             : {
    6364        1652 :     if (!hMiraMonLayer)
    6365           0 :         return 1;
    6366             : 
    6367        1652 :     if (!hMMFeature)
    6368           0 :         return 1;
    6369             : 
    6370        1652 :     if (nIRecord >= hMMFeature->nNumMRecords)
    6371           0 :         return 1;
    6372             : 
    6373        1652 :     if (nIField >= hMMFeature->pRecords[nIRecord].nNumField)
    6374           0 :         return 1;
    6375             : 
    6376        1652 :     if (MMTestAndFixValueToRecordDBXP(
    6377             :             hMiraMonLayer, pMMAdmDB, nIField + nNumPrivateMMField,
    6378        1652 :             hMMFeature->pRecords[nIRecord].pField[nIField].pDinValue))
    6379           0 :         return 1;
    6380             : 
    6381             :     // We analyze next fields
    6382        1652 :     if (nIField == hMMFeature->pRecords[nIRecord].nNumField - 1)
    6383             :     {
    6384         239 :         if (nIRecord + 1 < hMMFeature->nNumMRecords)
    6385             :         {
    6386          27 :             if (MMDetectAndFixDBFWidthChange(hMiraMonLayer, hMMFeature,
    6387             :                                              pMMAdmDB, nNumPrivateMMField,
    6388             :                                              nIRecord + 1, 0))
    6389           0 :                 return 1;
    6390             :         }
    6391             :         else
    6392         212 :             return 0;
    6393             :     }
    6394             :     else
    6395             :     {
    6396        1413 :         if (nIField + 1 < hMMFeature->pRecords[nIRecord].nNumField)
    6397             :         {
    6398        1413 :             if (MMDetectAndFixDBFWidthChange(hMiraMonLayer, hMMFeature,
    6399             :                                              pMMAdmDB, nNumPrivateMMField,
    6400             :                                              nIRecord, nIField + 1))
    6401           0 :                 return 1;
    6402             :         }
    6403             :         else
    6404           0 :             return 0;
    6405             :     }
    6406        1440 :     return 0;
    6407             : }  // End of MMDetectAndFixDBFWidthChange()
    6408             : 
    6409             : // Adds a DBF record to a MiraMon table associated with a vector layer.
    6410             : // It sets up flush settings for writing to the table and initializes
    6411             : // variables needed for the process. Then, it checks and fixes the width
    6412             : // change if necessary.
    6413          34 : int MMAddDBFRecordToMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6414             :                          struct MiraMonFeature *hMMFeature)
    6415             : {
    6416          34 :     struct MM_DATA_BASE_XP *pBD_XP = nullptr;
    6417          34 :     MM_EXT_DBF_N_FIELDS nNumPrivateMMField = 0;
    6418             :     struct MM_FLUSH_INFO *pFlushRecList;
    6419             : 
    6420          34 :     if (!hMiraMonLayer)
    6421           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6422             : 
    6423          34 :     pBD_XP = hMiraMonLayer->MMAdmDBWriting.pMMBDXP;
    6424             : 
    6425             :     // Test length
    6426          34 :     if (hMMFeature && hMMFeature->nNumMRecords &&
    6427          34 :         hMMFeature->pRecords[0].nNumField)
    6428             :     {
    6429          34 :         if (MMDetectAndFixDBFWidthChange(hMiraMonLayer, hMMFeature,
    6430             :                                          &hMiraMonLayer->MMAdmDBWriting,
    6431             :                                          nNumPrivateMMField, 0, 0))
    6432           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6433             :     }
    6434             : 
    6435             :     // Adding record to the MiraMon table (extended DBF)
    6436             :     // Flush settings
    6437          34 :     pFlushRecList = &hMiraMonLayer->MMAdmDBWriting.FlushRecList;
    6438          34 :     pFlushRecList->pBlockWhereToSaveOrRead =
    6439          34 :         (void *)hMiraMonLayer->MMAdmDBWriting.pRecList;
    6440             : 
    6441          34 :     pFlushRecList->pBlockToBeSaved =
    6442          34 :         (void *)hMiraMonLayer->MMAdmDBWriting.szRecordOnCourse;
    6443          34 :     pFlushRecList->SizeOfBlockToBeSaved = pBD_XP->BytesPerRecord;
    6444             : 
    6445          34 :     if (MMAddFeatureRecordToMMDB(
    6446             :             hMiraMonLayer, hMMFeature, &hMiraMonLayer->MMAdmDBWriting,
    6447             :             hMiraMonLayer->MMAdmDBWriting.szRecordOnCourse, pFlushRecList,
    6448          34 :             &hMiraMonLayer->MMAdmDBWriting.pMMBDXP->nRecords,
    6449             :             nNumPrivateMMField))
    6450           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6451             : 
    6452             :     // In this case, the number of features is also updated
    6453          34 :     hMiraMonLayer->TopHeader.nElemCount =
    6454          34 :         hMiraMonLayer->MMAdmDBWriting.pMMBDXP->nRecords;
    6455             : 
    6456          34 :     return MM_CONTINUE_WRITING_FEATURES;
    6457             : }
    6458             : 
    6459             : // Adds a point record to a MiraMon table associated with a vector layer.
    6460          89 : int MMAddPointRecordToMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6461             :                            struct MiraMonFeature *hMMFeature,
    6462             :                            MM_INTERNAL_FID nElemCount)
    6463             : {
    6464          89 :     struct MM_DATA_BASE_XP *pBD_XP = nullptr;
    6465          89 :     MM_EXT_DBF_N_FIELDS nNumPrivateMMField = MM_PRIVATE_POINT_DB_FIELDS;
    6466             :     struct MM_FLUSH_INFO *pFlushRecList;
    6467             : 
    6468          89 :     if (!hMiraMonLayer)
    6469           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6470             : 
    6471          89 :     if (!hMMFeature)
    6472           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6473             : 
    6474             :     // In V1.1 only _UI32_MAX records number is allowed
    6475          89 :     if (MMCheckVersionForFID(hMiraMonLayer,
    6476          89 :                              hMiraMonLayer->MMPoint.MMAdmDB.pMMBDXP->nRecords +
    6477          89 :                                  hMMFeature->nNumMRecords))
    6478             :     {
    6479           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    6480             :                  "Error in MMCheckVersionForFID() (6)");
    6481           0 :         return MM_STOP_WRITING_FEATURES;
    6482             :     }
    6483             : 
    6484          89 :     pBD_XP = hMiraMonLayer->MMPoint.MMAdmDB.pMMBDXP;
    6485             : 
    6486             :     // Test length
    6487             :     // Private fields
    6488             :     // ID_GRAFIC
    6489          89 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField,
    6490             :                                         &nElemCount, TRUE))
    6491           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6492          89 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer,
    6493             :                                       &hMiraMonLayer->MMPoint.MMAdmDB, 0,
    6494             :                                       hMiraMonLayer->szStringToOperate))
    6495           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6496             : 
    6497             :     // GDAL fields
    6498          89 :     if (hMMFeature->nNumMRecords && hMMFeature->pRecords[0].nNumField)
    6499             :     {
    6500          89 :         if (MMDetectAndFixDBFWidthChange(hMiraMonLayer, hMMFeature,
    6501             :                                          &hMiraMonLayer->MMPoint.MMAdmDB,
    6502             :                                          nNumPrivateMMField, 0, 0))
    6503           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6504             :     }
    6505             : 
    6506             :     // Now length is sure, write
    6507          89 :     memset(hMiraMonLayer->MMPoint.MMAdmDB.szRecordOnCourse, 0,
    6508          89 :            pBD_XP->BytesPerRecord);
    6509          89 :     MMWriteValueToRecordDBXP(hMiraMonLayer,
    6510             :                              hMiraMonLayer->MMPoint.MMAdmDB.szRecordOnCourse,
    6511          89 :                              pBD_XP->pField, &nElemCount, TRUE);
    6512             : 
    6513             :     // Adding record to the MiraMon table (extended DBF)
    6514             :     // Flush settings
    6515          89 :     pFlushRecList = &hMiraMonLayer->MMPoint.MMAdmDB.FlushRecList;
    6516          89 :     pFlushRecList->pBlockWhereToSaveOrRead =
    6517          89 :         (void *)hMiraMonLayer->MMPoint.MMAdmDB.pRecList;
    6518             : 
    6519          89 :     pFlushRecList->pBlockToBeSaved =
    6520          89 :         (void *)hMiraMonLayer->MMPoint.MMAdmDB.szRecordOnCourse;
    6521          89 :     pFlushRecList->SizeOfBlockToBeSaved = pBD_XP->BytesPerRecord;
    6522             : 
    6523          89 :     if (MMAddFeatureRecordToMMDB(
    6524             :             hMiraMonLayer, hMMFeature, &hMiraMonLayer->MMPoint.MMAdmDB,
    6525             :             hMiraMonLayer->MMPoint.MMAdmDB.szRecordOnCourse, pFlushRecList,
    6526          89 :             &hMiraMonLayer->MMPoint.MMAdmDB.pMMBDXP->nRecords,
    6527             :             nNumPrivateMMField))
    6528           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6529          89 :     return MM_CONTINUE_WRITING_FEATURES;
    6530             : }
    6531             : 
    6532             : // Adds a stringline record to a MiraMon table associated with a vector layer.
    6533         102 : int MMAddArcRecordToMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6534             :                          struct MiraMonFeature *hMMFeature,
    6535             :                          MM_INTERNAL_FID nElemCount, struct MM_AH *pArcHeader)
    6536             : {
    6537         102 :     struct MM_DATA_BASE_XP *pBD_XP = nullptr;
    6538             :     struct MiraMonArcLayer *pMMArcLayer;
    6539         102 :     MM_EXT_DBF_N_FIELDS nNumPrivateMMField = MM_PRIVATE_ARC_DB_FIELDS;
    6540             :     struct MM_FLUSH_INFO *pFlushRecList;
    6541             : 
    6542         102 :     if (!hMiraMonLayer)
    6543           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6544             : 
    6545         102 :     if (hMiraMonLayer->bIsPolygon)
    6546          53 :         pMMArcLayer = &hMiraMonLayer->MMPolygon.MMArc;
    6547             :     else
    6548          49 :         pMMArcLayer = &hMiraMonLayer->MMArc;
    6549             : 
    6550             :     // In V1.1 only _UI32_MAX records number is allowed
    6551         102 :     if (hMiraMonLayer->bIsPolygon)
    6552             :     {
    6553          53 :         if (MMCheckVersionForFID(hMiraMonLayer,
    6554          53 :                                  pMMArcLayer->MMAdmDB.pMMBDXP->nRecords + 1))
    6555             :         {
    6556           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    6557             :                      "Error in MMCheckVersionForFID() (7)");
    6558           0 :             return MM_STOP_WRITING_FEATURES;
    6559             :         }
    6560             :     }
    6561             :     else
    6562             :     {
    6563          49 :         if (MMCheckVersionForFID(hMiraMonLayer,
    6564          49 :                                  pMMArcLayer->MMAdmDB.pMMBDXP->nRecords +
    6565          49 :                                      hMMFeature->nNumMRecords))
    6566             :         {
    6567           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    6568             :                      "Error in MMCheckVersionForFID() (8)");
    6569           0 :             return MM_STOP_WRITING_FEATURES;
    6570             :         }
    6571             :     }
    6572             : 
    6573         102 :     pBD_XP = pMMArcLayer->MMAdmDB.pMMBDXP;
    6574             : 
    6575             :     // Test length
    6576             :     // Private fields
    6577             :     // ID_GRAFIC
    6578         102 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField,
    6579             :                                         &nElemCount, TRUE))
    6580           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6581         102 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMArcLayer->MMAdmDB, 0,
    6582             :                                       hMiraMonLayer->szStringToOperate))
    6583           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6584             : 
    6585             :     // N_VERTEXS
    6586         102 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 1,
    6587         102 :                                         &pArcHeader->nElemCount, TRUE))
    6588           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6589         102 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMArcLayer->MMAdmDB, 1,
    6590             :                                       hMiraMonLayer->szStringToOperate))
    6591           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6592             : 
    6593             :     // LENGTH
    6594         102 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 2,
    6595         102 :                                         &pArcHeader->dfLength, FALSE))
    6596           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6597         102 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMArcLayer->MMAdmDB, 2,
    6598             :                                       hMiraMonLayer->szStringToOperate))
    6599           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6600             : 
    6601             :     // NODE_INI
    6602         102 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 3,
    6603         102 :                                         &pArcHeader->nFirstIdNode, TRUE))
    6604           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6605         102 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMArcLayer->MMAdmDB, 3,
    6606             :                                       hMiraMonLayer->szStringToOperate))
    6607           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6608             : 
    6609             :     // NODE_FI
    6610         102 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 4,
    6611         102 :                                         &pArcHeader->nLastIdNode, TRUE))
    6612           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6613         102 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMArcLayer->MMAdmDB, 4,
    6614             :                                       hMiraMonLayer->szStringToOperate))
    6615           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6616             : 
    6617             :     // GDAL fields
    6618         102 :     if (!hMiraMonLayer->bIsPolygon)
    6619             :     {
    6620          49 :         if (hMMFeature->nNumMRecords && hMMFeature->pRecords[0].nNumField)
    6621             :         {
    6622          48 :             if (MMDetectAndFixDBFWidthChange(hMiraMonLayer, hMMFeature,
    6623             :                                              &pMMArcLayer->MMAdmDB,
    6624             :                                              nNumPrivateMMField, 0, 0))
    6625           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    6626             :         }
    6627             :     }
    6628             : 
    6629             :     // Now length is sure, write
    6630         102 :     memset(pMMArcLayer->MMAdmDB.szRecordOnCourse, 0, pBD_XP->BytesPerRecord);
    6631         102 :     MMWriteValueToRecordDBXP(hMiraMonLayer,
    6632             :                              pMMArcLayer->MMAdmDB.szRecordOnCourse,
    6633         102 :                              pBD_XP->pField, &nElemCount, TRUE);
    6634             : 
    6635         102 :     MMWriteValueToRecordDBXP(hMiraMonLayer,
    6636             :                              pMMArcLayer->MMAdmDB.szRecordOnCourse,
    6637         102 :                              pBD_XP->pField + 1, &pArcHeader->nElemCount, TRUE);
    6638             : 
    6639         102 :     MMWriteValueToRecordDBXP(hMiraMonLayer,
    6640             :                              pMMArcLayer->MMAdmDB.szRecordOnCourse,
    6641         102 :                              pBD_XP->pField + 2, &pArcHeader->dfLength, FALSE);
    6642             : 
    6643         102 :     MMWriteValueToRecordDBXP(
    6644             :         hMiraMonLayer, pMMArcLayer->MMAdmDB.szRecordOnCourse,
    6645         102 :         pBD_XP->pField + 3, &pArcHeader->nFirstIdNode, TRUE);
    6646             : 
    6647         102 :     MMWriteValueToRecordDBXP(
    6648             :         hMiraMonLayer, pMMArcLayer->MMAdmDB.szRecordOnCourse,
    6649         102 :         pBD_XP->pField + 4, &pArcHeader->nLastIdNode, TRUE);
    6650             : 
    6651             :     // Adding record to the MiraMon table (extended DBF)
    6652             :     // Flush settings
    6653         102 :     pFlushRecList = &pMMArcLayer->MMAdmDB.FlushRecList;
    6654         102 :     pFlushRecList->pBlockWhereToSaveOrRead =
    6655         102 :         (void *)pMMArcLayer->MMAdmDB.pRecList;
    6656             : 
    6657         102 :     pFlushRecList->SizeOfBlockToBeSaved = pBD_XP->BytesPerRecord;
    6658         102 :     pFlushRecList->pBlockToBeSaved =
    6659         102 :         (void *)pMMArcLayer->MMAdmDB.szRecordOnCourse;
    6660             : 
    6661         102 :     if (hMiraMonLayer->bIsPolygon)
    6662             :     {
    6663          53 :         if (MMAppendBlockToBuffer(pFlushRecList))
    6664           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6665          53 :         pMMArcLayer->MMAdmDB.pMMBDXP->nRecords++;
    6666          53 :         return MM_CONTINUE_WRITING_FEATURES;
    6667             :     }
    6668             : 
    6669          49 :     pFlushRecList->SizeOfBlockToBeSaved = pBD_XP->BytesPerRecord;
    6670          49 :     if (MMAddFeatureRecordToMMDB(
    6671             :             hMiraMonLayer, hMMFeature, &pMMArcLayer->MMAdmDB,
    6672             :             pMMArcLayer->MMAdmDB.szRecordOnCourse, pFlushRecList,
    6673          49 :             &pMMArcLayer->MMAdmDB.pMMBDXP->nRecords, nNumPrivateMMField))
    6674           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6675          49 :     return MM_CONTINUE_WRITING_FEATURES;
    6676             : }
    6677             : 
    6678             : // Adds a node record to a MiraMon table associated with a vector layer.
    6679         151 : int MMAddNodeRecordToMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6680             :                           MM_INTERNAL_FID nElemCount, struct MM_NH *pNodeHeader)
    6681             : {
    6682         151 :     struct MM_DATA_BASE_XP *pBD_XP = nullptr;
    6683             :     struct MiraMonNodeLayer *pMMNodeLayer;
    6684             :     double nDoubleValue;
    6685             : 
    6686         151 :     if (!hMiraMonLayer)
    6687           0 :         return 1;
    6688             : 
    6689         151 :     if (hMiraMonLayer->bIsPolygon)
    6690          53 :         pMMNodeLayer = &hMiraMonLayer->MMPolygon.MMArc.MMNode;
    6691             :     else
    6692          98 :         pMMNodeLayer = &hMiraMonLayer->MMArc.MMNode;
    6693             : 
    6694         151 :     if (!pMMNodeLayer)
    6695             :     {
    6696           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Error in pMMNodeLayer() (1)");
    6697           0 :         return MM_STOP_WRITING_FEATURES;
    6698             :     }
    6699             : 
    6700             :     // In V1.1 only _UI32_MAX records number is allowed
    6701         151 :     if (MMCheckVersionForFID(hMiraMonLayer,
    6702         151 :                              pMMNodeLayer->MMAdmDB.pMMBDXP->nRecords + 1))
    6703             :     {
    6704           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    6705             :                  "Error in MMCheckVersionForFID() (9)");
    6706           0 :         return MM_STOP_WRITING_FEATURES;
    6707             :     }
    6708             : 
    6709             :     // Test length
    6710             :     // Private fields
    6711             :     // ID_GRAFIC
    6712         151 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer,
    6713         151 :                                         pMMNodeLayer->MMAdmDB.pMMBDXP->pField,
    6714             :                                         &nElemCount, TRUE))
    6715           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6716         151 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMNodeLayer->MMAdmDB, 0,
    6717             :                                       hMiraMonLayer->szStringToOperate))
    6718           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6719             : 
    6720             :     // ARCS_A_NOD
    6721         151 :     nDoubleValue = pNodeHeader->nArcsCount;
    6722         151 :     if (MMWriteValueToszStringToOperate(
    6723         151 :             hMiraMonLayer, pMMNodeLayer->MMAdmDB.pMMBDXP->pField + 1,
    6724             :             &nDoubleValue, FALSE))
    6725           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6726         151 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMNodeLayer->MMAdmDB, 1,
    6727             :                                       hMiraMonLayer->szStringToOperate))
    6728           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6729             : 
    6730             :     // TIPUS_NODE
    6731         151 :     nDoubleValue = pNodeHeader->cNodeType;
    6732         151 :     if (MMWriteValueToszStringToOperate(
    6733         151 :             hMiraMonLayer, pMMNodeLayer->MMAdmDB.pMMBDXP->pField + 2,
    6734             :             &nDoubleValue, FALSE))
    6735           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6736         151 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMNodeLayer->MMAdmDB, 2,
    6737             :                                       hMiraMonLayer->szStringToOperate))
    6738           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6739             : 
    6740             :     // Adding record to the MiraMon table (extended DBF)
    6741             :     // Flush settings
    6742         151 :     pMMNodeLayer->MMAdmDB.FlushRecList.pBlockWhereToSaveOrRead =
    6743         151 :         (void *)pMMNodeLayer->MMAdmDB.pRecList;
    6744             : 
    6745         151 :     pBD_XP = pMMNodeLayer->MMAdmDB.pMMBDXP;
    6746             : 
    6747         151 :     pMMNodeLayer->MMAdmDB.FlushRecList.SizeOfBlockToBeSaved =
    6748         151 :         pBD_XP->BytesPerRecord;
    6749         151 :     pMMNodeLayer->MMAdmDB.FlushRecList.pBlockToBeSaved =
    6750         151 :         (void *)pMMNodeLayer->MMAdmDB.szRecordOnCourse;
    6751             : 
    6752         151 :     memset(pMMNodeLayer->MMAdmDB.szRecordOnCourse, 0, pBD_XP->BytesPerRecord);
    6753         151 :     MMWriteValueToRecordDBXP(hMiraMonLayer,
    6754             :                              pMMNodeLayer->MMAdmDB.szRecordOnCourse,
    6755         151 :                              pBD_XP->pField, &nElemCount, TRUE);
    6756             : 
    6757         151 :     nDoubleValue = pNodeHeader->nArcsCount;
    6758         151 :     MMWriteValueToRecordDBXP(hMiraMonLayer,
    6759             :                              pMMNodeLayer->MMAdmDB.szRecordOnCourse,
    6760         151 :                              pBD_XP->pField + 1, &nDoubleValue, FALSE);
    6761             : 
    6762         151 :     nDoubleValue = pNodeHeader->cNodeType;
    6763         151 :     MMWriteValueToRecordDBXP(hMiraMonLayer,
    6764             :                              pMMNodeLayer->MMAdmDB.szRecordOnCourse,
    6765         151 :                              pBD_XP->pField + 2, &nDoubleValue, FALSE);
    6766             : 
    6767         151 :     if (MMAppendBlockToBuffer(&pMMNodeLayer->MMAdmDB.FlushRecList))
    6768           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6769         151 :     pMMNodeLayer->MMAdmDB.pMMBDXP->nRecords++;
    6770         151 :     return MM_CONTINUE_WRITING_FEATURES;
    6771             : }
    6772             : 
    6773             : // Adds a polygon or multipolygon record to a MiraMon table
    6774             : // associated with a vector layer.
    6775          68 : int MMAddPolygonRecordToMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6776             :                              struct MiraMonFeature *hMMFeature,
    6777             :                              MM_INTERNAL_FID nElemCount,
    6778             :                              MM_N_VERTICES_TYPE nVerticesCount,
    6779             :                              struct MM_PH *pPolHeader)
    6780             : {
    6781          68 :     struct MM_DATA_BASE_XP *pBD_XP = nullptr;
    6782          68 :     MM_EXT_DBF_N_FIELDS nNumPrivateMMField = MM_PRIVATE_POLYGON_DB_FIELDS;
    6783             :     struct MM_FLUSH_INFO *pFlushRecList;
    6784             : 
    6785          68 :     if (!hMiraMonLayer)
    6786           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6787             : 
    6788             :     // In V1.1 only _UI32_MAX records number is allowed
    6789          68 :     if (MMCheckVersionForFID(
    6790          68 :             hMiraMonLayer, hMiraMonLayer->MMPolygon.MMAdmDB.pMMBDXP->nRecords +
    6791          68 :                                (hMMFeature ? hMMFeature->nNumMRecords : 0)))
    6792           0 :         return MM_STOP_WRITING_FEATURES;
    6793             : 
    6794          68 :     pBD_XP = hMiraMonLayer->MMPolygon.MMAdmDB.pMMBDXP;
    6795             : 
    6796             :     // Test length
    6797             :     // Private fields
    6798             :     // ID_GRAFIC
    6799          68 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField,
    6800             :                                         &nElemCount, TRUE))
    6801           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6802          68 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer,
    6803             :                                       &hMiraMonLayer->MMPolygon.MMAdmDB, 0,
    6804             :                                       hMiraMonLayer->szStringToOperate))
    6805           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6806             : 
    6807             :     // The other fields are valid if pPolHeader exists (it is not
    6808             :     // the universal polygon)
    6809          68 :     if (pPolHeader)
    6810             :     {
    6811             :         // N_VERTEXS
    6812          41 :         if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 1,
    6813             :                                             &nVerticesCount, TRUE))
    6814           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6815          41 :         if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer,
    6816             :                                           &hMiraMonLayer->MMPolygon.MMAdmDB, 1,
    6817             :                                           hMiraMonLayer->szStringToOperate))
    6818           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6819             : 
    6820             :         // PERIMETER
    6821          41 :         if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 2,
    6822          41 :                                             &pPolHeader->dfPerimeter, FALSE))
    6823           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6824          41 :         if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer,
    6825             :                                           &hMiraMonLayer->MMPolygon.MMAdmDB, 2,
    6826             :                                           hMiraMonLayer->szStringToOperate))
    6827           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6828             : 
    6829             :         // AREA
    6830          41 :         if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 3,
    6831          41 :                                             &pPolHeader->dfArea, FALSE))
    6832           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6833          41 :         if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer,
    6834             :                                           &hMiraMonLayer->MMPolygon.MMAdmDB, 3,
    6835             :                                           hMiraMonLayer->szStringToOperate))
    6836           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6837             : 
    6838             :         // N_ARCS
    6839          41 :         if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 4,
    6840          41 :                                             &pPolHeader->nArcsCount, TRUE))
    6841           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6842          41 :         if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer,
    6843             :                                           &hMiraMonLayer->MMPolygon.MMAdmDB, 4,
    6844             :                                           hMiraMonLayer->szStringToOperate))
    6845           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6846             : 
    6847             :         // N_POLIG
    6848          41 :         if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 5,
    6849          41 :                                             &pPolHeader->nRingsCount, TRUE))
    6850           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6851          41 :         if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer,
    6852             :                                           &hMiraMonLayer->MMPolygon.MMAdmDB, 5,
    6853             :                                           hMiraMonLayer->szStringToOperate))
    6854           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6855             :     }
    6856             : 
    6857             :     // GDAL fields
    6858          68 :     if (hMMFeature && hMMFeature->nNumMRecords &&
    6859          41 :         hMMFeature->pRecords[0].nNumField)
    6860             :     {
    6861          41 :         if (MMDetectAndFixDBFWidthChange(hMiraMonLayer, hMMFeature,
    6862             :                                          &hMiraMonLayer->MMPolygon.MMAdmDB,
    6863             :                                          nNumPrivateMMField, 0, 0))
    6864           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6865             :     }
    6866             : 
    6867             :     // Adding record to the MiraMon table (extended DBF)
    6868             :     // Flush settings
    6869          68 :     pFlushRecList = &hMiraMonLayer->MMPolygon.MMAdmDB.FlushRecList;
    6870          68 :     pFlushRecList->pBlockWhereToSaveOrRead =
    6871          68 :         (void *)hMiraMonLayer->MMPolygon.MMAdmDB.pRecList;
    6872             : 
    6873          68 :     pFlushRecList->SizeOfBlockToBeSaved = pBD_XP->BytesPerRecord;
    6874          68 :     pFlushRecList->pBlockToBeSaved =
    6875          68 :         (void *)hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse;
    6876             : 
    6877             :     // Now length is sure, write
    6878          68 :     memset(hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse, ' ',
    6879          68 :            pBD_XP->BytesPerRecord);
    6880          68 :     if (MMWriteValueToRecordDBXP(
    6881             :             hMiraMonLayer, hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse,
    6882          68 :             pBD_XP->pField, &nElemCount, TRUE))
    6883           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6884             : 
    6885          68 :     if (!hMMFeature)
    6886             :     {
    6887          27 :         if (MMAppendBlockToBuffer(pFlushRecList))
    6888           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6889          27 :         hMiraMonLayer->MMPolygon.MMAdmDB.pMMBDXP->nRecords++;
    6890          27 :         return MM_CONTINUE_WRITING_FEATURES;
    6891             :     }
    6892             : 
    6893          41 :     if (pPolHeader)
    6894             :     {
    6895          41 :         MMWriteValueToRecordDBXP(
    6896             :             hMiraMonLayer, hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse,
    6897          41 :             pBD_XP->pField + 1, &nVerticesCount, TRUE);
    6898             : 
    6899          41 :         MMWriteValueToRecordDBXP(
    6900             :             hMiraMonLayer, hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse,
    6901          41 :             pBD_XP->pField + 2, &pPolHeader->dfPerimeter, FALSE);
    6902             : 
    6903          41 :         MMWriteValueToRecordDBXP(
    6904             :             hMiraMonLayer, hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse,
    6905          41 :             pBD_XP->pField + 3, &pPolHeader->dfArea, FALSE);
    6906             : 
    6907          41 :         MMWriteValueToRecordDBXP(
    6908             :             hMiraMonLayer, hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse,
    6909          41 :             pBD_XP->pField + 4, &pPolHeader->nArcsCount, TRUE);
    6910             : 
    6911          41 :         MMWriteValueToRecordDBXP(
    6912             :             hMiraMonLayer, hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse,
    6913          41 :             pBD_XP->pField + 5, &pPolHeader->nRingsCount, TRUE);
    6914             :     }
    6915             : 
    6916          41 :     pFlushRecList->SizeOfBlockToBeSaved = pBD_XP->BytesPerRecord;
    6917          41 :     if (MMAddFeatureRecordToMMDB(
    6918             :             hMiraMonLayer, hMMFeature, &hMiraMonLayer->MMPolygon.MMAdmDB,
    6919             :             hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse, pFlushRecList,
    6920          41 :             &hMiraMonLayer->MMPolygon.MMAdmDB.pMMBDXP->nRecords,
    6921             :             nNumPrivateMMField))
    6922           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6923          41 :     return MM_CONTINUE_WRITING_FEATURES;
    6924             : }
    6925             : 
    6926             : // Close the MiraMon database associated with a vector layer.
    6927         442 : static int MMCloseMMBD_XPFile(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6928             :                               struct MMAdmDatabase *MMAdmDB)
    6929             : {
    6930         442 :     int ret_code = 1;
    6931         442 :     if (!hMiraMonLayer)
    6932           0 :         return 1;
    6933             : 
    6934         442 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    6935             :     {
    6936         194 :         if (!MMAdmDB->pMMBDXP ||
    6937         194 :             (MMAdmDB->pMMBDXP && !MMAdmDB->pMMBDXP->pfDataBase))
    6938             :         {
    6939             :             // In case of 0 elements created we have to
    6940             :             // create an empty DBF
    6941           0 :             if (hMiraMonLayer->bIsPolygon)
    6942             :             {
    6943           0 :                 if (hMiraMonLayer->TopHeader.nElemCount <= 1)
    6944             :                 {
    6945           0 :                     if (MMCreateMMDB(hMiraMonLayer, nullptr))
    6946             :                     {
    6947           0 :                         CPLError(CE_Failure, CPLE_OutOfMemory,
    6948             :                                  "Memory error in MiraMon "
    6949             :                                  "driver (MMCreateMMDB())");
    6950           0 :                         goto end_label;
    6951             :                     }
    6952             :                 }
    6953             :             }
    6954           0 :             else if (hMiraMonLayer->bIsPoint || hMiraMonLayer->bIsArc)
    6955             :             {
    6956           0 :                 if (hMiraMonLayer->TopHeader.nElemCount == 0)
    6957             :                 {
    6958           0 :                     if (MMCreateMMDB(hMiraMonLayer, nullptr))
    6959             :                     {
    6960           0 :                         CPLError(CE_Failure, CPLE_OutOfMemory,
    6961             :                                  "Memory error in MiraMon "
    6962             :                                  "driver (MMCreateMMDB())");
    6963           0 :                         goto end_label;
    6964             :                     }
    6965             :                 }
    6966             :             }
    6967             :         }
    6968             : 
    6969         194 :         if (MM_WriteNRecordsMMBD_XPFile(MMAdmDB->pMMBDXP))
    6970           0 :             goto end_label;
    6971             : 
    6972             :         // Flushing all to be flushed
    6973         194 :         MMAdmDB->FlushRecList.SizeOfBlockToBeSaved = 0;
    6974         194 :         if (MMAppendBlockToBuffer(&MMAdmDB->FlushRecList))
    6975           0 :             goto end_label;
    6976             :     }
    6977             : 
    6978         442 :     ret_code = 0;
    6979         442 : end_label:
    6980             :     // Closing database files
    6981         442 :     if (MMAdmDB && MMAdmDB->pMMBDXP && MMAdmDB->pMMBDXP->pfDataBase)
    6982         194 :         fclose_and_nullify(&MMAdmDB->pMMBDXP->pfDataBase);
    6983             : 
    6984         442 :     return ret_code;
    6985             : }
    6986             : 
    6987         230 : int MMCloseMMBD_XP(struct MiraMonVectLayerInfo *hMiraMonLayer)
    6988             : {
    6989         230 :     int ret_code = 0;
    6990         230 :     if (!hMiraMonLayer)
    6991           0 :         return 1;
    6992             : 
    6993         230 :     if (hMiraMonLayer->pMMBDXP && hMiraMonLayer->pMMBDXP->pfDataBase)
    6994             :     {
    6995         113 :         fclose_and_nullify(&hMiraMonLayer->pMMBDXP->pfDataBase);
    6996             :     }
    6997             : 
    6998         230 :     if (hMiraMonLayer->bIsPoint)
    6999             :         ret_code =
    7000          76 :             MMCloseMMBD_XPFile(hMiraMonLayer, &hMiraMonLayer->MMPoint.MMAdmDB);
    7001         154 :     else if (hMiraMonLayer->bIsArc && !hMiraMonLayer->bIsPolygon)
    7002             :     {
    7003          62 :         if (MMCloseMMBD_XPFile(hMiraMonLayer, &hMiraMonLayer->MMArc.MMAdmDB))
    7004           0 :             ret_code = 1;
    7005          62 :         if (MMCloseMMBD_XPFile(hMiraMonLayer,
    7006             :                                &hMiraMonLayer->MMArc.MMNode.MMAdmDB))
    7007           0 :             ret_code = 1;
    7008             :     }
    7009          92 :     else if (hMiraMonLayer->bIsPolygon)
    7010             :     {
    7011          75 :         if (MMCloseMMBD_XPFile(hMiraMonLayer,
    7012             :                                &hMiraMonLayer->MMPolygon.MMAdmDB))
    7013           0 :             ret_code = 1;
    7014          75 :         if (MMCloseMMBD_XPFile(hMiraMonLayer,
    7015             :                                &hMiraMonLayer->MMPolygon.MMArc.MMAdmDB))
    7016           0 :             ret_code = 1;
    7017          75 :         if (MMCloseMMBD_XPFile(hMiraMonLayer,
    7018             :                                &hMiraMonLayer->MMPolygon.MMArc.MMNode.MMAdmDB))
    7019           0 :             ret_code = 1;
    7020             :     }
    7021          17 :     else if (hMiraMonLayer->bIsDBF)
    7022             :         ret_code =
    7023          17 :             MMCloseMMBD_XPFile(hMiraMonLayer, &hMiraMonLayer->MMAdmDBWriting);
    7024             : 
    7025         230 :     return ret_code;
    7026             : }
    7027             : 
    7028             : // Destroys the memory used to create a MiraMon table associated
    7029             : // with a vector layer.
    7030         442 : static void MMDestroyMMDBFile(struct MiraMonVectLayerInfo *hMiraMonLayer,
    7031             :                               struct MMAdmDatabase *pMMAdmDB)
    7032             : {
    7033         442 :     if (!hMiraMonLayer)
    7034           0 :         return;
    7035             : 
    7036         442 :     if (pMMAdmDB && pMMAdmDB->szRecordOnCourse)
    7037             :     {
    7038          44 :         VSIFree(pMMAdmDB->szRecordOnCourse);
    7039          44 :         pMMAdmDB->szRecordOnCourse = nullptr;
    7040             :     }
    7041         442 :     if (hMiraMonLayer->szStringToOperate)
    7042             :     {
    7043           0 :         VSIFree(hMiraMonLayer->szStringToOperate);
    7044           0 :         hMiraMonLayer->szStringToOperate = nullptr;
    7045           0 :         hMiraMonLayer->nNumStringToOperate = 0;
    7046             :     }
    7047             : 
    7048         442 :     if (pMMAdmDB && pMMAdmDB->pMMBDXP)
    7049             :     {
    7050         312 :         MM_ReleaseDBFHeader(&pMMAdmDB->pMMBDXP);
    7051         312 :         hMiraMonLayer->pMMBDXP = nullptr;
    7052             :     }
    7053         442 :     if (pMMAdmDB && pMMAdmDB->pRecList)
    7054             :     {
    7055          44 :         VSIFree(pMMAdmDB->pRecList);
    7056          44 :         pMMAdmDB->pRecList = nullptr;
    7057             :     }
    7058             : }
    7059             : 
    7060         824 : void MMDestroyMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer)
    7061             : {
    7062         824 :     if (!hMiraMonLayer)
    7063           0 :         return;
    7064             : 
    7065         824 :     if (hMiraMonLayer->bIsPoint)
    7066             :     {
    7067          76 :         MMDestroyMMDBFile(hMiraMonLayer, &hMiraMonLayer->MMPoint.MMAdmDB);
    7068          76 :         return;
    7069             :     }
    7070         748 :     if (hMiraMonLayer->bIsArc && !hMiraMonLayer->bIsPolygon)
    7071             :     {
    7072          62 :         MMDestroyMMDBFile(hMiraMonLayer, &hMiraMonLayer->MMArc.MMAdmDB);
    7073          62 :         MMDestroyMMDBFile(hMiraMonLayer, &hMiraMonLayer->MMArc.MMNode.MMAdmDB);
    7074          62 :         return;
    7075             :     }
    7076         686 :     if (hMiraMonLayer->bIsPolygon)
    7077             :     {
    7078          75 :         MMDestroyMMDBFile(hMiraMonLayer, &hMiraMonLayer->MMPolygon.MMAdmDB);
    7079          75 :         MMDestroyMMDBFile(hMiraMonLayer,
    7080             :                           &hMiraMonLayer->MMPolygon.MMArc.MMAdmDB);
    7081          75 :         MMDestroyMMDBFile(hMiraMonLayer,
    7082             :                           &hMiraMonLayer->MMPolygon.MMArc.MMNode.MMAdmDB);
    7083             :     }
    7084         686 :     if (hMiraMonLayer->bIsDBF)
    7085          17 :         MMDestroyMMDBFile(hMiraMonLayer, &hMiraMonLayer->MMAdmDBWriting);
    7086             : }
    7087             : 
    7088             : // COMING FROM mm_gdal_functions.c/h but only used here
    7089         340 : void MM_FillFieldDescriptorByLanguage(void)
    7090             : {
    7091         340 :     CPLStrlcpy(szInternalGraphicIdentifierEng, "Internal Graphic identifier",
    7092             :                MM_MAX_IDENTIFIER_SIZE);
    7093         340 :     CPLStrlcpy(szInternalGraphicIdentifierCat, "Identificador Grafic intern",
    7094             :                MM_MAX_IDENTIFIER_SIZE);
    7095         340 :     *(unsigned char *)&szInternalGraphicIdentifierCat[16] = MM_a_WITH_GRAVE;
    7096         340 :     CPLStrlcpy(szInternalGraphicIdentifierSpa, "Identificador Grafico interno",
    7097             :                MM_MAX_IDENTIFIER_SIZE);
    7098         340 :     *(unsigned char *)&szInternalGraphicIdentifierSpa[16] = MM_a_WITH_ACUTE;
    7099             : 
    7100         340 :     CPLStrlcpy(szNumberOfVerticesEng, "Number of vertices",
    7101             :                MM_MAX_IDENTIFIER_SIZE);
    7102         340 :     CPLStrlcpy(szNumberOfVerticesCat, "Nombre de vertexs",
    7103             :                MM_MAX_IDENTIFIER_SIZE);
    7104         340 :     CPLStrlcpy(szNumberOfVerticesSpa, "Numero de vertices",
    7105             :                MM_MAX_IDENTIFIER_SIZE);
    7106         340 :     *(unsigned char *)&szNumberOfVerticesCat[11] = MM_e_WITH_GRAVE;
    7107         340 :     *(unsigned char *)&szNumberOfVerticesSpa[1] = MM_u_WITH_ACUTE;
    7108         340 :     *(unsigned char *)&szNumberOfVerticesSpa[11] = MM_e_WITH_ACUTE;
    7109             : 
    7110         340 :     CPLStrlcpy(szLengthOfAarcEng, "Length of arc", MM_MAX_IDENTIFIER_SIZE);
    7111         340 :     CPLStrlcpy(szLengthOfAarcCat, "Longitud de l'arc", MM_MAX_IDENTIFIER_SIZE);
    7112         340 :     CPLStrlcpy(szLengthOfAarcSpa, "Longitud del arco", MM_MAX_IDENTIFIER_SIZE);
    7113             : 
    7114         340 :     CPLStrlcpy(szInitialNodeEng, "Initial node", MM_MAX_IDENTIFIER_SIZE);
    7115         340 :     CPLStrlcpy(szInitialNodeCat, "Node inicial", MM_MAX_IDENTIFIER_SIZE);
    7116         340 :     CPLStrlcpy(szInitialNodeSpa, "Nodo inicial", MM_MAX_IDENTIFIER_SIZE);
    7117             : 
    7118         340 :     CPLStrlcpy(szFinalNodeEng, "Final node", MM_MAX_IDENTIFIER_SIZE);
    7119         340 :     CPLStrlcpy(szFinalNodeCat, "Node final", MM_MAX_IDENTIFIER_SIZE);
    7120         340 :     CPLStrlcpy(szFinalNodeSpa, "Nodo final", MM_MAX_IDENTIFIER_SIZE);
    7121             : 
    7122         340 :     CPLStrlcpy(szNumberOfArcsToNodeEng, "Number of arcs to node",
    7123             :                MM_MAX_IDENTIFIER_SIZE);
    7124         340 :     CPLStrlcpy(szNumberOfArcsToNodeCat, "Nombre d'arcs al node",
    7125             :                MM_MAX_IDENTIFIER_SIZE);
    7126         340 :     CPLStrlcpy(szNumberOfArcsToNodeSpa, "Numero de arcos al nodo",
    7127             :                MM_MAX_IDENTIFIER_SIZE);
    7128         340 :     *(unsigned char *)&szNumberOfArcsToNodeSpa[1] = MM_u_WITH_ACUTE;
    7129             : 
    7130         340 :     CPLStrlcpy(szNodeTypeEng, "Node type", MM_MAX_IDENTIFIER_SIZE);
    7131         340 :     CPLStrlcpy(szNodeTypeCat, "Tipus de node", MM_MAX_IDENTIFIER_SIZE);
    7132         340 :     CPLStrlcpy(szNodeTypeSpa, "Tipo de nodo", MM_MAX_IDENTIFIER_SIZE);
    7133             : 
    7134         340 :     CPLStrlcpy(szPerimeterOfThePolygonEng, "Perimeter of the polygon",
    7135             :                MM_MAX_IDENTIFIER_SIZE);
    7136         340 :     CPLStrlcpy(szPerimeterOfThePolygonCat, "Perimetre del poligon",
    7137             :                MM_MAX_IDENTIFIER_SIZE);
    7138         340 :     CPLStrlcpy(szPerimeterOfThePolygonSpa, "Perimetro del poligono",
    7139             :                MM_MAX_IDENTIFIER_SIZE);
    7140             : 
    7141         340 :     *(unsigned char *)&szPerimeterOfThePolygonCat[3] = MM_i_WITH_ACUTE;
    7142         340 :     *(unsigned char *)&szPerimeterOfThePolygonSpa[3] = MM_i_WITH_ACUTE;
    7143         340 :     *(unsigned char *)&szPerimeterOfThePolygonCat[17] = MM_i_WITH_ACUTE;
    7144         340 :     *(unsigned char *)&szPerimeterOfThePolygonSpa[17] = MM_i_WITH_ACUTE;
    7145             : 
    7146         340 :     CPLStrlcpy(szAreaOfThePolygonEng, "Area of the polygon",
    7147             :                MM_MAX_IDENTIFIER_SIZE);
    7148         340 :     CPLStrlcpy(szAreaOfThePolygonCat, "Area del poligon",
    7149             :                MM_MAX_IDENTIFIER_SIZE);
    7150         340 :     CPLStrlcpy(szAreaOfThePolygonSpa, "Area del poligono",
    7151             :                MM_MAX_IDENTIFIER_SIZE);
    7152             : 
    7153         340 :     *(unsigned char *)&szAreaOfThePolygonCat[0] = MM_A_WITH_GRAVE;
    7154         340 :     *(unsigned char *)&szAreaOfThePolygonSpa[0] = MM_A_WITH_ACUTE;
    7155         340 :     *(unsigned char *)&szAreaOfThePolygonCat[12] = MM_i_WITH_ACUTE;
    7156         340 :     *(unsigned char *)&szAreaOfThePolygonSpa[12] = MM_i_WITH_ACUTE;
    7157             : 
    7158         340 :     CPLStrlcpy(szNumberOfArcsEng, "Number of arcs", MM_MAX_IDENTIFIER_SIZE);
    7159         340 :     CPLStrlcpy(szNumberOfArcsCat, "Nombre d'arcs", MM_MAX_IDENTIFIER_SIZE);
    7160         340 :     CPLStrlcpy(szNumberOfArcsSpa, "Numero de arcos", MM_MAX_IDENTIFIER_SIZE);
    7161             : 
    7162         340 :     *(unsigned char *)&szNumberOfArcsSpa[1] = MM_u_WITH_ACUTE;
    7163             : 
    7164         340 :     CPLStrlcpy(szNumberOfElementaryPolygonsEng, "Number of elementary polygons",
    7165             :                MM_MAX_IDENTIFIER_SIZE);
    7166         340 :     CPLStrlcpy(szNumberOfElementaryPolygonsCat, "Nombre de poligons elementals",
    7167             :                MM_MAX_IDENTIFIER_SIZE);
    7168         340 :     CPLStrlcpy(szNumberOfElementaryPolygonsSpa,
    7169             :                "Numero de poligonos elementales", MM_MAX_IDENTIFIER_SIZE);
    7170             : 
    7171         340 :     *(unsigned char *)&szNumberOfElementaryPolygonsSpa[1] = MM_u_WITH_ACUTE;
    7172         340 :     *(unsigned char *)&szNumberOfElementaryPolygonsCat[13] = MM_i_WITH_ACUTE;
    7173         340 :     *(unsigned char *)&szNumberOfElementaryPolygonsSpa[13] = MM_i_WITH_ACUTE;
    7174         340 : }
    7175             : 
    7176         660 : static MM_BOOLEAN MM_FillFieldDB_XP(
    7177             :     struct MM_FIELD *camp, const char *FieldName,
    7178             :     const char *FieldDescriptionEng, const char *FieldDescriptionCat,
    7179             :     const char *FieldDescriptionSpa, char FieldType,
    7180             :     MM_BYTES_PER_FIELD_TYPE_DBF BytesPerField, MM_BYTE DecimalsIfFloat)
    7181             : {
    7182             :     char nom_temp[MM_MAX_LON_FIELD_NAME_DBF];
    7183             :     int retorn_valida_nom_camp;
    7184             : 
    7185         660 :     if (FieldName)
    7186             :     {
    7187         660 :         retorn_valida_nom_camp = MM_ISExtendedNameBD_XP(FieldName);
    7188         660 :         if (retorn_valida_nom_camp == MM_DBF_NAME_NO_VALID)
    7189           0 :             return FALSE;
    7190         660 :         CPLStrlcpy(camp->FieldName, FieldName, MM_MAX_LON_FIELD_NAME_DBF);
    7191             : 
    7192         660 :         if (retorn_valida_nom_camp == MM_VALID_EXTENDED_DBF_NAME)
    7193             :         {
    7194           0 :             MM_CalculateBytesExtendedFieldName(camp);
    7195           0 :             CPLStrlcpy(nom_temp, FieldName, MM_MAX_LON_FIELD_NAME_DBF);
    7196           0 :             MM_ReturnValidClassicDBFFieldName(nom_temp);
    7197           0 :             nom_temp[MM_MAX_LON_CLASSICAL_FIELD_NAME_DBF] = '\0';
    7198           0 :             CPLStrlcpy(camp->ClassicalDBFFieldName, nom_temp,
    7199             :                        MM_MAX_LON_CLASSICAL_FIELD_NAME_DBF);
    7200             :         }
    7201             :     }
    7202             : 
    7203         660 :     if (FieldDescriptionEng)
    7204         660 :         CPLStrlcpy(camp->FieldDescription[MM_DEF_LANGUAGE], FieldDescriptionEng,
    7205             :                    sizeof(camp->FieldDescription[MM_DEF_LANGUAGE]));
    7206             :     else
    7207           0 :         strcpy(camp->FieldDescription[MM_DEF_LANGUAGE], "\0");
    7208             : 
    7209         660 :     if (FieldDescriptionEng)
    7210         660 :         CPLStrlcpy(camp->FieldDescription[MM_ENG_LANGUAGE], FieldDescriptionEng,
    7211             :                    sizeof(camp->FieldDescription[MM_ENG_LANGUAGE]));
    7212             :     else
    7213           0 :         strcpy(camp->FieldDescription[MM_ENG_LANGUAGE], "\0");
    7214             : 
    7215         660 :     if (FieldDescriptionCat)
    7216         660 :         CPLStrlcpy(camp->FieldDescription[MM_CAT_LANGUAGE], FieldDescriptionCat,
    7217             :                    sizeof(camp->FieldDescription[MM_CAT_LANGUAGE]));
    7218             :     else
    7219           0 :         strcpy(camp->FieldDescription[MM_CAT_LANGUAGE], "\0");
    7220             : 
    7221         660 :     if (FieldDescriptionSpa)
    7222         660 :         CPLStrlcpy(camp->FieldDescription[MM_SPA_LANGUAGE], FieldDescriptionSpa,
    7223             :                    sizeof(camp->FieldDescription[MM_SPA_LANGUAGE]));
    7224             :     else
    7225           0 :         strcpy(camp->FieldDescription[MM_SPA_LANGUAGE], "\0");
    7226             : 
    7227         660 :     camp->FieldType = FieldType;
    7228         660 :     camp->DecimalsIfFloat = DecimalsIfFloat;
    7229         660 :     camp->BytesPerField = BytesPerField;
    7230         660 :     return TRUE;
    7231             : }
    7232             : 
    7233          27 : size_t MM_DefineFirstPolygonFieldsDB_XP(struct MM_DATA_BASE_XP *bd_xp,
    7234             :                                         MM_BYTE n_perimeter_decimals,
    7235             :                                         MM_BYTE n_area_decimals_decimals)
    7236             : {
    7237          27 :     MM_EXT_DBF_N_FIELDS i_camp = 0;
    7238             : 
    7239          27 :     MM_FillFieldDB_XP(
    7240          27 :         bd_xp->pField + i_camp, szMMNomCampIdGraficDefecte,
    7241             :         szInternalGraphicIdentifierEng, szInternalGraphicIdentifierCat,
    7242             :         szInternalGraphicIdentifierSpa, 'N', MM_MIN_WIDTH_ID_GRAFIC, 0);
    7243          27 :     bd_xp->IdGraficField = 0;
    7244          27 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_ID_GRAFIC;
    7245          27 :     i_camp++;
    7246             : 
    7247          27 :     MM_FillFieldDB_XP(bd_xp->pField + i_camp, szMMNomCampNVertexsDefecte,
    7248             :                       szNumberOfVerticesEng, szNumberOfVerticesCat,
    7249             :                       szNumberOfVerticesSpa, 'N', MM_MIN_WIDTH_N_VERTEXS, 0);
    7250          27 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_N_VERTEXS;
    7251          27 :     i_camp++;
    7252             : 
    7253          27 :     MM_FillFieldDB_XP(bd_xp->pField + i_camp, szMMNomCampPerimetreDefecte,
    7254             :                       szPerimeterOfThePolygonEng, szPerimeterOfThePolygonCat,
    7255             :                       szPerimeterOfThePolygonSpa, 'N', MM_MIN_WIDTH_LONG,
    7256             :                       n_perimeter_decimals);
    7257          27 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_PERIMETRE;
    7258          27 :     i_camp++;
    7259             : 
    7260          27 :     MM_FillFieldDB_XP(bd_xp->pField + i_camp, szMMNomCampAreaDefecte,
    7261             :                       szAreaOfThePolygonEng, szAreaOfThePolygonCat,
    7262             :                       szAreaOfThePolygonSpa, 'N', MM_MIN_WIDTH_AREA,
    7263             :                       n_area_decimals_decimals);
    7264          27 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_AREA;
    7265          27 :     i_camp++;
    7266             : 
    7267          27 :     MM_FillFieldDB_XP(bd_xp->pField + i_camp, szMMNomCampNArcsDefecte,
    7268             :                       szNumberOfArcsEng, szNumberOfArcsCat, szNumberOfArcsSpa,
    7269             :                       'N', MM_MIN_WIDTH_N_ARCS, 0);
    7270          27 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_N_ARCS;
    7271          27 :     i_camp++;
    7272             : 
    7273          27 :     MM_FillFieldDB_XP(
    7274          27 :         bd_xp->pField + i_camp, szMMNomCampNPoligonsDefecte,
    7275             :         szNumberOfElementaryPolygonsEng, szNumberOfElementaryPolygonsCat,
    7276             :         szNumberOfElementaryPolygonsSpa, 'N', MM_MIN_WIDTH_N_POLIG, 0);
    7277          27 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_N_POLIG;
    7278          27 :     i_camp++;
    7279             : 
    7280          27 :     return i_camp;
    7281             : }
    7282             : 
    7283          58 : size_t MM_DefineFirstArcFieldsDB_XP(struct MM_DATA_BASE_XP *bd_xp,
    7284             :                                     MM_BYTE n_decimals)
    7285             : {
    7286             :     MM_EXT_DBF_N_FIELDS i_camp;
    7287             : 
    7288          58 :     i_camp = 0;
    7289          58 :     MM_FillFieldDB_XP(
    7290          58 :         bd_xp->pField + i_camp, szMMNomCampIdGraficDefecte,
    7291             :         szInternalGraphicIdentifierEng, szInternalGraphicIdentifierCat,
    7292             :         szInternalGraphicIdentifierSpa, 'N', MM_MIN_WIDTH_ID_GRAFIC, 0);
    7293          58 :     bd_xp->IdGraficField = 0;
    7294          58 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_ID_GRAFIC;
    7295          58 :     i_camp++;
    7296             : 
    7297          58 :     MM_FillFieldDB_XP(bd_xp->pField + i_camp, szMMNomCampNVertexsDefecte,
    7298             :                       szNumberOfVerticesEng, szNumberOfVerticesCat,
    7299             :                       szNumberOfVerticesSpa, 'N', MM_MIN_WIDTH_N_VERTEXS, 0);
    7300          58 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_N_VERTEXS;
    7301          58 :     i_camp++;
    7302             : 
    7303          58 :     MM_FillFieldDB_XP(bd_xp->pField + i_camp, szMMNomCampLongitudArcDefecte,
    7304             :                       szLengthOfAarcEng, szLengthOfAarcCat, szLengthOfAarcSpa,
    7305             :                       'N', MM_MIN_WIDTH_LONG, n_decimals);
    7306          58 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_LONG_ARC;
    7307          58 :     i_camp++;
    7308             : 
    7309          58 :     MM_FillFieldDB_XP(bd_xp->pField + i_camp, szMMNomCampNodeIniDefecte,
    7310             :                       szInitialNodeEng, szInitialNodeCat, szInitialNodeSpa, 'N',
    7311             :                       MM_MIN_WIDTH_INITIAL_NODE, 0);
    7312          58 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_NODE_INI;
    7313          58 :     i_camp++;
    7314             : 
    7315          58 :     MM_FillFieldDB_XP(bd_xp->pField + i_camp, szMMNomCampNodeFiDefecte,
    7316             :                       szFinalNodeEng, szFinalNodeCat, szFinalNodeSpa, 'N',
    7317             :                       MM_MIN_WIDTH_FINAL_NODE, 0);
    7318          58 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_NODE_FI;
    7319          58 :     i_camp++;
    7320             : 
    7321          58 :     return i_camp;
    7322             : }
    7323             : 
    7324          58 : size_t MM_DefineFirstNodeFieldsDB_XP(struct MM_DATA_BASE_XP *bd_xp)
    7325             : {
    7326             :     MM_EXT_DBF_N_FIELDS i_camp;
    7327             : 
    7328          58 :     i_camp = 0;
    7329             : 
    7330          58 :     MM_FillFieldDB_XP(
    7331          58 :         bd_xp->pField + i_camp, szMMNomCampIdGraficDefecte,
    7332             :         szInternalGraphicIdentifierEng, szInternalGraphicIdentifierCat,
    7333             :         szInternalGraphicIdentifierSpa, 'N', MM_MIN_WIDTH_ID_GRAFIC, 0);
    7334          58 :     bd_xp->IdGraficField = 0;
    7335          58 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_ID_GRAFIC;
    7336          58 :     i_camp++;
    7337             : 
    7338          58 :     MM_FillFieldDB_XP(bd_xp->pField + i_camp, szMMNomCampArcsANodeDefecte,
    7339             :                       szNumberOfArcsToNodeEng, szNumberOfArcsToNodeCat,
    7340             :                       szNumberOfArcsToNodeSpa, 'N', MM_MIN_WIDTH_ARCS_TO_NODE,
    7341             :                       0);
    7342          58 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_ARCS_A_NOD;
    7343          58 :     i_camp++;
    7344             : 
    7345          58 :     MM_FillFieldDB_XP(bd_xp->pField + i_camp, szMMNomCampTipusNodeDefecte,
    7346             :                       szNodeTypeEng, szNodeTypeCat, szNodeTypeSpa, 'N', 1, 0);
    7347          58 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_TIPUS_NODE;
    7348          58 :     i_camp++;
    7349             : 
    7350          58 :     return i_camp;
    7351             : }
    7352             : 
    7353          34 : size_t MM_DefineFirstPointFieldsDB_XP(struct MM_DATA_BASE_XP *bd_xp)
    7354             : {
    7355          34 :     size_t i_camp = 0;
    7356             : 
    7357          34 :     MM_FillFieldDB_XP(
    7358          34 :         bd_xp->pField + i_camp, szMMNomCampIdGraficDefecte,
    7359             :         szInternalGraphicIdentifierEng, szInternalGraphicIdentifierCat,
    7360             :         szInternalGraphicIdentifierSpa, 'N', MM_MIN_WIDTH_ID_GRAFIC, 0);
    7361          34 :     bd_xp->IdGraficField = 0;
    7362          34 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_ID_GRAFIC;
    7363          34 :     i_camp++;
    7364             : 
    7365          34 :     return i_camp;
    7366             : }
    7367             : 
    7368             : CPL_C_END  // Necessary for compiling in GDAL project

Generated by: LCOV version 1.14