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: 2734 3634 75.2 %
Date: 2025-09-10 17:48:50 Functions: 100 100 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         502 : static void MMSet1_1Version(struct MM_TH *pTopHeader)
     184             : {
     185         502 :     pTopHeader->aLayerVersion[0] = ' ';
     186         502 :     pTopHeader->aLayerVersion[1] = '1';
     187         502 :     pTopHeader->aLayerSubVersion = '1';
     188         502 : }
     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         336 : 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         336 :     if (!hMiraMonLayer)
    1838           0 :         return 1;
    1839             : 
    1840             :     // Some variables must be initialized
    1841         336 :     MM_FillFieldDescriptorByLanguage();
    1842             : 
    1843         336 :     memset(hMiraMonLayer, 0, sizeof(*hMiraMonLayer));
    1844             : 
    1845             :     //hMiraMonLayer->Version = MM_VECTOR_LAYER_LAST_VERSION;
    1846             : 
    1847         336 :     hMiraMonLayer->ReadOrWrite = ReadOrWrite;
    1848         336 :     hMiraMonLayer->MMMap = MMMap;
    1849             : 
    1850             :     // Don't free in destructor
    1851         336 :     hMiraMonLayer->pLayerDB = pLayerDB;
    1852             : 
    1853             :     // Opening mode
    1854         336 :     strcpy(hMiraMonLayer->pszFlags, "wb+");
    1855             : 
    1856         336 :     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         336 :     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         336 :     else if (LayerVersion == MM_32BITS_VERSION)
    1869             :     {
    1870         312 :         MMSet1_1Version(&hMiraMonLayer->TopHeader);
    1871         312 :         hMiraMonLayer->nHeaderDiskSize = MM_HEADER_SIZE_32_BITS;
    1872         312 :         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         336 :     hMiraMonLayer->pszSrcLayerName = CPLStrdup(pzFileName);
    1882         336 :     hMiraMonLayer->szLayerTitle = CPLStrdup(CPLGetFilename(pzFileName));
    1883             : 
    1884         336 :     if (!hMiraMonLayer->bIsBeenInit &&
    1885         336 :         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         336 :     hMiraMonLayer->nNumStringToOperate = 0;
    1897         336 :     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         336 :     hMiraMonLayer->nMMLanguage = nMMLanguage;
    1906             : 
    1907         336 :     if (nMMRecode == MM_RECODE_UTF8)
    1908           4 :         hMiraMonLayer->nCharSet = MM_JOC_CARAC_UTF8_DBF;
    1909             :     else  //if(nMMRecode==MM_RECODE_ANSI)
    1910         332 :         hMiraMonLayer->nCharSet = MM_JOC_CARAC_ANSI_DBASE;
    1911         336 :     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 || !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 :     return ret_code;
    2017             : }
    2018             : 
    2019         137 : static int MMCloseNodeLayer(struct MiraMonVectLayerInfo *hMiraMonLayer)
    2020             : {
    2021         137 :     int ret_code = 1;
    2022             :     struct MiraMonArcLayer *pMMArcLayer;
    2023             : 
    2024         137 :     if (!hMiraMonLayer)
    2025           0 :         return 1;
    2026             : 
    2027         137 :     if (hMiraMonLayer->bIsPolygon)
    2028          75 :         pMMArcLayer = &hMiraMonLayer->MMPolygon.MMArc;
    2029             :     else
    2030          62 :         pMMArcLayer = &hMiraMonLayer->MMArc;
    2031             : 
    2032         137 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    2033             :     {
    2034          58 :         hMiraMonLayer->TopHeader.bIs3d = hMiraMonLayer->bIsReal3d;
    2035             : 
    2036          58 :         if (MMWriteHeader(pMMArcLayer->MMNode.pF, &pMMArcLayer->TopNodeHeader))
    2037           0 :             goto end_label;
    2038          58 :         hMiraMonLayer->OffsetCheck = hMiraMonLayer->nHeaderDiskSize;
    2039             : 
    2040             :         // NH Section
    2041          58 :         if (MMWriteNHNodeSection(hMiraMonLayer, hMiraMonLayer->nHeaderDiskSize))
    2042           0 :             goto end_label;
    2043             : 
    2044             :         // NL Section
    2045          58 :         pMMArcLayer->MMNode.FlushNL.SizeOfBlockToBeSaved = 0;
    2046          58 :         if (MMAppendBlockToBuffer(&pMMArcLayer->MMNode.FlushNL))
    2047           0 :             goto end_label;
    2048          58 :         if (MMMoveFromFileToFile(pMMArcLayer->MMNode.pFNL,
    2049             :                                  pMMArcLayer->MMNode.pF,
    2050             :                                  &hMiraMonLayer->OffsetCheck))
    2051           0 :             goto end_label;
    2052             : 
    2053          58 :         fclose_and_nullify(&pMMArcLayer->MMNode.pFNL);
    2054          58 :         if (*pMMArcLayer->MMNode.pszNLName != '\0')
    2055          58 :             VSIUnlink(pMMArcLayer->MMNode.pszNLName);
    2056             :     }
    2057             : 
    2058         137 :     ret_code = 0;
    2059         137 : end_label:
    2060         137 :     fclose_and_nullify(&pMMArcLayer->MMNode.pFNL);
    2061             : 
    2062         137 :     fclose_and_nullify(&pMMArcLayer->MMNode.pF);
    2063             : 
    2064         137 :     return ret_code;
    2065             : }
    2066             : 
    2067         137 : static int MMCloseArcLayer(struct MiraMonVectLayerInfo *hMiraMonLayer)
    2068             : {
    2069         137 :     int ret_code = 0;
    2070             :     struct MiraMonArcLayer *pMMArcLayer;
    2071             :     struct MM_TH *pArcTopHeader;
    2072             : 
    2073         137 :     if (!hMiraMonLayer)
    2074           0 :         return 1;
    2075             : 
    2076         137 :     if (hMiraMonLayer->bIsPolygon)
    2077             :     {
    2078          75 :         pMMArcLayer = &hMiraMonLayer->MMPolygon.MMArc;
    2079          75 :         pArcTopHeader = &hMiraMonLayer->MMPolygon.TopArcHeader;
    2080             :     }
    2081             :     else
    2082             :     {
    2083          62 :         pMMArcLayer = &hMiraMonLayer->MMArc;
    2084          62 :         pArcTopHeader = &hMiraMonLayer->TopHeader;
    2085             :     }
    2086             : 
    2087         137 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    2088             :     {
    2089          58 :         hMiraMonLayer->nFinalElemCount = pArcTopHeader->nElemCount;
    2090          58 :         pArcTopHeader->bIs3d = hMiraMonLayer->bIsReal3d;
    2091             : 
    2092          58 :         if (MMWriteHeader(pMMArcLayer->pF, pArcTopHeader))
    2093             :         {
    2094           0 :             CPLError(CE_Failure, CPLE_NoWriteAccess, "Error writing to file %s",
    2095           0 :                      pMMArcLayer->pszLayerName);
    2096           0 :             goto end_label;
    2097             :         }
    2098          58 :         hMiraMonLayer->OffsetCheck = hMiraMonLayer->nHeaderDiskSize;
    2099             : 
    2100             :         // AH Section
    2101          58 :         if (MMWriteAHArcSection(hMiraMonLayer, hMiraMonLayer->OffsetCheck))
    2102             :         {
    2103           0 :             CPLError(CE_Failure, CPLE_NoWriteAccess, "Error writing to file %s",
    2104           0 :                      pMMArcLayer->pszLayerName);
    2105           0 :             goto end_label;
    2106             :         }
    2107             : 
    2108             :         // AL Section
    2109          58 :         pMMArcLayer->FlushAL.SizeOfBlockToBeSaved = 0;
    2110          58 :         if (MMAppendBlockToBuffer(&pMMArcLayer->FlushAL))
    2111             :         {
    2112           0 :             CPLError(CE_Failure, CPLE_NoWriteAccess, "Error writing to file %s",
    2113           0 :                      pMMArcLayer->pszLayerName);
    2114           0 :             goto end_label;
    2115             :         }
    2116          58 :         if (MMMoveFromFileToFile(pMMArcLayer->pFAL, pMMArcLayer->pF,
    2117             :                                  &hMiraMonLayer->OffsetCheck))
    2118             :         {
    2119           0 :             CPLError(CE_Failure, CPLE_NoWriteAccess, "Error writing to file %s",
    2120           0 :                      pMMArcLayer->pszLayerName);
    2121           0 :             goto end_label;
    2122             :         }
    2123          58 :         fclose_and_nullify(&pMMArcLayer->pFAL);
    2124             : 
    2125          58 :         if (*pMMArcLayer->pszALName != '\0')
    2126          58 :             VSIUnlink(pMMArcLayer->pszALName);
    2127             : 
    2128             :         // 3D Section
    2129          58 :         if (MMClose3DSectionLayer(
    2130             :                 hMiraMonLayer, pArcTopHeader->nElemCount, pMMArcLayer->pF,
    2131          58 :                 pMMArcLayer->pF3d, pMMArcLayer->psz3DLayerName,
    2132             :                 &pMMArcLayer->pZSection, hMiraMonLayer->OffsetCheck))
    2133             :         {
    2134           0 :             CPLError(CE_Failure, CPLE_NoWriteAccess, "Error writing to file %s",
    2135           0 :                      pMMArcLayer->pszLayerName);
    2136           0 :             goto end_label;
    2137             :         }
    2138             :     }
    2139             : 
    2140         137 :     ret_code = 0;
    2141         137 : end_label:
    2142         137 :     fclose_and_nullify(&pMMArcLayer->pF);
    2143             : 
    2144         137 :     fclose_and_nullify(&pMMArcLayer->pFAL);
    2145             : 
    2146         137 :     if (MMCloseNodeLayer(hMiraMonLayer))
    2147           0 :         ret_code = 1;
    2148             : 
    2149         137 :     return ret_code;
    2150             : }
    2151             : 
    2152          75 : static int MMClosePolygonLayer(struct MiraMonVectLayerInfo *hMiraMonLayer)
    2153             : {
    2154          75 :     int ret_code = 0;
    2155             :     struct MiraMonPolygonLayer *pMMPolygonLayer;
    2156             : 
    2157          75 :     if (!hMiraMonLayer)
    2158           0 :         return 1;
    2159             : 
    2160          75 :     pMMPolygonLayer = &hMiraMonLayer->MMPolygon;
    2161             : 
    2162          75 :     MMCloseArcLayer(hMiraMonLayer);
    2163             : 
    2164          75 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    2165             :     {
    2166          27 :         hMiraMonLayer->nFinalElemCount = hMiraMonLayer->TopHeader.nElemCount;
    2167          27 :         hMiraMonLayer->TopHeader.bIs3d = hMiraMonLayer->bIsReal3d;
    2168             : 
    2169          27 :         if (MMWriteHeader(pMMPolygonLayer->pF, &hMiraMonLayer->TopHeader))
    2170             :         {
    2171           0 :             CPLError(CE_Failure, CPLE_NoWriteAccess, "Error writing to file %s",
    2172           0 :                      pMMPolygonLayer->pszLayerName);
    2173           0 :             goto end_label;
    2174             :         }
    2175          27 :         hMiraMonLayer->OffsetCheck = hMiraMonLayer->nHeaderDiskSize;
    2176             : 
    2177             :         // PS Section
    2178          27 :         pMMPolygonLayer->FlushPS.SizeOfBlockToBeSaved = 0;
    2179          27 :         if (MMAppendBlockToBuffer(&pMMPolygonLayer->FlushPS))
    2180             :         {
    2181           0 :             CPLError(CE_Failure, CPLE_NoWriteAccess, "Error writing to file %s",
    2182           0 :                      pMMPolygonLayer->pszLayerName);
    2183           0 :             goto end_label;
    2184             :         }
    2185          27 :         if (MMMoveFromFileToFile(pMMPolygonLayer->pFPS, pMMPolygonLayer->pF,
    2186             :                                  &hMiraMonLayer->OffsetCheck))
    2187             :         {
    2188           0 :             CPLError(CE_Failure, CPLE_NoWriteAccess, "Error writing to file %s",
    2189           0 :                      pMMPolygonLayer->pszLayerName);
    2190           0 :             goto end_label;
    2191             :         }
    2192             : 
    2193          27 :         fclose_and_nullify(&pMMPolygonLayer->pFPS);
    2194          27 :         if (*pMMPolygonLayer->pszPSName != '\0')
    2195          27 :             VSIUnlink(pMMPolygonLayer->pszPSName);
    2196             : 
    2197             :         // AH Section
    2198          27 :         if (MMWritePHPolygonSection(hMiraMonLayer, hMiraMonLayer->OffsetCheck))
    2199             :         {
    2200           0 :             CPLError(CE_Failure, CPLE_NoWriteAccess, "Error writing to file %s",
    2201           0 :                      pMMPolygonLayer->pszLayerName);
    2202           0 :             goto end_label;
    2203             :         }
    2204             : 
    2205             :         // PAL Section
    2206          27 :         pMMPolygonLayer->FlushPAL.SizeOfBlockToBeSaved = 0;
    2207          27 :         if (MMAppendBlockToBuffer(&pMMPolygonLayer->FlushPAL))
    2208             :         {
    2209           0 :             CPLError(CE_Failure, CPLE_NoWriteAccess, "Error writing to file %s",
    2210           0 :                      pMMPolygonLayer->pszLayerName);
    2211           0 :             goto end_label;
    2212             :         }
    2213          27 :         if (MMMoveFromFileToFile(pMMPolygonLayer->pFPAL, pMMPolygonLayer->pF,
    2214             :                                  &hMiraMonLayer->OffsetCheck))
    2215             :         {
    2216           0 :             CPLError(CE_Failure, CPLE_NoWriteAccess, "Error writing to file %s",
    2217           0 :                      pMMPolygonLayer->pszLayerName);
    2218           0 :             goto end_label;
    2219             :         }
    2220          27 :         fclose_and_nullify(&pMMPolygonLayer->pFPAL);
    2221             : 
    2222          27 :         if (*pMMPolygonLayer->pszPALName != '\0')
    2223          27 :             VSIUnlink(pMMPolygonLayer->pszPALName);
    2224             :     }
    2225             : 
    2226          75 :     ret_code = 0;
    2227             : 
    2228          75 : end_label:
    2229          75 :     fclose_and_nullify(&pMMPolygonLayer->pF);
    2230             : 
    2231          75 :     fclose_and_nullify(&pMMPolygonLayer->pFPAL);
    2232             : 
    2233          75 :     return ret_code;
    2234             : }
    2235             : 
    2236         230 : int MMCloseLayer(struct MiraMonVectLayerInfo *hMiraMonLayer)
    2237             : {
    2238         230 :     int ret_code = 0;
    2239             :     //CheckMMVectorLayerVersion(hMiraMonLayer, 1)
    2240             : 
    2241         230 :     if (!hMiraMonLayer)
    2242           0 :         return 0;
    2243             : 
    2244         230 :     if (hMiraMonLayer->bIsPoint)
    2245             :     {
    2246          76 :         ret_code = MMClosePointLayer(hMiraMonLayer);
    2247             :     }
    2248         154 :     else if (hMiraMonLayer->bIsArc && !hMiraMonLayer->bIsPolygon)
    2249             :     {
    2250          62 :         ret_code = MMCloseArcLayer(hMiraMonLayer);
    2251             :     }
    2252          92 :     else if (hMiraMonLayer->bIsPolygon)
    2253             :     {
    2254          75 :         ret_code = MMClosePolygonLayer(hMiraMonLayer);
    2255             :     }
    2256          17 :     else if (hMiraMonLayer->bIsDBF)
    2257             :     {
    2258             :         // If no geometry, remove all created files
    2259          17 :         if (hMiraMonLayer->pszSrcLayerName)
    2260          17 :             VSIUnlink(hMiraMonLayer->pszSrcLayerName);
    2261          17 :         if (hMiraMonLayer->szLayerTitle)
    2262          17 :             VSIUnlink(hMiraMonLayer->szLayerTitle);
    2263             :     }
    2264             : 
    2265             :     // MiraMon metadata files
    2266         230 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    2267             :     {
    2268         109 :         if (MMWriteVectorMetadata(hMiraMonLayer))
    2269             :         {
    2270           0 :             CPLError(CE_Failure, CPLE_NoWriteAccess,
    2271             :                      "Some error writing in metadata file of the layer");
    2272           0 :             ret_code = 1;
    2273             :         }
    2274             :     }
    2275             : 
    2276             :     // MiraMon database files
    2277         230 :     if (MMCloseMMBD_XP(hMiraMonLayer))
    2278             :     {
    2279           0 :         CPLError(CE_Failure, CPLE_NoWriteAccess,
    2280             :                  "Some error writing in DBF file of the layer");
    2281           0 :         ret_code = 1;
    2282             :     }
    2283         230 :     return ret_code;
    2284             : }
    2285             : 
    2286             : /* -------------------------------------------------------------------- */
    2287             : /*      Layer Functions: Destroying (allocated memory)                  */
    2288             : /* -------------------------------------------------------------------- */
    2289         425 : static void MMDestroyMMAdmDB(struct MMAdmDatabase *pMMAdmDB)
    2290             : {
    2291         425 :     if (pMMAdmDB->pRecList)
    2292             :     {
    2293         150 :         VSIFree(pMMAdmDB->pRecList);
    2294         150 :         pMMAdmDB->pRecList = nullptr;
    2295             :     }
    2296             : 
    2297         425 :     if (pMMAdmDB->szRecordOnCourse)
    2298             :     {
    2299         150 :         VSIFree(pMMAdmDB->szRecordOnCourse);
    2300         150 :         pMMAdmDB->szRecordOnCourse = nullptr;
    2301         150 :         pMMAdmDB->nNumRecordOnCourse = 0;
    2302             :     }
    2303         425 : }
    2304             : 
    2305          76 : static int MMDestroyPointLayer(struct MiraMonVectLayerInfo *hMiraMonLayer)
    2306             : {
    2307          76 :     if (!hMiraMonLayer)
    2308           0 :         return 1;
    2309             : 
    2310          76 :     if (hMiraMonLayer->MMPoint.pTL)
    2311             :     {
    2312          34 :         VSIFree(hMiraMonLayer->MMPoint.pTL);
    2313          34 :         hMiraMonLayer->MMPoint.pTL = nullptr;
    2314             :     }
    2315             : 
    2316          76 :     MMDestroyZSectionDescription(&hMiraMonLayer->MMPoint.pZSection);
    2317          76 :     MMDestroyMMAdmDB(&hMiraMonLayer->MMPoint.MMAdmDB);
    2318             : 
    2319          76 :     return 0;
    2320             : }
    2321             : 
    2322         137 : static int MMDestroyNodeLayer(struct MiraMonVectLayerInfo *hMiraMonLayer)
    2323             : {
    2324             :     struct MiraMonArcLayer *pMMArcLayer;
    2325             : 
    2326         137 :     if (!hMiraMonLayer)
    2327           0 :         return 1;
    2328             : 
    2329         137 :     if (hMiraMonLayer->bIsPolygon)
    2330          75 :         pMMArcLayer = &hMiraMonLayer->MMPolygon.MMArc;
    2331             :     else
    2332          62 :         pMMArcLayer = &hMiraMonLayer->MMArc;
    2333             : 
    2334         137 :     if (pMMArcLayer->MMNode.pNL)
    2335             :     {
    2336          58 :         VSIFree(pMMArcLayer->MMNode.pNL);
    2337          58 :         pMMArcLayer->MMNode.pNL = nullptr;
    2338             :     }
    2339             : 
    2340         137 :     if (pMMArcLayer->MMNode.pNodeHeader)
    2341             :     {
    2342          58 :         VSIFree(pMMArcLayer->MMNode.pNodeHeader);
    2343          58 :         pMMArcLayer->MMNode.pNodeHeader = nullptr;
    2344             :     }
    2345             : 
    2346         137 :     MMDestroyMMAdmDB(&hMiraMonLayer->MMArc.MMNode.MMAdmDB);
    2347         137 :     return 0;
    2348             : }
    2349             : 
    2350         137 : static int MMDestroyArcLayer(struct MiraMonVectLayerInfo *hMiraMonLayer)
    2351             : {
    2352             :     struct MiraMonArcLayer *pMMArcLayer;
    2353             : 
    2354         137 :     if (!hMiraMonLayer)
    2355           0 :         return 1;
    2356             : 
    2357         137 :     if (hMiraMonLayer->bIsPolygon)
    2358          75 :         pMMArcLayer = &hMiraMonLayer->MMPolygon.MMArc;
    2359             :     else
    2360          62 :         pMMArcLayer = &hMiraMonLayer->MMArc;
    2361             : 
    2362         137 :     if (pMMArcLayer->pAL)
    2363             :     {
    2364          58 :         VSIFree(pMMArcLayer->pAL);
    2365          58 :         pMMArcLayer->pAL = nullptr;
    2366             :     }
    2367         137 :     if (pMMArcLayer->pArcHeader)
    2368             :     {
    2369         127 :         VSIFree(pMMArcLayer->pArcHeader);
    2370         127 :         pMMArcLayer->pArcHeader = nullptr;
    2371             :     }
    2372             : 
    2373         137 :     MMDestroyZSectionDescription(&pMMArcLayer->pZSection);
    2374         137 :     MMDestroyMMAdmDB(&pMMArcLayer->MMAdmDB);
    2375             : 
    2376         137 :     MMDestroyNodeLayer(hMiraMonLayer);
    2377         137 :     return 0;
    2378             : }
    2379             : 
    2380          75 : static int MMDestroyPolygonLayer(struct MiraMonVectLayerInfo *hMiraMonLayer)
    2381             : {
    2382             :     struct MiraMonPolygonLayer *pMMPolygonLayer;
    2383             : 
    2384          75 :     if (!hMiraMonLayer)
    2385           0 :         return 1;
    2386             : 
    2387          75 :     pMMPolygonLayer = &hMiraMonLayer->MMPolygon;
    2388             : 
    2389          75 :     MMDestroyArcLayer(hMiraMonLayer);
    2390             : 
    2391          75 :     if (pMMPolygonLayer->pPAL)
    2392             :     {
    2393          27 :         VSIFree(pMMPolygonLayer->pPAL);
    2394          27 :         pMMPolygonLayer->pPAL = nullptr;
    2395             :     }
    2396             : 
    2397          75 :     if (pMMPolygonLayer->pPS)
    2398             :     {
    2399          27 :         VSIFree(pMMPolygonLayer->pPS);
    2400          27 :         pMMPolygonLayer->pPS = nullptr;
    2401             :     }
    2402             : 
    2403          75 :     if (pMMPolygonLayer->pPolHeader)
    2404             :     {
    2405          75 :         VSIFree(pMMPolygonLayer->pPolHeader);
    2406          75 :         pMMPolygonLayer->pPolHeader = nullptr;
    2407             :     }
    2408             : 
    2409          75 :     MMDestroyMMAdmDB(&pMMPolygonLayer->MMAdmDB);
    2410             : 
    2411          75 :     return 0;
    2412             : }
    2413             : 
    2414         820 : int MMDestroyLayer(struct MiraMonVectLayerInfo *hMiraMonLayer)
    2415             : {
    2416             :     //CheckMMVectorLayerVersion(hMiraMonLayer, 1)
    2417             : 
    2418         820 :     if (!hMiraMonLayer)
    2419           0 :         return 1;
    2420             : 
    2421         820 :     if (hMiraMonLayer->bIsPoint)
    2422          76 :         MMDestroyPointLayer(hMiraMonLayer);
    2423         744 :     else if (hMiraMonLayer->bIsArc && !hMiraMonLayer->bIsPolygon)
    2424          62 :         MMDestroyArcLayer(hMiraMonLayer);
    2425         682 :     else if (hMiraMonLayer->bIsPolygon)
    2426          75 :         MMDestroyPolygonLayer(hMiraMonLayer);
    2427             : 
    2428         820 :     if (hMiraMonLayer->pszSrcLayerName)
    2429             :     {
    2430         457 :         VSIFree(hMiraMonLayer->pszSrcLayerName);
    2431         457 :         hMiraMonLayer->pszSrcLayerName = nullptr;
    2432             :     }
    2433         820 :     if (hMiraMonLayer->szLayerTitle)
    2434             :     {
    2435         336 :         VSIFree(hMiraMonLayer->szLayerTitle);
    2436         336 :         hMiraMonLayer->szLayerTitle = nullptr;
    2437             :     }
    2438         820 :     if (hMiraMonLayer->pSRS)
    2439             :     {
    2440         170 :         VSIFree(hMiraMonLayer->pSRS);
    2441         170 :         hMiraMonLayer->pSRS = nullptr;
    2442             :     }
    2443             : 
    2444         820 :     if (hMiraMonLayer->pZUnit)
    2445             :     {
    2446           0 :         VSIFree(hMiraMonLayer->pZUnit);
    2447           0 :         hMiraMonLayer->pZUnit = nullptr;
    2448             :     }
    2449             : 
    2450         820 :     if (hMiraMonLayer->pMultRecordIndex)
    2451             :     {
    2452         104 :         VSIFree(hMiraMonLayer->pMultRecordIndex);
    2453         104 :         hMiraMonLayer->pMultRecordIndex = nullptr;
    2454             :     }
    2455             : 
    2456         820 :     if (hMiraMonLayer->ReadFeature.pNCoordRing)
    2457             :     {
    2458          85 :         free(hMiraMonLayer->ReadFeature.pNCoordRing);
    2459          85 :         hMiraMonLayer->ReadFeature.pNCoordRing = nullptr;
    2460             :     }
    2461         820 :     if (hMiraMonLayer->ReadFeature.pCoord)
    2462             :     {
    2463          97 :         free(hMiraMonLayer->ReadFeature.pCoord);
    2464          97 :         hMiraMonLayer->ReadFeature.pCoord = nullptr;
    2465             :     }
    2466         820 :     if (hMiraMonLayer->ReadFeature.pZCoord)
    2467             :     {
    2468          19 :         free(hMiraMonLayer->ReadFeature.pZCoord);
    2469          19 :         hMiraMonLayer->ReadFeature.pZCoord = nullptr;
    2470             :     }
    2471         820 :     if (hMiraMonLayer->ReadFeature.pRecords)
    2472             :     {
    2473           0 :         free(hMiraMonLayer->ReadFeature.pRecords);
    2474           0 :         hMiraMonLayer->ReadFeature.pRecords = nullptr;
    2475             :     }
    2476         820 :     if (hMiraMonLayer->ReadFeature.flag_VFG)
    2477             :     {
    2478          38 :         free(hMiraMonLayer->ReadFeature.flag_VFG);
    2479          38 :         hMiraMonLayer->ReadFeature.flag_VFG = nullptr;
    2480             :     }
    2481             : 
    2482         820 :     if (hMiraMonLayer->pArcs)
    2483             :     {
    2484          44 :         VSIFree(hMiraMonLayer->pArcs);
    2485          44 :         hMiraMonLayer->pArcs = nullptr;
    2486             :     }
    2487             : 
    2488         820 :     if (hMiraMonLayer->szStringToOperate)
    2489             :     {
    2490         449 :         VSIFree(hMiraMonLayer->szStringToOperate);
    2491         449 :         hMiraMonLayer->szStringToOperate = nullptr;
    2492         449 :         hMiraMonLayer->nNumStringToOperate = 0;
    2493             :     }
    2494             : 
    2495         820 :     if (hMiraMonLayer->pLayerDB)
    2496             :     {
    2497         108 :         if (hMiraMonLayer->pLayerDB->pFields)
    2498             :         {
    2499         108 :             VSIFree(hMiraMonLayer->pLayerDB->pFields);
    2500         108 :             hMiraMonLayer->pLayerDB->pFields = nullptr;
    2501             :         }
    2502         108 :         VSIFree(hMiraMonLayer->pLayerDB);
    2503         108 :         hMiraMonLayer->pLayerDB = nullptr;
    2504             :     }
    2505             : 
    2506             :     // Destroys all database objects
    2507         820 :     MMDestroyMMDB(hMiraMonLayer);
    2508             : 
    2509         820 :     return 0;
    2510             : }
    2511             : 
    2512             : /* -------------------------------------------------------------------- */
    2513             : /*      Flush Layer Functions                                           */
    2514             : /* -------------------------------------------------------------------- */
    2515             : 
    2516             : // Initializes a MM_FLUSH_INFO structure, which is used for buffering
    2517             : // data before writing it to a file.
    2518        1152 : int MMInitFlush(struct MM_FLUSH_INFO *pFlush, VSILFILE *pF, GUInt64 nBlockSize,
    2519             :                 char **pBuffer, MM_FILE_OFFSET DiskOffsetWhereToFlush,
    2520             :                 GInt32 nMyDiskSize)
    2521             : {
    2522        1152 :     memset(pFlush, 0, sizeof(*pFlush));
    2523        1152 :     *pBuffer = nullptr;
    2524             : 
    2525        1152 :     pFlush->nMyDiskSize = nMyDiskSize;
    2526        1152 :     pFlush->pF = pF;
    2527        1152 :     pFlush->nBlockSize = nBlockSize;
    2528        1152 :     pFlush->nNumBytes = 0;
    2529        1152 :     if (MMCheckSize_t(nBlockSize, 1))
    2530           0 :         return 1;
    2531             : 
    2532        1152 :     if (!nBlockSize)
    2533             :     {
    2534           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    2535             :                  "Error in MiraMon "
    2536             :                  "driver: MMInitFlush() with no bytes to process");
    2537           0 :         return 1;
    2538             :     }
    2539             : 
    2540        1152 :     if (nullptr == (*pBuffer = (char *)VSICalloc(1, (size_t)nBlockSize)))
    2541             :     {
    2542           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    2543             :                  "Memory error in MiraMon "
    2544             :                  "driver (MMInitFlush())");
    2545           0 :         return 1;
    2546             :     }
    2547        1152 :     pFlush->OffsetWhereToFlush = DiskOffsetWhereToFlush;
    2548        1152 :     pFlush->CurrentOffset = 0;
    2549        1152 :     return 0;
    2550             : }
    2551             : 
    2552             : // Reads data from a file into a buffer.
    2553         487 : int MMReadFlush(struct MM_FLUSH_INFO *pFlush)
    2554             : {
    2555         487 :     VSIFSeekL(pFlush->pF, pFlush->OffsetWhereToFlush, SEEK_SET);
    2556         487 :     if (pFlush->nBlockSize !=
    2557         487 :         (GUInt64)(VSIFReadL(pFlush->pBlockWhereToSaveOrRead, 1,
    2558         487 :                             (size_t)pFlush->nBlockSize, pFlush->pF)))
    2559           6 :         return 1;
    2560         481 :     return 0;
    2561             : }
    2562             : 
    2563             : // Flushes data from a buffer to a disk file.
    2564         722 : static int MMFlushToDisk(struct MM_FLUSH_INFO *FlushInfo)
    2565             : {
    2566         722 :     if (!FlushInfo->nNumBytes)
    2567          86 :         return 0;
    2568             :     // Just flush to the disk at the correct place.
    2569         636 :     VSIFSeekL(FlushInfo->pF, FlushInfo->OffsetWhereToFlush, SEEK_SET);
    2570             : 
    2571         636 :     if (FlushInfo->nNumBytes !=
    2572         636 :         (GUInt64)VSIFWriteL(FlushInfo->pBlockWhereToSaveOrRead, 1,
    2573         636 :                             (size_t)FlushInfo->nNumBytes, FlushInfo->pF))
    2574           0 :         return 1;
    2575         636 :     FlushInfo->OffsetWhereToFlush += FlushInfo->nNumBytes;
    2576         636 :     FlushInfo->NTimesFlushed++;
    2577         636 :     FlushInfo->TotalSavedBytes += FlushInfo->nNumBytes;
    2578         636 :     FlushInfo->nNumBytes = 0;
    2579             : 
    2580         636 :     return 0;
    2581             : }
    2582             : 
    2583             : // Reads a block of data from a buffer in memory
    2584        8344 : int MMReadBlockFromBuffer(struct MM_FLUSH_INFO *FlushInfo)
    2585             : {
    2586        8344 :     if (!FlushInfo->SizeOfBlockToBeSaved)
    2587           0 :         return 0;
    2588             : 
    2589        8344 :     if (FlushInfo->pBlockToBeSaved)
    2590             :     {
    2591        8344 :         memcpy(FlushInfo->pBlockToBeSaved,
    2592        8344 :                (void *)((char *)FlushInfo->pBlockWhereToSaveOrRead +
    2593        8344 :                         FlushInfo->CurrentOffset),
    2594             :                FlushInfo->SizeOfBlockToBeSaved);
    2595             :     }
    2596        8344 :     FlushInfo->CurrentOffset += FlushInfo->SizeOfBlockToBeSaved;
    2597             : 
    2598        8344 :     return 0;
    2599             : }
    2600             : 
    2601             : // Appends a block of data to a buffer in memory, which is
    2602             : // used for later flushing to disk.
    2603        5592 : int MMAppendBlockToBuffer(struct MM_FLUSH_INFO *FlushInfo)
    2604             : {
    2605        5592 :     if (FlushInfo->SizeOfBlockToBeSaved)
    2606             :     {
    2607             :         // If all the bloc itself does not fit to the buffer,
    2608             :         // then all the block is written directly to the disk
    2609        4870 :         if (FlushInfo->nNumBytes == 0 &&
    2610         696 :             FlushInfo->SizeOfBlockToBeSaved >= FlushInfo->nBlockSize)
    2611             :         {
    2612           0 :             if (MMFlushToDisk(FlushInfo))
    2613           0 :                 return 1;
    2614           0 :             return 0;
    2615             :         }
    2616             : 
    2617             :         // There is space in FlushInfo->pBlockWhereToSaveOrRead?
    2618        4870 :         if (FlushInfo->nNumBytes + FlushInfo->SizeOfBlockToBeSaved <=
    2619        4870 :             FlushInfo->nBlockSize)
    2620             :         {
    2621        4870 :             if (FlushInfo->pBlockToBeSaved)
    2622             :             {
    2623        4549 :                 memcpy((void *)((char *)FlushInfo->pBlockWhereToSaveOrRead +
    2624        4549 :                                 FlushInfo->nNumBytes),
    2625        4549 :                        FlushInfo->pBlockToBeSaved,
    2626             :                        FlushInfo->SizeOfBlockToBeSaved);
    2627             :             }
    2628             :             else  // Add zero characters
    2629             :             {
    2630         321 :                 char zero_caracters[8] = {0, 0, 0, 0, 0, 0, 0, 0};
    2631         321 :                 memcpy((char *)FlushInfo->pBlockWhereToSaveOrRead +
    2632         321 :                            FlushInfo->nNumBytes,
    2633             :                        zero_caracters, FlushInfo->SizeOfBlockToBeSaved);
    2634             :             }
    2635             : 
    2636        4870 :             FlushInfo->nNumBytes += FlushInfo->SizeOfBlockToBeSaved;
    2637             :         }
    2638             :         else
    2639             :         {
    2640             :             // Empty the buffer
    2641           0 :             if (MMFlushToDisk(FlushInfo))
    2642           0 :                 return 1;
    2643             :             // Append the pendant bytes
    2644           0 :             if (MMAppendBlockToBuffer(FlushInfo))
    2645           0 :                 return 1;
    2646             :         }
    2647        4870 :         return 0;
    2648             :     }
    2649             :     // Just flush to the disc.
    2650         722 :     return MMFlushToDisk(FlushInfo);
    2651             : }
    2652             : 
    2653             : // Copy the contents of a temporary file to a final file.
    2654             : // Used everywhere when closing layers.
    2655         236 : int MMMoveFromFileToFile(VSILFILE *pSrcFile, VSILFILE *pDestFile,
    2656             :                          MM_FILE_OFFSET *pnOffset)
    2657             : {
    2658         236 :     size_t bufferSize = 1024 * 1024;  // 1 MB buffer;
    2659             :     unsigned char *buffer;
    2660             :     size_t bytesRead, bytesWritten;
    2661             : 
    2662         236 :     if (!pSrcFile || !pDestFile || !pnOffset)
    2663           0 :         return 0;
    2664             : 
    2665         236 :     buffer = (unsigned char *)VSICalloc(1, bufferSize);
    2666             : 
    2667         236 :     if (!buffer)
    2668           0 :         return 1;
    2669             : 
    2670         236 :     VSIFSeekL(pSrcFile, 0, SEEK_SET);
    2671         236 :     VSIFSeekL(pDestFile, *pnOffset, SEEK_SET);
    2672         472 :     while ((bytesRead = VSIFReadL(buffer, sizeof(unsigned char), bufferSize,
    2673             :                                   pSrcFile)) > 0)
    2674             :     {
    2675             :         bytesWritten =
    2676         236 :             VSIFWriteL(buffer, sizeof(unsigned char), bytesRead, pDestFile);
    2677         236 :         if (bytesWritten != bytesRead)
    2678             :         {
    2679           0 :             VSIFree(buffer);
    2680           0 :             return 1;
    2681             :         }
    2682         236 :         (*pnOffset) += bytesWritten;
    2683             :     }
    2684         236 :     VSIFree(buffer);
    2685         236 :     return 0;
    2686             : }
    2687             : 
    2688             : /* -------------------------------------------------------------------- */
    2689             : /*      Layer: Offsets and variables types managing                     */
    2690             : /* -------------------------------------------------------------------- */
    2691             : 
    2692             : // Alineation described in format documents.
    2693         192 : static void MMGetOffsetAlignedTo8(MM_FILE_OFFSET *Offset)
    2694             : {
    2695             :     MM_FILE_OFFSET reajust;
    2696             : 
    2697         192 :     if ((*Offset) % 8L)
    2698             :     {
    2699         170 :         reajust = 8 - ((*Offset) % 8L);
    2700         170 :         (*Offset) += reajust;
    2701             :     }
    2702         192 : }
    2703             : 
    2704             : // Reading integers depending on the version being read.
    2705        2821 : int MMReadGUInt64DependingOnVersion(struct MiraMonVectLayerInfo *hMiraMonLayer,
    2706             :                                     struct MM_FLUSH_INFO *FlushInfo,
    2707             :                                     GUInt64 *pnUI64)
    2708             : {
    2709             :     uint32_t nUL32;
    2710             : 
    2711        2821 :     if (!hMiraMonLayer)
    2712           0 :         return 1;
    2713             : 
    2714        2821 :     if (hMiraMonLayer->LayerVersion == MM_32BITS_VERSION)
    2715             :     {
    2716        2743 :         FlushInfo->pBlockToBeSaved = (void *)&nUL32;
    2717        2743 :         FlushInfo->SizeOfBlockToBeSaved = sizeof(nUL32);
    2718        2743 :         if (MMReadBlockFromBuffer(FlushInfo))
    2719             :         {
    2720           0 :             FlushInfo->pBlockToBeSaved = nullptr;
    2721           0 :             return 1;
    2722             :         }
    2723        2743 :         *pnUI64 = (GUInt64)nUL32;
    2724             :     }
    2725             :     else
    2726             :     {
    2727          78 :         FlushInfo->pBlockToBeSaved = (void *)pnUI64;
    2728          78 :         FlushInfo->SizeOfBlockToBeSaved = sizeof(*pnUI64);
    2729          78 :         if (MMReadBlockFromBuffer(FlushInfo))
    2730             :         {
    2731           0 :             FlushInfo->pBlockToBeSaved = nullptr;
    2732           0 :             return 1;
    2733             :         }
    2734             :     }
    2735        2821 :     FlushInfo->pBlockToBeSaved = nullptr;
    2736        2821 :     return 0;
    2737             : }
    2738             : 
    2739             : // Reading offsets depending on the version is being read.
    2740         744 : int MMReadOffsetDependingOnVersion(struct MiraMonVectLayerInfo *hMiraMonLayer,
    2741             :                                    struct MM_FLUSH_INFO *FlushInfo,
    2742             :                                    MM_FILE_OFFSET *pnUI64)
    2743             : {
    2744             :     uint32_t nUL32;
    2745             : 
    2746         744 :     if (!hMiraMonLayer)
    2747           0 :         return 1;
    2748             : 
    2749         744 :     if (hMiraMonLayer->LayerVersion == MM_32BITS_VERSION)
    2750             :     {
    2751         722 :         FlushInfo->pBlockToBeSaved = (void *)&nUL32;
    2752         722 :         FlushInfo->SizeOfBlockToBeSaved = sizeof(nUL32);
    2753         722 :         if (MMReadBlockFromBuffer(FlushInfo))
    2754             :         {
    2755           0 :             FlushInfo->pBlockToBeSaved = nullptr;
    2756           0 :             return 1;
    2757             :         }
    2758         722 :         *pnUI64 = (MM_FILE_OFFSET)nUL32;
    2759             :     }
    2760             :     else
    2761             :     {
    2762          22 :         FlushInfo->pBlockToBeSaved = (void *)pnUI64;
    2763          22 :         FlushInfo->SizeOfBlockToBeSaved = sizeof(*pnUI64);
    2764          22 :         if (MMReadBlockFromBuffer(FlushInfo))
    2765             :         {
    2766           0 :             FlushInfo->pBlockToBeSaved = nullptr;
    2767           0 :             return 1;
    2768             :         }
    2769             :     }
    2770         744 :     FlushInfo->pBlockToBeSaved = nullptr;
    2771         744 :     return 0;
    2772             : }
    2773             : 
    2774             : // Appending integers depending on the version.
    2775        1219 : int MMAppendIntegerDependingOnVersion(
    2776             :     struct MiraMonVectLayerInfo *hMiraMonLayer, struct MM_FLUSH_INFO *FlushInfo,
    2777             :     uint32_t *nUL32, GUInt64 nUI64)
    2778             : {
    2779             :     int result;
    2780             : 
    2781        1219 :     if (!hMiraMonLayer)
    2782           0 :         return 1;
    2783             : 
    2784        1219 :     if (hMiraMonLayer->LayerVersion == MM_32BITS_VERSION)
    2785             :     {
    2786        1069 :         *nUL32 = (uint32_t)nUI64;
    2787        1069 :         FlushInfo->SizeOfBlockToBeSaved = sizeof(*nUL32);
    2788        1069 :         hMiraMonLayer->OffsetCheck += FlushInfo->SizeOfBlockToBeSaved;
    2789        1069 :         FlushInfo->pBlockToBeSaved = (void *)nUL32;
    2790             :     }
    2791             :     else
    2792             :     {
    2793         150 :         FlushInfo->SizeOfBlockToBeSaved = sizeof(nUI64);
    2794         150 :         hMiraMonLayer->OffsetCheck += FlushInfo->SizeOfBlockToBeSaved;
    2795         150 :         FlushInfo->pBlockToBeSaved = (void *)&nUI64;
    2796             :     }
    2797        1219 :     result = MMAppendBlockToBuffer(FlushInfo);
    2798        1219 :     FlushInfo->pBlockToBeSaved = nullptr;
    2799        1219 :     return result;
    2800             : }
    2801             : 
    2802             : /* -------------------------------------------------------------------- */
    2803             : /*      Layer: Reading and writing layer sections                       */
    2804             : /*      This code follows the specifications of the following document: */
    2805             : /*             https://www.miramon.cat/new_note/eng/notes/   \          */
    2806             : /*              FormatFitxersTopologicsMiraMon.pdf                      */
    2807             : /* -------------------------------------------------------------------- */
    2808          69 : int MMReadAHArcSection(struct MiraMonVectLayerInfo *hMiraMonLayer)
    2809             : {
    2810             :     MM_INTERNAL_FID iElem, nElem;
    2811             :     struct MM_FLUSH_INFO FlushTMP;
    2812          69 :     char *pBuffer = nullptr;
    2813             :     MM_FILE_OFFSET nBlockSize;
    2814             :     struct MiraMonArcLayer *pMMArcLayer;
    2815             :     MM_N_VERTICES_TYPE nElementCount;
    2816             : 
    2817          69 :     if (!hMiraMonLayer)
    2818           0 :         return 1;
    2819             : 
    2820          69 :     if (hMiraMonLayer->bIsPolygon)
    2821             :     {
    2822          41 :         pMMArcLayer = &hMiraMonLayer->MMPolygon.MMArc;
    2823          41 :         nElem = hMiraMonLayer->MMPolygon.TopArcHeader.nElemCount;
    2824             :     }
    2825             :     else
    2826             :     {
    2827          28 :         pMMArcLayer = &hMiraMonLayer->MMArc;
    2828          28 :         nElem = hMiraMonLayer->TopHeader.nElemCount;
    2829             :     }
    2830             : 
    2831          69 :     if (MMCheckSize_t(nElem, pMMArcLayer->nSizeArcHeader))
    2832             :     {
    2833           0 :         return 1;
    2834             :     }
    2835             : 
    2836          69 :     nBlockSize = nElem * (pMMArcLayer->nSizeArcHeader);
    2837             : 
    2838          69 :     if (MMInitFlush(&FlushTMP, pMMArcLayer->pF, nBlockSize, &pBuffer,
    2839          69 :                     hMiraMonLayer->nHeaderDiskSize, 0))
    2840             :     {
    2841           0 :         if (pBuffer)
    2842           0 :             VSIFree(pBuffer);
    2843           0 :         return 1;
    2844             :     }
    2845          69 :     FlushTMP.pBlockWhereToSaveOrRead = (void *)pBuffer;
    2846          69 :     if (MMReadFlush(&FlushTMP))
    2847             :     {
    2848           0 :         if (pBuffer)
    2849           0 :             VSIFree(pBuffer);
    2850           0 :         return 1;
    2851             :     }
    2852             : 
    2853         343 :     for (iElem = 0; iElem < nElem; iElem++)
    2854             :     {
    2855             :         // Bounding box
    2856         274 :         FlushTMP.pBlockToBeSaved =
    2857         274 :             (void *)&(pMMArcLayer->pArcHeader[iElem].dfBB.dfMinX);
    2858         274 :         FlushTMP.SizeOfBlockToBeSaved =
    2859             :             sizeof(pMMArcLayer->pArcHeader[iElem].dfBB.dfMinX);
    2860         274 :         if (MMReadBlockFromBuffer(&FlushTMP))
    2861             :         {
    2862           0 :             if (pBuffer)
    2863           0 :                 VSIFree(pBuffer);
    2864           0 :             return 1;
    2865             :         }
    2866         274 :         FlushTMP.pBlockToBeSaved =
    2867         274 :             (void *)&pMMArcLayer->pArcHeader[iElem].dfBB.dfMaxX;
    2868         274 :         FlushTMP.SizeOfBlockToBeSaved =
    2869             :             sizeof(pMMArcLayer->pArcHeader[iElem].dfBB.dfMaxX);
    2870         274 :         if (MMReadBlockFromBuffer(&FlushTMP))
    2871             :         {
    2872           0 :             if (pBuffer)
    2873           0 :                 VSIFree(pBuffer);
    2874           0 :             return 1;
    2875             :         }
    2876         274 :         FlushTMP.pBlockToBeSaved =
    2877         274 :             (void *)&pMMArcLayer->pArcHeader[iElem].dfBB.dfMinY;
    2878         274 :         FlushTMP.SizeOfBlockToBeSaved =
    2879             :             sizeof(pMMArcLayer->pArcHeader[iElem].dfBB.dfMinY);
    2880         274 :         if (MMReadBlockFromBuffer(&FlushTMP))
    2881             :         {
    2882           0 :             if (pBuffer)
    2883           0 :                 VSIFree(pBuffer);
    2884           0 :             return 1;
    2885             :         }
    2886         274 :         FlushTMP.pBlockToBeSaved =
    2887         274 :             (void *)&pMMArcLayer->pArcHeader[iElem].dfBB.dfMaxY;
    2888         274 :         FlushTMP.SizeOfBlockToBeSaved =
    2889             :             sizeof(pMMArcLayer->pArcHeader[iElem].dfBB.dfMaxY);
    2890         274 :         if (MMReadBlockFromBuffer(&FlushTMP))
    2891             :         {
    2892           0 :             if (pBuffer)
    2893           0 :                 VSIFree(pBuffer);
    2894           0 :             return 1;
    2895             :         }
    2896             : 
    2897             :         // Element count: number of vertices of the arc
    2898         274 :         nElementCount = pMMArcLayer->pArcHeader[iElem].nElemCount;
    2899         274 :         if (MMReadGUInt64DependingOnVersion(hMiraMonLayer, &FlushTMP,
    2900             :                                             &nElementCount))
    2901             :         {
    2902           0 :             if (pBuffer)
    2903           0 :                 VSIFree(pBuffer);
    2904           0 :             return 1;
    2905             :         }
    2906         274 :         pMMArcLayer->pArcHeader[iElem].nElemCount = nElementCount;
    2907             : 
    2908             :         // Offset: offset of the first vertice of the arc
    2909         274 :         if (MMReadOffsetDependingOnVersion(
    2910             :                 hMiraMonLayer, &FlushTMP,
    2911         274 :                 &pMMArcLayer->pArcHeader[iElem].nOffset))
    2912             :         {
    2913           0 :             if (pBuffer)
    2914           0 :                 VSIFree(pBuffer);
    2915           0 :             return 1;
    2916             :         }
    2917             :         // First node: first node of the arc
    2918         274 :         if (MMReadGUInt64DependingOnVersion(
    2919             :                 hMiraMonLayer, &FlushTMP,
    2920         274 :                 &pMMArcLayer->pArcHeader[iElem].nFirstIdNode))
    2921             :         {
    2922           0 :             if (pBuffer)
    2923           0 :                 VSIFree(pBuffer);
    2924           0 :             return 1;
    2925             :         }
    2926             :         // Last node: first node of the arc
    2927         274 :         if (MMReadGUInt64DependingOnVersion(
    2928             :                 hMiraMonLayer, &FlushTMP,
    2929         274 :                 &pMMArcLayer->pArcHeader[iElem].nLastIdNode))
    2930             :         {
    2931           0 :             if (pBuffer)
    2932           0 :                 VSIFree(pBuffer);
    2933           0 :             return 1;
    2934             :         }
    2935             :         // Length of the arc
    2936         274 :         FlushTMP.pBlockToBeSaved =
    2937         274 :             (void *)&pMMArcLayer->pArcHeader[iElem].dfLength;
    2938         274 :         FlushTMP.SizeOfBlockToBeSaved =
    2939             :             sizeof(pMMArcLayer->pArcHeader[iElem].dfLength);
    2940         274 :         if (MMReadBlockFromBuffer(&FlushTMP))
    2941             :         {
    2942           0 :             if (pBuffer)
    2943           0 :                 VSIFree(pBuffer);
    2944           0 :             return 1;
    2945             :         }
    2946             :     }
    2947             : 
    2948          69 :     if (pBuffer)
    2949          69 :         VSIFree(pBuffer);
    2950          69 :     return 0;
    2951             : }
    2952             : 
    2953          58 : int MMWriteAHArcSection(struct MiraMonVectLayerInfo *hMiraMonLayer,
    2954             :                         MM_FILE_OFFSET DiskOffset)
    2955             : {
    2956             :     MM_INTERNAL_FID iElem;
    2957             :     struct MM_FLUSH_INFO FlushTMP;
    2958          58 :     char *pBuffer = nullptr;
    2959             :     uint32_t nUL32;
    2960             :     MM_FILE_OFFSET nOffsetDiff;
    2961             :     struct MiraMonArcLayer *pMMArcLayer;
    2962             : 
    2963          58 :     if (!hMiraMonLayer)
    2964           0 :         return 1;
    2965             : 
    2966          58 :     if (hMiraMonLayer->bIsPolygon)
    2967          27 :         pMMArcLayer = &hMiraMonLayer->MMPolygon.MMArc;
    2968             :     else
    2969          31 :         pMMArcLayer = &hMiraMonLayer->MMArc;
    2970             : 
    2971          58 :     nOffsetDiff =
    2972          58 :         hMiraMonLayer->nHeaderDiskSize +
    2973          58 :         hMiraMonLayer->nFinalElemCount * (pMMArcLayer->nSizeArcHeader);
    2974             : 
    2975          58 :     if (MMInitFlush(&FlushTMP, pMMArcLayer->pF, MM_1MB, &pBuffer, DiskOffset,
    2976             :                     0))
    2977             :     {
    2978           0 :         if (pBuffer)
    2979           0 :             VSIFree(pBuffer);
    2980           0 :         return 1;
    2981             :     }
    2982             : 
    2983          58 :     FlushTMP.pBlockWhereToSaveOrRead = (void *)pBuffer;
    2984         160 :     for (iElem = 0; iElem < hMiraMonLayer->nFinalElemCount; iElem++)
    2985             :     {
    2986             :         // Bounding box
    2987         102 :         FlushTMP.SizeOfBlockToBeSaved =
    2988             :             sizeof(pMMArcLayer->pArcHeader[iElem].dfBB.dfMinX);
    2989         102 :         FlushTMP.pBlockToBeSaved =
    2990         102 :             (void *)&pMMArcLayer->pArcHeader[iElem].dfBB.dfMinX;
    2991         102 :         hMiraMonLayer->OffsetCheck += FlushTMP.SizeOfBlockToBeSaved;
    2992         102 :         if (MMAppendBlockToBuffer(&FlushTMP))
    2993             :         {
    2994           0 :             if (pBuffer)
    2995           0 :                 VSIFree(pBuffer);
    2996           0 :             return 1;
    2997             :         }
    2998         102 :         FlushTMP.pBlockToBeSaved =
    2999         102 :             (void *)&pMMArcLayer->pArcHeader[iElem].dfBB.dfMaxX;
    3000         102 :         hMiraMonLayer->OffsetCheck += FlushTMP.SizeOfBlockToBeSaved;
    3001         102 :         if (MMAppendBlockToBuffer(&FlushTMP))
    3002             :         {
    3003           0 :             if (pBuffer)
    3004           0 :                 VSIFree(pBuffer);
    3005           0 :             return 1;
    3006             :         }
    3007         102 :         FlushTMP.pBlockToBeSaved =
    3008         102 :             (void *)&pMMArcLayer->pArcHeader[iElem].dfBB.dfMinY;
    3009         102 :         hMiraMonLayer->OffsetCheck += FlushTMP.SizeOfBlockToBeSaved;
    3010         102 :         if (MMAppendBlockToBuffer(&FlushTMP))
    3011             :         {
    3012           0 :             if (pBuffer)
    3013           0 :                 VSIFree(pBuffer);
    3014           0 :             return 1;
    3015             :         }
    3016         102 :         FlushTMP.pBlockToBeSaved =
    3017         102 :             (void *)&pMMArcLayer->pArcHeader[iElem].dfBB.dfMaxY;
    3018         102 :         hMiraMonLayer->OffsetCheck += FlushTMP.SizeOfBlockToBeSaved;
    3019         102 :         if (MMAppendBlockToBuffer(&FlushTMP))
    3020             :         {
    3021           0 :             if (pBuffer)
    3022           0 :                 VSIFree(pBuffer);
    3023           0 :             return 1;
    3024             :         }
    3025             : 
    3026             :         // Element count: number of vertices of the arc
    3027         102 :         if (MMAppendIntegerDependingOnVersion(
    3028             :                 hMiraMonLayer, &FlushTMP, &nUL32,
    3029         102 :                 pMMArcLayer->pArcHeader[iElem].nElemCount))
    3030             :         {
    3031           0 :             if (pBuffer)
    3032           0 :                 VSIFree(pBuffer);
    3033           0 :             return 1;
    3034             :         }
    3035             : 
    3036             :         // Offset: offset of the first vertice of the arc
    3037         102 :         if (MMAppendIntegerDependingOnVersion(
    3038             :                 hMiraMonLayer, &FlushTMP, &nUL32,
    3039         102 :                 pMMArcLayer->pArcHeader[iElem].nOffset + nOffsetDiff))
    3040             :         {
    3041           0 :             if (pBuffer)
    3042           0 :                 VSIFree(pBuffer);
    3043           0 :             return 1;
    3044             :         }
    3045             :         // First node: first node of the arc
    3046         102 :         if (MMAppendIntegerDependingOnVersion(
    3047             :                 hMiraMonLayer, &FlushTMP, &nUL32,
    3048         102 :                 pMMArcLayer->pArcHeader[iElem].nFirstIdNode))
    3049             :         {
    3050           0 :             if (pBuffer)
    3051           0 :                 VSIFree(pBuffer);
    3052           0 :             return 1;
    3053             :         }
    3054             :         // Last node: first node of the arc
    3055         102 :         if (MMAppendIntegerDependingOnVersion(
    3056             :                 hMiraMonLayer, &FlushTMP, &nUL32,
    3057         102 :                 pMMArcLayer->pArcHeader[iElem].nLastIdNode))
    3058             :         {
    3059           0 :             if (pBuffer)
    3060           0 :                 VSIFree(pBuffer);
    3061           0 :             return 1;
    3062             :         }
    3063             :         // Length of the arc
    3064         102 :         FlushTMP.SizeOfBlockToBeSaved =
    3065             :             sizeof(pMMArcLayer->pArcHeader[iElem].dfLength);
    3066         102 :         hMiraMonLayer->OffsetCheck += FlushTMP.SizeOfBlockToBeSaved;
    3067         102 :         FlushTMP.pBlockToBeSaved =
    3068         102 :             (void *)&pMMArcLayer->pArcHeader[iElem].dfLength;
    3069         102 :         if (MMAppendBlockToBuffer(&FlushTMP))
    3070             :         {
    3071           0 :             if (pBuffer)
    3072           0 :                 VSIFree(pBuffer);
    3073           0 :             return 1;
    3074             :         }
    3075             :     }
    3076          58 :     FlushTMP.SizeOfBlockToBeSaved = 0;
    3077          58 :     if (MMAppendBlockToBuffer(&FlushTMP))
    3078             :     {
    3079           0 :         if (pBuffer)
    3080           0 :             VSIFree(pBuffer);
    3081           0 :         return 1;
    3082             :     }
    3083             : 
    3084          58 :     if (pBuffer)
    3085          58 :         VSIFree(pBuffer);
    3086          58 :     return 0;
    3087             : }
    3088             : 
    3089             : #ifdef JUST_IN_CASE_WE_NEED_IT_SOMEDAY
    3090             : static int MMReadNHNodeSection(struct MiraMonVectLayerInfo *hMiraMonLayer)
    3091             : {
    3092             :     MM_INTERNAL_FID iElem, nElem;
    3093             :     struct MM_FLUSH_INFO FlushTMP;
    3094             :     char *pBuffer = nullptr;
    3095             :     MM_FILE_OFFSET nBlockSize;
    3096             :     struct MiraMonArcLayer *pMMArcLayer;
    3097             : 
    3098             :     if (hMiraMonLayer->bIsPolygon)
    3099             :         pMMArcLayer = &hMiraMonLayer->MMPolygon.MMArc;
    3100             :     else
    3101             :         pMMArcLayer = &hMiraMonLayer->MMArc;
    3102             : 
    3103             :     nElem = pMMArcLayer->TopNodeHeader.nElemCount;
    3104             : 
    3105             :     nBlockSize = nElem * pMMArcLayer->MMNode.nSizeNodeHeader;
    3106             : 
    3107             :     if (MMInitFlush(&FlushTMP, pMMArcLayer->MMNode.pF, nBlockSize, &pBuffer,
    3108             :                     hMiraMonLayer->nHeaderDiskSize, 0))
    3109             :     {
    3110             :         if (pBuffer)
    3111             :             VSIFree(pBuffer);
    3112             :         return 1;
    3113             :     }
    3114             : 
    3115             :     FlushTMP.pBlockWhereToSaveOrRead = (void *)pBuffer;
    3116             :     if (MMReadFlush(&FlushTMP))
    3117             :     {
    3118             :         if (pBuffer)
    3119             :             VSIFree(pBuffer);
    3120             :         return 1;
    3121             :     }
    3122             : 
    3123             :     for (iElem = 0; iElem < nElem; iElem++)
    3124             :     {
    3125             :         // Arcs count
    3126             :         FlushTMP.pBlockToBeSaved =
    3127             :             (void *)&pMMArcLayer->MMNode.pNodeHeader[iElem].nArcsCount;
    3128             :         FlushTMP.SizeOfBlockToBeSaved =
    3129             :             sizeof(pMMArcLayer->MMNode.pNodeHeader[iElem].nArcsCount);
    3130             :         if (MMReadBlockFromBuffer(&FlushTMP))
    3131             :         {
    3132             :             if (pBuffer)
    3133             :                 VSIFree(pBuffer);
    3134             :             return 1;
    3135             :         }
    3136             :         // Node type
    3137             :         FlushTMP.pBlockToBeSaved =
    3138             :             (void *)&pMMArcLayer->MMNode.pNodeHeader[iElem].cNodeType;
    3139             :         FlushTMP.SizeOfBlockToBeSaved =
    3140             :             sizeof(pMMArcLayer->MMNode.pNodeHeader[iElem].cNodeType);
    3141             :         if (MMReadBlockFromBuffer(&FlushTMP))
    3142             :         {
    3143             :             if (pBuffer)
    3144             :                 VSIFree(pBuffer);
    3145             :             return 1;
    3146             :         }
    3147             :         FlushTMP.SizeOfBlockToBeSaved = 1;
    3148             :         FlushTMP.pBlockToBeSaved = (void *)nullptr;
    3149             :         if (MMReadBlockFromBuffer(&FlushTMP))
    3150             :         {
    3151             :             if (pBuffer)
    3152             :                 VSIFree(pBuffer);
    3153             :             return 1;
    3154             :         }
    3155             : 
    3156             :         // Offset: offset of the first arc to the node
    3157             :         if (MMReadOffsetDependingOnVersion(
    3158             :                 hMiraMonLayer, &FlushTMP,
    3159             :                 &pMMArcLayer->MMNode.pNodeHeader[iElem].nOffset))
    3160             :         {
    3161             :             if (pBuffer)
    3162             :                 VSIFree(pBuffer);
    3163             :             return 1;
    3164             :         }
    3165             :     }
    3166             : 
    3167             :     if (pBuffer)
    3168             :         VSIFree(pBuffer);
    3169             :     return 0;
    3170             : }
    3171             : #endif  // JUST_IN_CASE_WE_NEED_IT_SOMEDAY
    3172             : 
    3173          58 : int MMWriteNHNodeSection(struct MiraMonVectLayerInfo *hMiraMonLayer,
    3174             :                          MM_FILE_OFFSET DiskOffset)
    3175             : {
    3176             :     MM_INTERNAL_FID iElem;
    3177             :     struct MM_FLUSH_INFO FlushTMP;
    3178          58 :     char *pBuffer = nullptr;
    3179             :     uint32_t nUL32;
    3180             :     MM_FILE_OFFSET nOffsetDiff;
    3181             :     struct MiraMonArcLayer *pMMArcLayer;
    3182             : 
    3183          58 :     if (!hMiraMonLayer)
    3184           0 :         return 1;
    3185             : 
    3186          58 :     if (hMiraMonLayer->bIsPolygon)
    3187          27 :         pMMArcLayer = &hMiraMonLayer->MMPolygon.MMArc;
    3188             :     else
    3189          31 :         pMMArcLayer = &hMiraMonLayer->MMArc;
    3190             : 
    3191          58 :     nOffsetDiff = hMiraMonLayer->nHeaderDiskSize +
    3192          58 :                   (pMMArcLayer->TopNodeHeader.nElemCount *
    3193          58 :                    pMMArcLayer->MMNode.nSizeNodeHeader);
    3194             : 
    3195          58 :     if (MMInitFlush(&FlushTMP, pMMArcLayer->MMNode.pF, MM_1MB, &pBuffer,
    3196             :                     DiskOffset, 0))
    3197             :     {
    3198           0 :         if (pBuffer)
    3199           0 :             VSIFree(pBuffer);
    3200           0 :         return 1;
    3201             :     }
    3202             : 
    3203          58 :     FlushTMP.pBlockWhereToSaveOrRead = (void *)pBuffer;
    3204         209 :     for (iElem = 0; iElem < pMMArcLayer->TopNodeHeader.nElemCount; iElem++)
    3205             :     {
    3206             :         // Arcs count
    3207         151 :         FlushTMP.SizeOfBlockToBeSaved =
    3208             :             sizeof(pMMArcLayer->MMNode.pNodeHeader[iElem].nArcsCount);
    3209         151 :         hMiraMonLayer->OffsetCheck += FlushTMP.SizeOfBlockToBeSaved;
    3210         151 :         FlushTMP.pBlockToBeSaved =
    3211         151 :             (void *)&pMMArcLayer->MMNode.pNodeHeader[iElem].nArcsCount;
    3212         151 :         if (MMAppendBlockToBuffer(&FlushTMP))
    3213             :         {
    3214           0 :             if (pBuffer)
    3215           0 :                 VSIFree(pBuffer);
    3216           0 :             return 1;
    3217             :         }
    3218             :         // Node type
    3219         151 :         FlushTMP.SizeOfBlockToBeSaved =
    3220             :             sizeof(pMMArcLayer->MMNode.pNodeHeader[iElem].cNodeType);
    3221         151 :         hMiraMonLayer->OffsetCheck += FlushTMP.SizeOfBlockToBeSaved;
    3222         151 :         FlushTMP.pBlockToBeSaved =
    3223         151 :             (void *)&pMMArcLayer->MMNode.pNodeHeader[iElem].cNodeType;
    3224         151 :         if (MMAppendBlockToBuffer(&FlushTMP))
    3225             :         {
    3226           0 :             if (pBuffer)
    3227           0 :                 VSIFree(pBuffer);
    3228           0 :             return 1;
    3229             :         }
    3230         151 :         FlushTMP.SizeOfBlockToBeSaved = 1;
    3231         151 :         hMiraMonLayer->OffsetCheck += FlushTMP.SizeOfBlockToBeSaved;
    3232         151 :         FlushTMP.pBlockToBeSaved = (void *)nullptr;
    3233         151 :         if (MMAppendBlockToBuffer(&FlushTMP))
    3234             :         {
    3235           0 :             if (pBuffer)
    3236           0 :                 VSIFree(pBuffer);
    3237           0 :             return 1;
    3238             :         }
    3239             : 
    3240             :         // Offset: offset of the first arc to the node
    3241         151 :         if (MMAppendIntegerDependingOnVersion(
    3242             :                 hMiraMonLayer, &FlushTMP, &nUL32,
    3243         151 :                 pMMArcLayer->MMNode.pNodeHeader[iElem].nOffset + nOffsetDiff))
    3244             :         {
    3245           0 :             if (pBuffer)
    3246           0 :                 VSIFree(pBuffer);
    3247           0 :             return 1;
    3248             :         }
    3249             :     }
    3250          58 :     FlushTMP.SizeOfBlockToBeSaved = 0;
    3251          58 :     if (MMAppendBlockToBuffer(&FlushTMP))
    3252             :     {
    3253           0 :         if (pBuffer)
    3254           0 :             VSIFree(pBuffer);
    3255           0 :         return 1;
    3256             :     }
    3257             : 
    3258          58 :     if (pBuffer)
    3259          58 :         VSIFree(pBuffer);
    3260          58 :     return 0;
    3261             : }
    3262             : 
    3263          44 : int MMReadPHPolygonSection(struct MiraMonVectLayerInfo *hMiraMonLayer)
    3264             : {
    3265             :     MM_INTERNAL_FID iElem;
    3266             :     struct MM_FLUSH_INFO FlushTMP;
    3267          44 :     char *pBuffer = nullptr;
    3268             :     MM_FILE_OFFSET nBlockSize;
    3269             :     struct MiraMonPolygonLayer *pMMPolygonLayer;
    3270             : 
    3271          44 :     if (!hMiraMonLayer)
    3272           0 :         return 1;
    3273             : 
    3274          44 :     pMMPolygonLayer = &hMiraMonLayer->MMPolygon;
    3275             : 
    3276          44 :     if (MMCheckSize_t(hMiraMonLayer->TopHeader.nElemCount,
    3277          88 :                       pMMPolygonLayer->nPHElementSize) ||
    3278          44 :         MMCheckSize_t(hMiraMonLayer->MMPolygon.TopArcHeader.nElemCount,
    3279          44 :                       hMiraMonLayer->MMPolygon.nPSElementSize))
    3280             :     {
    3281           0 :         return 1;
    3282             :     }
    3283          44 :     nBlockSize =
    3284          44 :         hMiraMonLayer->TopHeader.nElemCount * (pMMPolygonLayer->nPHElementSize);
    3285             : 
    3286          44 :     if (MMInitFlush(&FlushTMP, pMMPolygonLayer->pF, nBlockSize, &pBuffer,
    3287          44 :                     hMiraMonLayer->nHeaderDiskSize +
    3288          44 :                         (hMiraMonLayer->MMPolygon.TopArcHeader.nElemCount *
    3289          44 :                          hMiraMonLayer->MMPolygon.nPSElementSize),
    3290             :                     0))
    3291             :     {
    3292           0 :         if (pBuffer)
    3293           0 :             VSIFree(pBuffer);
    3294           0 :         return 1;
    3295             :     }
    3296          44 :     FlushTMP.pBlockWhereToSaveOrRead = (void *)pBuffer;
    3297          44 :     if (MMReadFlush(&FlushTMP))
    3298             :     {
    3299           0 :         if (pBuffer)
    3300           0 :             VSIFree(pBuffer);
    3301           0 :         return 1;
    3302             :     }
    3303             : 
    3304         175 :     for (iElem = 0; iElem < hMiraMonLayer->TopHeader.nElemCount; iElem++)
    3305             :     {
    3306             :         // Bounding box
    3307         131 :         FlushTMP.pBlockToBeSaved =
    3308         131 :             (void *)&(pMMPolygonLayer->pPolHeader[iElem].dfBB.dfMinX);
    3309         131 :         FlushTMP.SizeOfBlockToBeSaved =
    3310             :             sizeof(pMMPolygonLayer->pPolHeader[iElem].dfBB.dfMinX);
    3311         131 :         if (MMReadBlockFromBuffer(&FlushTMP))
    3312             :         {
    3313           0 :             if (pBuffer)
    3314           0 :                 VSIFree(pBuffer);
    3315           0 :             return 1;
    3316             :         }
    3317         131 :         FlushTMP.pBlockToBeSaved =
    3318         131 :             (void *)&pMMPolygonLayer->pPolHeader[iElem].dfBB.dfMaxX;
    3319         131 :         FlushTMP.SizeOfBlockToBeSaved =
    3320             :             sizeof(pMMPolygonLayer->pPolHeader[iElem].dfBB.dfMaxX);
    3321         131 :         if (MMReadBlockFromBuffer(&FlushTMP))
    3322             :         {
    3323           0 :             if (pBuffer)
    3324           0 :                 VSIFree(pBuffer);
    3325           0 :             return 1;
    3326             :         }
    3327         131 :         FlushTMP.pBlockToBeSaved =
    3328         131 :             (void *)&pMMPolygonLayer->pPolHeader[iElem].dfBB.dfMinY;
    3329         131 :         FlushTMP.SizeOfBlockToBeSaved =
    3330             :             sizeof(pMMPolygonLayer->pPolHeader[iElem].dfBB.dfMinY);
    3331         131 :         if (MMReadBlockFromBuffer(&FlushTMP))
    3332             :         {
    3333           0 :             if (pBuffer)
    3334           0 :                 VSIFree(pBuffer);
    3335           0 :             return 1;
    3336             :         }
    3337         131 :         FlushTMP.pBlockToBeSaved =
    3338         131 :             (void *)&pMMPolygonLayer->pPolHeader[iElem].dfBB.dfMaxY;
    3339         131 :         FlushTMP.SizeOfBlockToBeSaved =
    3340             :             sizeof(pMMPolygonLayer->pPolHeader[iElem].dfBB.dfMaxY);
    3341         131 :         if (MMReadBlockFromBuffer(&FlushTMP))
    3342             :         {
    3343           0 :             if (pBuffer)
    3344           0 :                 VSIFree(pBuffer);
    3345           0 :             return 1;
    3346             :         }
    3347             : 
    3348             :         // Arcs count: number of arcs of the polygon
    3349         131 :         if (MMReadGUInt64DependingOnVersion(
    3350             :                 hMiraMonLayer, &FlushTMP,
    3351         131 :                 &pMMPolygonLayer->pPolHeader[iElem].nArcsCount))
    3352             :         {
    3353           0 :             if (pBuffer)
    3354           0 :                 VSIFree(pBuffer);
    3355           0 :             return 1;
    3356             :         }
    3357             : 
    3358             :         // External arcs count: number of external arcs of the polygon
    3359         131 :         if (MMReadGUInt64DependingOnVersion(
    3360             :                 hMiraMonLayer, &FlushTMP,
    3361         131 :                 &pMMPolygonLayer->pPolHeader[iElem].nExternalRingsCount))
    3362             :         {
    3363           0 :             if (pBuffer)
    3364           0 :                 VSIFree(pBuffer);
    3365           0 :             return 1;
    3366             :         }
    3367             : 
    3368             :         // Rings count: number of rings of the polygon
    3369         131 :         if (MMReadGUInt64DependingOnVersion(
    3370             :                 hMiraMonLayer, &FlushTMP,
    3371         131 :                 &pMMPolygonLayer->pPolHeader[iElem].nRingsCount))
    3372             :         {
    3373           0 :             if (pBuffer)
    3374           0 :                 VSIFree(pBuffer);
    3375           0 :             return 1;
    3376             :         }
    3377             : 
    3378             :         // Offset: offset of the first vertex of the arc
    3379         131 :         if (MMReadOffsetDependingOnVersion(
    3380             :                 hMiraMonLayer, &FlushTMP,
    3381         131 :                 &pMMPolygonLayer->pPolHeader[iElem].nOffset))
    3382             :         {
    3383           0 :             if (pBuffer)
    3384           0 :                 VSIFree(pBuffer);
    3385           0 :             return 1;
    3386             :         }
    3387             : 
    3388             :         // Perimeter of the arc
    3389         131 :         FlushTMP.SizeOfBlockToBeSaved =
    3390             :             sizeof(pMMPolygonLayer->pPolHeader[iElem].dfPerimeter);
    3391         131 :         FlushTMP.pBlockToBeSaved =
    3392         131 :             (void *)&pMMPolygonLayer->pPolHeader[iElem].dfPerimeter;
    3393         131 :         if (MMReadBlockFromBuffer(&FlushTMP))
    3394             :         {
    3395           0 :             if (pBuffer)
    3396           0 :                 VSIFree(pBuffer);
    3397           0 :             return 1;
    3398             :         }
    3399             : 
    3400             :         // Area of the arc
    3401         131 :         FlushTMP.SizeOfBlockToBeSaved =
    3402             :             sizeof(pMMPolygonLayer->pPolHeader[iElem].dfArea);
    3403         131 :         FlushTMP.pBlockToBeSaved =
    3404         131 :             (void *)&pMMPolygonLayer->pPolHeader[iElem].dfArea;
    3405         131 :         if (MMReadBlockFromBuffer(&FlushTMP))
    3406             :         {
    3407           0 :             if (pBuffer)
    3408           0 :                 VSIFree(pBuffer);
    3409           0 :             return 1;
    3410             :         }
    3411             :     }
    3412             : 
    3413          44 :     if (pBuffer)
    3414          44 :         VSIFree(pBuffer);
    3415          44 :     return 0;
    3416             : }
    3417             : 
    3418          27 : int MMWritePHPolygonSection(struct MiraMonVectLayerInfo *hMiraMonLayer,
    3419             :                             MM_FILE_OFFSET DiskOffset)
    3420             : {
    3421             :     MM_INTERNAL_FID iElem;
    3422             :     struct MM_FLUSH_INFO FlushTMP;
    3423          27 :     char *pBuffer = nullptr;
    3424             :     uint32_t nUL32;
    3425             :     MM_FILE_OFFSET nOffsetDiff;
    3426             :     struct MiraMonPolygonLayer *pMMPolygonLayer;
    3427             : 
    3428          27 :     if (!hMiraMonLayer)
    3429           0 :         return 1;
    3430             : 
    3431          27 :     pMMPolygonLayer = &hMiraMonLayer->MMPolygon;
    3432             : 
    3433          27 :     if (!pMMPolygonLayer->pF)
    3434           0 :         return 0;
    3435             : 
    3436          27 :     if (!hMiraMonLayer->nFinalElemCount)
    3437           0 :         return 0;
    3438             : 
    3439          27 :     nOffsetDiff = DiskOffset + hMiraMonLayer->TopHeader.nElemCount *
    3440          27 :                                    (pMMPolygonLayer->nPHElementSize);
    3441             : 
    3442          27 :     if (MMInitFlush(&FlushTMP, pMMPolygonLayer->pF, MM_1MB, &pBuffer,
    3443             :                     DiskOffset, 0))
    3444             :     {
    3445           0 :         if (pBuffer)
    3446           0 :             VSIFree(pBuffer);
    3447           0 :         return 1;
    3448             :     }
    3449             : 
    3450          27 :     FlushTMP.pBlockWhereToSaveOrRead = (void *)pBuffer;
    3451          95 :     for (iElem = 0; iElem < hMiraMonLayer->nFinalElemCount; iElem++)
    3452             :     {
    3453             :         // Bounding box
    3454          68 :         FlushTMP.SizeOfBlockToBeSaved =
    3455             :             sizeof(pMMPolygonLayer->pPolHeader[iElem].dfBB.dfMinX);
    3456          68 :         FlushTMP.pBlockToBeSaved =
    3457          68 :             (void *)&pMMPolygonLayer->pPolHeader[iElem].dfBB.dfMinX;
    3458          68 :         hMiraMonLayer->OffsetCheck += FlushTMP.SizeOfBlockToBeSaved;
    3459          68 :         if (MMAppendBlockToBuffer(&FlushTMP))
    3460             :         {
    3461           0 :             if (pBuffer)
    3462           0 :                 VSIFree(pBuffer);
    3463           0 :             return 1;
    3464             :         }
    3465          68 :         FlushTMP.pBlockToBeSaved =
    3466          68 :             (void *)&pMMPolygonLayer->pPolHeader[iElem].dfBB.dfMaxX;
    3467          68 :         hMiraMonLayer->OffsetCheck += FlushTMP.SizeOfBlockToBeSaved;
    3468          68 :         if (MMAppendBlockToBuffer(&FlushTMP))
    3469             :         {
    3470           0 :             if (pBuffer)
    3471           0 :                 VSIFree(pBuffer);
    3472           0 :             return 1;
    3473             :         }
    3474          68 :         FlushTMP.pBlockToBeSaved =
    3475          68 :             (void *)&pMMPolygonLayer->pPolHeader[iElem].dfBB.dfMinY;
    3476          68 :         hMiraMonLayer->OffsetCheck += FlushTMP.SizeOfBlockToBeSaved;
    3477          68 :         if (MMAppendBlockToBuffer(&FlushTMP))
    3478             :         {
    3479           0 :             if (pBuffer)
    3480           0 :                 VSIFree(pBuffer);
    3481           0 :             return 1;
    3482             :         }
    3483          68 :         FlushTMP.pBlockToBeSaved =
    3484          68 :             (void *)&pMMPolygonLayer->pPolHeader[iElem].dfBB.dfMaxY;
    3485          68 :         hMiraMonLayer->OffsetCheck += FlushTMP.SizeOfBlockToBeSaved;
    3486          68 :         if (MMAppendBlockToBuffer(&FlushTMP))
    3487             :         {
    3488           0 :             if (pBuffer)
    3489           0 :                 VSIFree(pBuffer);
    3490           0 :             return 1;
    3491             :         }
    3492             : 
    3493             :         // Arcs count: number of the arcs of the polygon
    3494          68 :         if (MMAppendIntegerDependingOnVersion(
    3495             :                 hMiraMonLayer, &FlushTMP, &nUL32,
    3496          68 :                 pMMPolygonLayer->pPolHeader[iElem].nArcsCount))
    3497             :         {
    3498           0 :             if (pBuffer)
    3499           0 :                 VSIFree(pBuffer);
    3500           0 :             return 1;
    3501             :         }
    3502             : 
    3503             :         // External arcs count: number of external arcs of the polygon
    3504          68 :         if (MMAppendIntegerDependingOnVersion(
    3505             :                 hMiraMonLayer, &FlushTMP, &nUL32,
    3506          68 :                 pMMPolygonLayer->pPolHeader[iElem].nExternalRingsCount))
    3507             :         {
    3508           0 :             if (pBuffer)
    3509           0 :                 VSIFree(pBuffer);
    3510           0 :             return 1;
    3511             :         }
    3512             : 
    3513             :         // Rings count: number of rings of the polygon
    3514          68 :         if (MMAppendIntegerDependingOnVersion(
    3515             :                 hMiraMonLayer, &FlushTMP, &nUL32,
    3516          68 :                 pMMPolygonLayer->pPolHeader[iElem].nRingsCount))
    3517             :         {
    3518           0 :             if (pBuffer)
    3519           0 :                 VSIFree(pBuffer);
    3520           0 :             return 1;
    3521             :         }
    3522             : 
    3523             :         // Offset: offset of the first vertex of the arc
    3524          68 :         if (MMAppendIntegerDependingOnVersion(
    3525             :                 hMiraMonLayer, &FlushTMP, &nUL32,
    3526          68 :                 pMMPolygonLayer->pPolHeader[iElem].nOffset + nOffsetDiff))
    3527             :         {
    3528           0 :             if (pBuffer)
    3529           0 :                 VSIFree(pBuffer);
    3530           0 :             return 1;
    3531             :         }
    3532             : 
    3533             :         // Perimeter of the arc
    3534          68 :         FlushTMP.SizeOfBlockToBeSaved =
    3535             :             sizeof(pMMPolygonLayer->pPolHeader[iElem].dfPerimeter);
    3536          68 :         hMiraMonLayer->OffsetCheck += FlushTMP.SizeOfBlockToBeSaved;
    3537          68 :         FlushTMP.pBlockToBeSaved =
    3538          68 :             (void *)&pMMPolygonLayer->pPolHeader[iElem].dfPerimeter;
    3539          68 :         if (MMAppendBlockToBuffer(&FlushTMP))
    3540             :         {
    3541           0 :             if (pBuffer)
    3542           0 :                 VSIFree(pBuffer);
    3543           0 :             return 1;
    3544             :         }
    3545             : 
    3546             :         // Area of the arc
    3547          68 :         FlushTMP.SizeOfBlockToBeSaved =
    3548             :             sizeof(pMMPolygonLayer->pPolHeader[iElem].dfArea);
    3549          68 :         hMiraMonLayer->OffsetCheck += FlushTMP.SizeOfBlockToBeSaved;
    3550          68 :         FlushTMP.pBlockToBeSaved =
    3551          68 :             (void *)&pMMPolygonLayer->pPolHeader[iElem].dfArea;
    3552          68 :         if (MMAppendBlockToBuffer(&FlushTMP))
    3553             :         {
    3554           0 :             if (pBuffer)
    3555           0 :                 VSIFree(pBuffer);
    3556           0 :             return 1;
    3557             :         }
    3558             :     }
    3559          27 :     FlushTMP.SizeOfBlockToBeSaved = 0;
    3560          27 :     if (MMAppendBlockToBuffer(&FlushTMP))
    3561             :     {
    3562           0 :         if (pBuffer)
    3563           0 :             VSIFree(pBuffer);
    3564           0 :         return 1;
    3565             :     }
    3566             : 
    3567          27 :     if (pBuffer)
    3568          27 :         VSIFree(pBuffer);
    3569          27 :     return 0;
    3570             : }
    3571             : 
    3572             : /* -------------------------------------------------------------------- */
    3573             : /*      Feature Functions                                               */
    3574             : /* -------------------------------------------------------------------- */
    3575          84 : int MMInitFeature(struct MiraMonFeature *hMMFeature)
    3576             : {
    3577          84 :     memset(hMMFeature, 0, sizeof(*hMMFeature));
    3578             : 
    3579          84 :     hMMFeature->nMaxMRecords = MM_INIT_NUMBER_OF_RECORDS;
    3580          84 :     if (MMCheckSize_t(hMMFeature->nMaxMRecords,
    3581             :                       sizeof(*(hMMFeature->pRecords))))
    3582           0 :         return 1;
    3583             : 
    3584          84 :     if (!hMMFeature->nMaxMRecords)
    3585           0 :         return 0;  // No elements nothing to do.
    3586             : 
    3587          84 :     if ((hMMFeature->pRecords = VSICalloc((size_t)hMMFeature->nMaxMRecords,
    3588             :                                           sizeof(*(hMMFeature->pRecords)))) ==
    3589             :         nullptr)
    3590           0 :         return 1;
    3591             : 
    3592          84 :     hMMFeature->pRecords[0].nMaxField = MM_INIT_NUMBER_OF_FIELDS;
    3593          84 :     hMMFeature->pRecords[0].nNumField = 0;
    3594          84 :     if (MMCheckSize_t(hMMFeature->pRecords[0].nMaxField,
    3595             :                       sizeof(*(hMMFeature->pRecords[0].pField))))
    3596           0 :         return 1;
    3597          84 :     if (nullptr == (hMMFeature->pRecords[0].pField =
    3598          84 :                         VSICalloc((size_t)hMMFeature->pRecords[0].nMaxField,
    3599             :                                   sizeof(*(hMMFeature->pRecords[0].pField)))))
    3600           0 :         return 1;
    3601             : 
    3602          84 :     return 0;
    3603             : }
    3604             : 
    3605             : // Conserves all allocated memory but resets the information
    3606         565 : void MMResetFeatureGeometry(struct MiraMonFeature *hMMFeature)
    3607             : {
    3608         565 :     if (hMMFeature->pNCoordRing)
    3609             :     {
    3610         420 :         memset(hMMFeature->pNCoordRing, 0,
    3611         420 :                (size_t)hMMFeature->nMaxpNCoordRing *
    3612             :                    sizeof(*(hMMFeature->pNCoordRing)));
    3613             :     }
    3614         565 :     if (hMMFeature->pCoord)
    3615             :     {
    3616         420 :         memset(hMMFeature->pCoord, 0,
    3617         420 :                (size_t)hMMFeature->nMaxpCoord * sizeof(*(hMMFeature->pCoord)));
    3618             :     }
    3619         565 :     hMMFeature->nICoord = 0;
    3620         565 :     if (hMMFeature->pZCoord)
    3621             :     {
    3622         281 :         memset(hMMFeature->pZCoord, 0,
    3623         281 :                (size_t)hMMFeature->nMaxpZCoord *
    3624             :                    sizeof(*(hMMFeature->pZCoord)));
    3625             :     }
    3626         565 :     hMMFeature->nNRings = 0;
    3627         565 :     hMMFeature->nIRing = 0;
    3628             : 
    3629         565 :     if (hMMFeature->flag_VFG)
    3630             :     {
    3631         330 :         memset(hMMFeature->flag_VFG, 0,
    3632         330 :                (size_t)hMMFeature->nMaxVFG * sizeof(*(hMMFeature->flag_VFG)));
    3633             :     }
    3634         565 : }
    3635             : 
    3636             : // Preserves all allocated memory but initializes it to zero.
    3637         562 : void MMResetFeatureRecord(struct MiraMonFeature *hMMFeature)
    3638             : {
    3639             :     MM_EXT_DBF_N_MULTIPLE_RECORDS nIRecord;
    3640             :     MM_EXT_DBF_N_FIELDS nIField;
    3641             : 
    3642         562 :     if (!hMMFeature->pRecords)
    3643         352 :         return;
    3644             : 
    3645         450 :     for (nIRecord = 0; nIRecord < hMMFeature->nMaxMRecords; nIRecord++)
    3646             :     {
    3647         240 :         if (!hMMFeature->pRecords[nIRecord].pField)
    3648          25 :             continue;
    3649        4565 :         for (nIField = 0; nIField < hMMFeature->pRecords[nIRecord].nMaxField;
    3650        4350 :              nIField++)
    3651             :         {
    3652        4350 :             if (hMMFeature->pRecords[nIRecord].pField[nIField].pDinValue)
    3653         912 :                 *(hMMFeature->pRecords[nIRecord].pField[nIField].pDinValue) =
    3654             :                     '\0';
    3655        4350 :             hMMFeature->pRecords[nIRecord].pField[nIField].bIsValid = 0;
    3656             :         }
    3657         215 :         hMMFeature->pRecords[nIRecord].nNumField = 0;
    3658             :     }
    3659         210 :     hMMFeature->nNumMRecords = 0;
    3660             : }
    3661             : 
    3662             : // Destroys all allocated memory
    3663         205 : void MMDestroyFeature(struct MiraMonFeature *hMMFeature)
    3664             : {
    3665         205 :     if (hMMFeature->pCoord)
    3666             :     {
    3667          67 :         VSIFree(hMMFeature->pCoord);
    3668          67 :         hMMFeature->pCoord = nullptr;
    3669             :     }
    3670         205 :     if (hMMFeature->pZCoord)
    3671             :     {
    3672          67 :         VSIFree(hMMFeature->pZCoord);
    3673          67 :         hMMFeature->pZCoord = nullptr;
    3674             :     }
    3675         205 :     if (hMMFeature->pNCoordRing)
    3676             :     {
    3677          67 :         VSIFree(hMMFeature->pNCoordRing);
    3678          67 :         hMMFeature->pNCoordRing = nullptr;
    3679             :     }
    3680             : 
    3681         205 :     if (hMMFeature->flag_VFG)
    3682             :     {
    3683          27 :         VSIFree(hMMFeature->flag_VFG);
    3684          27 :         hMMFeature->flag_VFG = nullptr;
    3685             :     }
    3686             : 
    3687         205 :     if (hMMFeature->pRecords)
    3688             :     {
    3689             :         MM_EXT_DBF_N_MULTIPLE_RECORDS nIRecord;
    3690             :         MM_EXT_DBF_N_FIELDS nIField;
    3691             : 
    3692         262 :         for (nIRecord = 0; nIRecord < hMMFeature->nMaxMRecords; nIRecord++)
    3693             :         {
    3694         178 :             if (!hMMFeature->pRecords[nIRecord].pField)
    3695          75 :                 continue;
    3696         103 :             for (nIField = 0;
    3697        2293 :                  nIField < hMMFeature->pRecords[nIRecord].nMaxField; nIField++)
    3698             :             {
    3699        2190 :                 if (hMMFeature->pRecords[nIRecord].pField[nIField].pDinValue)
    3700         422 :                     VSIFree(hMMFeature->pRecords[nIRecord]
    3701         422 :                                 .pField[nIField]
    3702         422 :                                 .pDinValue);
    3703             :             }
    3704         103 :             VSIFree(hMMFeature->pRecords[nIRecord].pField);
    3705             :         }
    3706          84 :         VSIFree(hMMFeature->pRecords);
    3707          84 :         hMMFeature->pRecords = nullptr;
    3708             :     }
    3709             : 
    3710         205 :     hMMFeature->nNRings = 0;
    3711         205 :     hMMFeature->nNumMRecords = 0;
    3712         205 :     hMMFeature->nMaxMRecords = 0;
    3713         205 : }
    3714             : 
    3715             : // Creates a MiraMon polygon, multipolygon, or linestring (arc) feature.
    3716          90 : static int MMCreateFeaturePolOrArc(struct MiraMonVectLayerInfo *hMiraMonLayer,
    3717             :                                    struct MiraMonFeature *hMMFeature)
    3718             : {
    3719          90 :     double *pZ = nullptr;
    3720             :     struct MM_POINT_2D *pCoord, *pCoordReal;
    3721             :     MM_POLYGON_RINGS_COUNT nIPart;
    3722             :     MM_N_VERTICES_TYPE nIVertice;
    3723             :     double dtempx, dtempy;
    3724             :     MM_POLYGON_RINGS_COUNT nExternalRingsCount;
    3725          90 :     struct MM_PH *pCurrentPolHeader = nullptr;
    3726             :     struct MM_AH *pCurrentArcHeader;
    3727             :     // To access how many points have been stored in the last stringline
    3728          90 :     struct MM_AH *pLastArcHeader = nullptr;
    3729          90 :     struct MM_NH *pCurrentNodeHeader, *pCurrentNodeHeaderPlus1 = nullptr;
    3730             :     uint32_t UnsignedLongNumber;
    3731             :     struct MiraMonArcLayer *pMMArc;
    3732             :     struct MiraMonNodeLayer *pMMNode;
    3733             :     struct MM_TH *pArcTopHeader;
    3734             :     struct MM_TH *pNodeTopHeader;
    3735          90 :     char VFG = 0;
    3736             :     MM_FILE_OFFSET nOffsetTmp;
    3737          90 :     struct MM_ZD *pZDesc = nullptr;
    3738             :     struct MM_FLUSH_INFO *pFlushAL, *pFlushNL, *pFlushZL, *pFlushPS, *pFlushPAL;
    3739          90 :     MM_N_VERTICES_TYPE nPolVertices = 0;
    3740             :     MM_BOOLEAN bReverseArc;
    3741          90 :     int prevCoord = -1;
    3742          90 :     MM_BOOLEAN bPolZeroJustCreated = FALSE;
    3743             : 
    3744          90 :     if (!hMiraMonLayer)
    3745           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    3746             : 
    3747          90 :     if (!hMMFeature)
    3748           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    3749             : 
    3750             :     // Setting pointer to 3D structure (if exists).
    3751          90 :     if (hMiraMonLayer->TopHeader.bIs3d)
    3752          90 :         pZ = hMMFeature->pZCoord;
    3753             : 
    3754             :     // Setting pointers to arc/node structures.
    3755          90 :     if (hMiraMonLayer->bIsPolygon)
    3756             :     {
    3757          41 :         pMMArc = &hMiraMonLayer->MMPolygon.MMArc;
    3758          41 :         pArcTopHeader = &hMiraMonLayer->MMPolygon.TopArcHeader;
    3759             : 
    3760          41 :         pMMNode = &hMiraMonLayer->MMPolygon.MMArc.MMNode;
    3761          41 :         pNodeTopHeader = &hMiraMonLayer->MMPolygon.MMArc.TopNodeHeader;
    3762             :     }
    3763             :     else
    3764             :     {
    3765          49 :         pMMArc = &hMiraMonLayer->MMArc;
    3766          49 :         pArcTopHeader = &hMiraMonLayer->TopHeader;
    3767             : 
    3768          49 :         pMMNode = &hMiraMonLayer->MMArc.MMNode;
    3769          49 :         pNodeTopHeader = &hMiraMonLayer->MMArc.TopNodeHeader;
    3770             :     }
    3771             : 
    3772             :     // Setting pointers to polygon structures
    3773          90 :     if (hMiraMonLayer->bIsPolygon)
    3774             :     {
    3775          41 :         if (MMResizePolHeaderPointer(&hMiraMonLayer->MMPolygon.pPolHeader,
    3776          41 :                                      &hMiraMonLayer->MMPolygon.nMaxPolHeader,
    3777             :                                      hMiraMonLayer->TopHeader.nElemCount,
    3778             :                                      MM_INCR_NUMBER_OF_POLYGONS, 0))
    3779             :         {
    3780           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
    3781             :                      "Memory error in MiraMon "
    3782             :                      "driver (MMResizePolHeaderPointer())");
    3783           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    3784             :         }
    3785             : 
    3786          41 :         pCurrentPolHeader = hMiraMonLayer->MMPolygon.pPolHeader +
    3787          41 :                             hMiraMonLayer->TopHeader.nElemCount;
    3788          41 :         MMInitBoundingBox(&pCurrentPolHeader->dfBB);
    3789             : 
    3790          41 :         pCurrentPolHeader->dfPerimeter = 0;
    3791          41 :         pCurrentPolHeader->dfArea = 0L;
    3792             :     }
    3793             : 
    3794             :     // Setting flushes to all sections described in
    3795             :     // format specifications document.
    3796          90 :     pFlushAL = &pMMArc->FlushAL;
    3797          90 :     pFlushNL = &pMMNode->FlushNL;
    3798          90 :     pFlushZL = &pMMArc->pZSection.FlushZL;
    3799          90 :     pFlushPS = &hMiraMonLayer->MMPolygon.FlushPS;
    3800          90 :     pFlushPAL = &hMiraMonLayer->MMPolygon.FlushPAL;
    3801             : 
    3802          90 :     pFlushNL->pBlockWhereToSaveOrRead = (void *)pMMNode->pNL;
    3803          90 :     pFlushAL->pBlockWhereToSaveOrRead = (void *)pMMArc->pAL;
    3804          90 :     if (hMiraMonLayer->TopHeader.bIs3d)
    3805          90 :         pFlushZL->pBlockWhereToSaveOrRead = (void *)pMMArc->pZSection.pZL;
    3806          90 :     if (hMiraMonLayer->bIsPolygon)
    3807             :     {
    3808          41 :         pFlushPS->pBlockWhereToSaveOrRead =
    3809          41 :             (void *)hMiraMonLayer->MMPolygon.pPS;
    3810          41 :         pFlushPAL->pBlockWhereToSaveOrRead =
    3811          41 :             (void *)hMiraMonLayer->MMPolygon.pPAL;
    3812             :     }
    3813             : 
    3814             :     // Creation of the MiraMon extended database
    3815          90 :     if (!hMiraMonLayer->bIsPolygon)
    3816             :     {
    3817          49 :         if (hMiraMonLayer->TopHeader.nElemCount == 0)
    3818             :         {
    3819          31 :             CPLDebugOnly("MiraMon", "Creating MiraMon database");
    3820          31 :             if (MMCreateMMDB(hMiraMonLayer, hMMFeature->pCoord))
    3821           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    3822          31 :             CPLDebugOnly("MiraMon", "MiraMon database created. "
    3823             :                                     "Creating features...");
    3824             :         }
    3825             :     }
    3826             :     else
    3827             :     {  // Universal polygon has been created
    3828          41 :         if (hMiraMonLayer->TopHeader.nElemCount == 1)
    3829             :         {
    3830          27 :             CPLDebugOnly("MiraMon", "Creating MiraMon database");
    3831          27 :             if (MMCreateMMDB(hMiraMonLayer, hMMFeature->pCoord))
    3832           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    3833          27 :             CPLDebugOnly("MiraMon", "MiraMon database created. "
    3834             :                                     "Creating features...");
    3835             : 
    3836             :             // Universal polygon have a record with ID_GRAFIC=0 and blancs
    3837          27 :             if (MMAddPolygonRecordToMMDB(hMiraMonLayer, nullptr, 0, 0, nullptr))
    3838             :             {
    3839             :                 // Rare case where polygon zero creates the database
    3840             :                 // but some error occurs in the creation of the polygon zero.
    3841             :                 // The database must be destroyed and created again
    3842             :                 // next time the polygon zero is created.
    3843           0 :                 MMCloseMMBD_XP(hMiraMonLayer);
    3844           0 :                 MMDestroyMMDB(hMiraMonLayer);
    3845           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    3846             :             }
    3847          27 :             bPolZeroJustCreated = TRUE;
    3848             :         }
    3849             :     }
    3850             : 
    3851             :     // Checking if its possible continue writing the file due
    3852             :     // to version limitations.
    3853          90 :     if (hMiraMonLayer->LayerVersion == MM_32BITS_VERSION)
    3854             :     {
    3855             :         MM_FILE_OFFSET nNodeOffset, nArcOffset;
    3856             :         MM_INTERNAL_FID nArcElemCount, nNodeElemCount;
    3857          76 :         nNodeOffset = pFlushNL->TotalSavedBytes + pFlushNL->nNumBytes;
    3858          76 :         nArcOffset = pMMArc->nOffsetArc;
    3859             : 
    3860          76 :         nArcElemCount = pArcTopHeader->nElemCount;
    3861          76 :         nNodeElemCount = pNodeTopHeader->nElemCount;
    3862         164 :         for (nIPart = 0; nIPart < hMMFeature->nNRings; nIPart++,
    3863          88 :             nArcElemCount++,
    3864          88 :             nNodeElemCount += (hMiraMonLayer->bIsPolygon ? 1 : 2))
    3865             :         {
    3866             :             // There is space for the element that is going to be written?
    3867             :             // Polygon or arc
    3868          88 :             if (MMCheckVersionForFID(hMiraMonLayer,
    3869             :                                      hMiraMonLayer->TopHeader.nElemCount))
    3870             :             {
    3871           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
    3872             :                          "Error in MMCheckVersionForFID() (1)");
    3873           0 :                 return MM_STOP_WRITING_FEATURES;
    3874             :             }
    3875             : 
    3876             :             // Arc if there is no polygon
    3877          88 :             if (MMCheckVersionForFID(hMiraMonLayer, nArcElemCount))
    3878             :             {
    3879           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
    3880             :                          "Error in MMCheckVersionForFID() (2)");
    3881           0 :                 return MM_STOP_WRITING_FEATURES;
    3882             :             }
    3883             : 
    3884             :             // Nodes
    3885          88 :             if (MMCheckVersionForFID(hMiraMonLayer, nNodeElemCount))
    3886             :             {
    3887           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
    3888             :                          "Error in MMCheckVersionForFID() (3)");
    3889           0 :                 return MM_STOP_WRITING_FEATURES;
    3890             :             }
    3891             : 
    3892             :             // There is space for the last node(s) that is(are) going to be written?
    3893          88 :             if (!hMiraMonLayer->bIsPolygon)
    3894             :             {
    3895          41 :                 if (MMCheckVersionForFID(hMiraMonLayer, nNodeElemCount + 1))
    3896             :                 {
    3897           0 :                     CPLError(CE_Failure, CPLE_NotSupported,
    3898             :                              "Error in MMCheckVersionForFID() (4)");
    3899           0 :                     return MM_STOP_WRITING_FEATURES;
    3900             :                 }
    3901             :             }
    3902             : 
    3903             :             // Checking offsets
    3904             :             // AL: check the last point
    3905          88 :             if (MMCheckVersionOffset(hMiraMonLayer, nArcOffset))
    3906             :             {
    3907           0 :                 CPLDebugOnly("MiraMon", "Error in MMCheckVersionOffset() (0)");
    3908           0 :                 return MM_STOP_WRITING_FEATURES;
    3909             :             }
    3910             :             // Setting next offset
    3911          88 :             nArcOffset +=
    3912          88 :                 (hMMFeature->pNCoordRing[nIPart]) * pMMArc->nALElementSize;
    3913             : 
    3914             :             // NL: check the last node
    3915          88 :             if (hMiraMonLayer->bIsPolygon)
    3916          47 :                 nNodeOffset += (hMMFeature->nNRings) * MM_SIZE_OF_NL_32BITS;
    3917             :             else
    3918          41 :                 nNodeOffset += (2 * hMMFeature->nNRings) * MM_SIZE_OF_NL_32BITS;
    3919             : 
    3920          88 :             if (MMCheckVersionOffset(hMiraMonLayer, nNodeOffset))
    3921             :             {
    3922           0 :                 CPLDebugOnly("MiraMon", "Error in MMCheckVersionOffset() (1)");
    3923           0 :                 return MM_STOP_WRITING_FEATURES;
    3924             :             }
    3925             :             // Setting next offset
    3926          88 :             nNodeOffset += MM_SIZE_OF_NL_32BITS;
    3927             : 
    3928          88 :             if (!hMiraMonLayer->bIsPolygon)
    3929             :             {
    3930          41 :                 if (MMCheckVersionOffset(hMiraMonLayer, nNodeOffset))
    3931             :                 {
    3932           0 :                     CPLDebugOnly("MiraMon",
    3933             :                                  "Error in MMCheckVersionOffset() (2)");
    3934           0 :                     return MM_STOP_WRITING_FEATURES;
    3935             :                 }
    3936             :                 // Setting next offset
    3937          41 :                 nNodeOffset += MM_SIZE_OF_NL_32BITS;
    3938             :             }
    3939             : 
    3940             :             // Where 3D part is going to start
    3941          88 :             if (hMiraMonLayer->TopHeader.bIs3d)
    3942             :             {
    3943          88 :                 if (nArcElemCount == 0)
    3944             :                 {
    3945          54 :                     if (MMCheckVersionFor3DOffset(hMiraMonLayer,
    3946             :                                                   nArcElemCount + 1, 0, 0))
    3947           0 :                         return MM_STOP_WRITING_FEATURES;
    3948             :                 }
    3949             :                 else
    3950             :                 {
    3951          34 :                     pZDesc = pMMArc->pZSection.pZDescription;
    3952          34 :                     if (!pZDesc)
    3953             :                     {
    3954           0 :                         CPLError(CE_Failure, CPLE_ObjectNull,
    3955             :                                  "Error: pZDescription should not be nullptr");
    3956           0 :                         return MM_STOP_WRITING_FEATURES;
    3957             :                     }
    3958             : 
    3959          34 :                     if (pZDesc[nArcElemCount - 1].nZCount < 0)
    3960             :                     {
    3961             :                         // One altitude was written on last element
    3962          13 :                         if (MMCheckVersionFor3DOffset(
    3963             :                                 hMiraMonLayer, nArcElemCount + 1, nArcOffset,
    3964          13 :                                 pZDesc[nArcElemCount - 1].nOffsetZ +
    3965             :                                     sizeof(*pZ)))
    3966           0 :                             return MM_STOP_WRITING_FEATURES;
    3967             :                     }
    3968             :                     else
    3969             :                     {
    3970             :                         // One for each vertice altitude was written on last element
    3971          21 :                         if (MMCheckVersionFor3DOffset(
    3972             :                                 hMiraMonLayer, nArcElemCount + 1, nArcOffset,
    3973          21 :                                 pZDesc[nArcElemCount - 1].nOffsetZ +
    3974          21 :                                     sizeof(*pZ) * (pMMArc->pArcHeader +
    3975             :                                                    (nArcElemCount - 1))
    3976          21 :                                                       ->nElemCount))
    3977           0 :                             return MM_STOP_WRITING_FEATURES;
    3978             :                     }
    3979             :                 }
    3980             :             }
    3981             :         }
    3982             :     }
    3983             : 
    3984             :     // Going through parts of the feature.
    3985          90 :     nExternalRingsCount = 0;
    3986          90 :     pCoord = hMMFeature->pCoord;
    3987             : 
    3988          90 :     if (!pCoord)
    3989             :     {
    3990           0 :         if (bPolZeroJustCreated)
    3991             :         {
    3992             :             // Rare case where polygon zero creates the database
    3993             :             // but some error occurs in the creation of the polygon zero.
    3994             :             // The database must be destroyed and created again
    3995             :             // next time the polygon zero is created.
    3996           0 :             MMCloseMMBD_XP(hMiraMonLayer);
    3997           0 :             MMDestroyMMDB(hMiraMonLayer);
    3998             :         }
    3999           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    4000             :     }
    4001             : 
    4002             :     // Doing real job
    4003         192 :     for (nIPart = 0; nIPart < hMMFeature->nNRings; nIPart++,
    4004         102 :         pArcTopHeader->nElemCount++,
    4005         102 :         pNodeTopHeader->nElemCount += (hMiraMonLayer->bIsPolygon ? 1 : 2))
    4006             :     {
    4007             :         // Resize structures if necessary
    4008         102 :         if (MMResizeArcHeaderPointer(
    4009         102 :                 &pMMArc->pArcHeader, &pMMArc->nMaxArcHeader,
    4010         102 :                 pArcTopHeader->nElemCount + 1, MM_INCR_NUMBER_OF_ARCS, 0))
    4011             :         {
    4012           0 :             CPLDebugOnly("MiraMon", "Error in MMResizeArcHeaderPointer()");
    4013           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
    4014             :                      "Memory error in MiraMon "
    4015             :                      "driver (MMCreateFeaturePolOrArc())");
    4016           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    4017             :         }
    4018         102 :         if (MMResizeNodeHeaderPointer(
    4019         102 :                 &pMMNode->pNodeHeader, &pMMNode->nMaxNodeHeader,
    4020         102 :                 hMiraMonLayer->bIsPolygon ? pNodeTopHeader->nElemCount + 1
    4021          49 :                                           : pNodeTopHeader->nElemCount + 2,
    4022             :                 MM_INCR_NUMBER_OF_NODES, 0))
    4023             :         {
    4024           0 :             CPLDebugOnly("MiraMon", "Error in MMResizeNodeHeaderPointer()");
    4025           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
    4026             :                      "Memory error in MiraMon "
    4027             :                      "driver (MMCreateFeaturePolOrArc())");
    4028           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    4029             :         }
    4030             : 
    4031         102 :         if (hMiraMonLayer->TopHeader.bIs3d)
    4032             :         {
    4033         102 :             if (MMResizeZSectionDescrPointer(
    4034             :                     &pMMArc->pZSection.pZDescription,
    4035             :                     &pMMArc->pZSection.nMaxZDescription, pMMArc->nMaxArcHeader,
    4036             :                     MM_INCR_NUMBER_OF_ARCS, 0))
    4037             :             {
    4038           0 :                 CPLDebugOnly("MiraMon",
    4039             :                              "Error in MMResizeZSectionDescrPointer()");
    4040           0 :                 CPLError(CE_Failure, CPLE_OutOfMemory,
    4041             :                          "Memory error in MiraMon "
    4042             :                          "driver (MMCreateFeaturePolOrArc())");
    4043           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4044             :             }
    4045         102 :             pZDesc = pMMArc->pZSection.pZDescription;
    4046             :         }
    4047             : 
    4048             :         // Setting pointers to current headers
    4049         102 :         pCurrentArcHeader = pMMArc->pArcHeader + pArcTopHeader->nElemCount;
    4050         102 :         MMInitBoundingBox(&pCurrentArcHeader->dfBB);
    4051             : 
    4052         102 :         pCurrentNodeHeader = pMMNode->pNodeHeader + pNodeTopHeader->nElemCount;
    4053         102 :         if (!hMiraMonLayer->bIsPolygon)
    4054          49 :             pCurrentNodeHeaderPlus1 = pCurrentNodeHeader + 1;
    4055             : 
    4056             :         // Initializing feature information (section AH/PH)
    4057         102 :         pCurrentArcHeader->nElemCount = hMMFeature->pNCoordRing[nIPart];
    4058         102 :         pCurrentArcHeader->dfLength = 0.0;
    4059         102 :         pCurrentArcHeader->nOffset =
    4060         102 :             pFlushAL->TotalSavedBytes + pFlushAL->nNumBytes;
    4061             : 
    4062             :         // Dumping vertices and calculating stuff that
    4063             :         // MiraMon needs (longitude/perimeter, area)
    4064         102 :         bReverseArc = FALSE;
    4065         102 :         if (hMiraMonLayer->bIsPolygon)
    4066             :         {
    4067          53 :             VFG = hMMFeature->flag_VFG[nIPart];
    4068          53 :             bReverseArc = (VFG & MM_ROTATE_ARC) ? TRUE : FALSE;
    4069             :         }
    4070             : 
    4071         102 :         if (bReverseArc)
    4072             :         {
    4073           1 :             prevCoord = 1;  // to find previous coordinate
    4074           1 :             pCoordReal = pCoord + pCurrentArcHeader->nElemCount - 1;
    4075             :         }
    4076             :         else
    4077             :         {
    4078         101 :             prevCoord = -1;  // to find previous coordinate
    4079         101 :             pCoordReal = pCoord;
    4080             :         }
    4081             : 
    4082         572 :         for (nIVertice = 0; nIVertice < pCurrentArcHeader->nElemCount;
    4083         470 :              nIVertice++, (bReverseArc) ? pCoordReal-- : pCoordReal++)
    4084             :         {
    4085             :             // Writing the arc in the normal way
    4086         470 :             pFlushAL->SizeOfBlockToBeSaved = sizeof(pCoordReal->dfX);
    4087         470 :             pFlushAL->pBlockToBeSaved = (void *)&(pCoord + nIVertice)->dfX;
    4088         470 :             if (MMAppendBlockToBuffer(pFlushAL))
    4089             :             {
    4090           0 :                 CPLDebugOnly("MiraMon", "Error in MMAppendBlockToBuffer() (1)");
    4091           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4092             :             }
    4093             : 
    4094         470 :             pFlushAL->pBlockToBeSaved = (void *)&(pCoord + nIVertice)->dfY;
    4095         470 :             if (MMAppendBlockToBuffer(pFlushAL))
    4096             :             {
    4097           0 :                 CPLDebugOnly("MiraMon", "Error in MMAppendBlockToBuffer() (2)");
    4098           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4099             :             }
    4100             : 
    4101             :             // Calculating stuff using the inverse coordinates if it's needed
    4102         470 :             MMUpdateBoundingBoxXY(&pCurrentArcHeader->dfBB, pCoordReal);
    4103         470 :             if (nIVertice == 0 ||
    4104         368 :                 nIVertice == pCurrentArcHeader->nElemCount - 1)
    4105         204 :                 MMUpdateBoundingBoxXY(&pNodeTopHeader->hBB, pCoordReal);
    4106         470 :             if (nIVertice > 0)
    4107             :             {
    4108         368 :                 dtempx = pCoordReal->dfX - (pCoordReal + prevCoord)->dfX;
    4109         368 :                 dtempy = pCoordReal->dfY - (pCoordReal + prevCoord)->dfY;
    4110         368 :                 pCurrentArcHeader->dfLength +=
    4111         368 :                     sqrt(dtempx * dtempx + dtempy * dtempy);
    4112         368 :                 if (hMiraMonLayer->bIsPolygon && pCurrentPolHeader)
    4113             :                 {
    4114         262 :                     pCurrentPolHeader->dfArea +=
    4115         262 :                         (pCoordReal->dfX * (pCoordReal + prevCoord)->dfY -
    4116         262 :                          (pCoordReal + prevCoord)->dfX * pCoordReal->dfY);
    4117             :                 }
    4118             :             }
    4119             :         }
    4120         102 :         if (bReverseArc)
    4121           1 :             pCoord = pCoordReal + pCurrentArcHeader->nElemCount + 1;
    4122             :         else
    4123         101 :             pCoord += pCurrentArcHeader->nElemCount;
    4124             : 
    4125         102 :         nPolVertices += pCurrentArcHeader->nElemCount;
    4126             : 
    4127             :         // Updating bounding boxes
    4128         102 :         MMUpdateBoundingBox(&pArcTopHeader->hBB, &pCurrentArcHeader->dfBB);
    4129         102 :         if (hMiraMonLayer->bIsPolygon)
    4130          53 :             MMUpdateBoundingBox(&hMiraMonLayer->TopHeader.hBB,
    4131             :                                 &pCurrentArcHeader->dfBB);
    4132             : 
    4133         102 :         pMMArc->nOffsetArc +=
    4134         102 :             (pCurrentArcHeader->nElemCount) * pMMArc->nALElementSize;
    4135             : 
    4136         102 :         pCurrentArcHeader->nFirstIdNode = (2 * pArcTopHeader->nElemCount);
    4137         102 :         if (hMiraMonLayer->bIsPolygon)
    4138             :         {
    4139          53 :             pCurrentArcHeader->nFirstIdNode = pArcTopHeader->nElemCount;
    4140          53 :             pCurrentArcHeader->nLastIdNode = pArcTopHeader->nElemCount;
    4141             :         }
    4142             :         else
    4143             :         {
    4144          49 :             pCurrentArcHeader->nFirstIdNode = (2 * pArcTopHeader->nElemCount);
    4145          49 :             pCurrentArcHeader->nLastIdNode =
    4146          49 :                 (2 * pArcTopHeader->nElemCount + 1);
    4147             :         }
    4148         102 :         if (MMAddArcRecordToMMDB(hMiraMonLayer, hMMFeature,
    4149             :                                  pArcTopHeader->nElemCount, pCurrentArcHeader))
    4150             :         {
    4151           0 :             CPLDebugOnly("MiraMon", "Error in MMAddArcRecordToMMDB()");
    4152           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    4153             :         }
    4154             : 
    4155             :         // Node Stuff: writing NL section
    4156         102 :         pCurrentNodeHeader->nArcsCount = 1;
    4157         102 :         if (hMiraMonLayer->bIsPolygon)
    4158          53 :             pCurrentNodeHeader->cNodeType = MM_RING_NODE;
    4159             :         else
    4160          49 :             pCurrentNodeHeader->cNodeType = MM_FINAL_NODE;
    4161             : 
    4162         102 :         pCurrentNodeHeader->nOffset =
    4163         102 :             pFlushNL->TotalSavedBytes + pFlushNL->nNumBytes;
    4164         102 :         if (MMAppendIntegerDependingOnVersion(hMiraMonLayer, pFlushNL,
    4165             :                                               &UnsignedLongNumber,
    4166             :                                               pArcTopHeader->nElemCount))
    4167             :         {
    4168           0 :             CPLDebugOnly("MiraMon",
    4169             :                          "Error in MMAppendIntegerDependingOnVersion()");
    4170           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    4171             :         }
    4172             : 
    4173             :         // 8bytes alignment
    4174         102 :         nOffsetTmp = pFlushNL->TotalSavedBytes + pFlushNL->nNumBytes;
    4175         102 :         MMGetOffsetAlignedTo8(&nOffsetTmp);
    4176         102 :         if (nOffsetTmp != pFlushNL->TotalSavedBytes + pFlushNL->nNumBytes)
    4177             :         {
    4178          88 :             pFlushNL->SizeOfBlockToBeSaved =
    4179          88 :                 (size_t)(nOffsetTmp -
    4180          88 :                          (pFlushNL->TotalSavedBytes + pFlushNL->nNumBytes));
    4181          88 :             pFlushNL->pBlockToBeSaved = (void *)nullptr;
    4182          88 :             if (MMAppendBlockToBuffer(pFlushNL))
    4183             :             {
    4184           0 :                 CPLDebugOnly("MiraMon", "Error in MMAppendBlockToBuffer() (3)");
    4185           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4186             :             }
    4187             :         }
    4188         102 :         if (MMAddNodeRecordToMMDB(hMiraMonLayer, pNodeTopHeader->nElemCount,
    4189             :                                   pCurrentNodeHeader))
    4190             :         {
    4191           0 :             CPLDebugOnly("MiraMon", "Error in MMAddNodeRecordToMMDB()");
    4192           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    4193             :         }
    4194             : 
    4195         102 :         if (!hMiraMonLayer->bIsPolygon)
    4196             :         {
    4197          49 :             pCurrentNodeHeaderPlus1->nArcsCount = 1;
    4198          49 :             if (hMiraMonLayer->bIsPolygon)
    4199           0 :                 pCurrentNodeHeaderPlus1->cNodeType = MM_RING_NODE;
    4200             :             else
    4201          49 :                 pCurrentNodeHeaderPlus1->cNodeType = MM_FINAL_NODE;
    4202             : 
    4203          49 :             pCurrentNodeHeaderPlus1->nOffset =
    4204          49 :                 pFlushNL->TotalSavedBytes + pFlushNL->nNumBytes;
    4205             : 
    4206          49 :             if (MMAppendIntegerDependingOnVersion(hMiraMonLayer, pFlushNL,
    4207             :                                                   &UnsignedLongNumber,
    4208             :                                                   pArcTopHeader->nElemCount))
    4209             :             {
    4210           0 :                 CPLDebugOnly("MiraMon",
    4211             :                              "Error in MMAppendIntegerDependingOnVersion()");
    4212           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4213             :             }
    4214             : 
    4215             :             // 8bytes alignment
    4216          49 :             nOffsetTmp = pFlushNL->TotalSavedBytes + pFlushNL->nNumBytes;
    4217          49 :             MMGetOffsetAlignedTo8(&nOffsetTmp);
    4218          49 :             if (nOffsetTmp != pFlushNL->TotalSavedBytes + pFlushNL->nNumBytes)
    4219             :             {
    4220          41 :                 pFlushNL->SizeOfBlockToBeSaved =
    4221          41 :                     (size_t)(nOffsetTmp -
    4222          41 :                              (pFlushNL->TotalSavedBytes + pFlushNL->nNumBytes));
    4223          41 :                 pFlushNL->pBlockToBeSaved = (void *)nullptr;
    4224          41 :                 if (MMAppendBlockToBuffer(pFlushNL))
    4225             :                 {
    4226           0 :                     CPLDebugOnly("MiraMon", "Error in MMAppendBlockToBuffer()");
    4227           0 :                     return MM_FATAL_ERROR_WRITING_FEATURES;
    4228             :                 }
    4229             :             }
    4230          49 :             if (MMAddNodeRecordToMMDB(hMiraMonLayer,
    4231          49 :                                       pNodeTopHeader->nElemCount + 1,
    4232             :                                       pCurrentNodeHeaderPlus1))
    4233             :             {
    4234           0 :                 CPLDebugOnly("MiraMon", "Error in MMAddNodeRecordToMMDB()");
    4235           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4236             :             }
    4237             :         }
    4238             : 
    4239             :         // 3D stuff
    4240         102 :         if (hMiraMonLayer->TopHeader.bIs3d && pZDesc)
    4241             :         {
    4242         102 :             pZDesc[pArcTopHeader->nElemCount].dfBBminz =
    4243             :                 STATISTICAL_UNDEF_VALUE;
    4244         102 :             pZDesc[pArcTopHeader->nElemCount].dfBBmaxz =
    4245             :                 -STATISTICAL_UNDEF_VALUE;
    4246             : 
    4247             :             // Number of arc altitudes. If the number of altitudes is
    4248             :             // positive this indicates the number of altitudes for
    4249             :             // each vertex of the arc, and all the altitudes of the
    4250             :             // vertex 0 are written first, then those of the vertex 1,
    4251             :             // etc. If the number of altitudes is negative this
    4252             :             // indicates the number of arc altitudes, understanding
    4253             :             // that all the vertices have the same altitude (it is
    4254             :             // the case of a contour line, for example).
    4255             : 
    4256         161 :             for (nIVertice = 0; nIVertice < pCurrentArcHeader->nElemCount;
    4257          59 :                  nIVertice++, pZ++)
    4258             :             {
    4259         145 :                 pFlushZL->SizeOfBlockToBeSaved = sizeof(*pZ);
    4260         145 :                 pFlushZL->pBlockToBeSaved = (void *)pZ;
    4261         145 :                 if (MMAppendBlockToBuffer(pFlushZL))
    4262             :                 {
    4263           0 :                     CPLDebugOnly("MiraMon", "Error in MMAppendBlockToBuffer()");
    4264           0 :                     return MM_FATAL_ERROR_WRITING_FEATURES;
    4265             :                 }
    4266             : 
    4267         145 :                 if (pZDesc[pArcTopHeader->nElemCount].dfBBminz > *pZ)
    4268         115 :                     pZDesc[pArcTopHeader->nElemCount].dfBBminz = *pZ;
    4269         145 :                 if (pZDesc[pArcTopHeader->nElemCount].dfBBmaxz < *pZ)
    4270         116 :                     pZDesc[pArcTopHeader->nElemCount].dfBBmaxz = *pZ;
    4271             : 
    4272         145 :                 if (pMMArc->pZSection.ZHeader.dfBBminz > *pZ)
    4273          68 :                     pMMArc->pZSection.ZHeader.dfBBminz = *pZ;
    4274         145 :                 if (pMMArc->pZSection.ZHeader.dfBBmaxz < *pZ)
    4275          67 :                     pMMArc->pZSection.ZHeader.dfBBmaxz = *pZ;
    4276             : 
    4277             :                 // Only one altitude (the same for all vertices) is written
    4278         145 :                 if (hMMFeature->bAllZHaveSameValue)
    4279          86 :                     break;
    4280             :             }
    4281         102 :             if (hMMFeature->bAllZHaveSameValue)
    4282             :             {
    4283             :                 // Same altitude for all vertices
    4284          86 :                 pZDesc[pArcTopHeader->nElemCount].nZCount = -1;
    4285             :             }
    4286             :             else
    4287             :             {
    4288             :                 // One different altitude for each vertice
    4289          16 :                 pZDesc[pArcTopHeader->nElemCount].nZCount = 1;
    4290             :             }
    4291             : 
    4292         102 :             if (pArcTopHeader->nElemCount == 0)
    4293          58 :                 pZDesc[pArcTopHeader->nElemCount].nOffsetZ = 0;
    4294             :             else
    4295             :             {
    4296          44 :                 pLastArcHeader =
    4297          44 :                     pMMArc->pArcHeader + pArcTopHeader->nElemCount - 1;
    4298             : 
    4299          44 :                 if (pZDesc[pArcTopHeader->nElemCount - 1].nZCount < 0)
    4300             :                 {
    4301          32 :                     pZDesc[pArcTopHeader->nElemCount].nOffsetZ =
    4302          32 :                         pZDesc[pArcTopHeader->nElemCount - 1].nOffsetZ +
    4303             :                         sizeof(*pZ);
    4304             :                 }
    4305             :                 else
    4306             :                 {
    4307          12 :                     pZDesc[pArcTopHeader->nElemCount].nOffsetZ =
    4308          12 :                         pZDesc[pArcTopHeader->nElemCount - 1].nOffsetZ +
    4309          12 :                         sizeof(*pZ) * (pLastArcHeader->nElemCount);
    4310             :                 }
    4311             :             }
    4312             :         }
    4313             : 
    4314             :         // Exclusive polygon stuff
    4315         102 :         if (hMiraMonLayer->bIsPolygon && pCurrentPolHeader)
    4316             :         {
    4317             :             // PS SECTION
    4318          53 :             if (MMAppendIntegerDependingOnVersion(hMiraMonLayer, pFlushPS,
    4319             :                                                   &UnsignedLongNumber, 0))
    4320             :             {
    4321           0 :                 CPLDebugOnly("MiraMon",
    4322             :                              "Error in MMAppendIntegerDependingOnVersion()");
    4323           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4324             :             }
    4325             : 
    4326          53 :             if (MMAppendIntegerDependingOnVersion(
    4327             :                     hMiraMonLayer, pFlushPS, &UnsignedLongNumber,
    4328             :                     hMiraMonLayer->TopHeader.nElemCount))
    4329             :             {
    4330           0 :                 CPLDebugOnly("MiraMon",
    4331             :                              "Error in MMAppendIntegerDependingOnVersion()");
    4332           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4333             :             }
    4334             : 
    4335             :             // PAL SECTION
    4336             :             // Vertices of rings defining
    4337             :             // holes in polygons are in a counterclockwise direction.
    4338             :             // Holes are at the end of all external rings that contain the holes!!
    4339          53 :             if (VFG & MM_EXTERIOR_ARC_SIDE)
    4340          45 :                 nExternalRingsCount++;
    4341             : 
    4342          53 :             pCurrentPolHeader->nArcsCount++;
    4343             :             //(MM_POLYGON_ARCS_COUNT)hMMFeature->nNRings;
    4344          53 :             if (VFG & MM_EXTERIOR_ARC_SIDE)
    4345             :                 pCurrentPolHeader
    4346          45 :                     ->nExternalRingsCount++;  //= nExternalRingsCount;
    4347             : 
    4348          53 :             if (VFG & MM_END_ARC_IN_RING)
    4349          53 :                 pCurrentPolHeader->nRingsCount++;  //= hMMFeature->nNRings;
    4350          53 :             if (nIPart == 0)
    4351             :             {
    4352          41 :                 pCurrentPolHeader->nOffset =
    4353          41 :                     pFlushPAL->TotalSavedBytes + pFlushPAL->nNumBytes;
    4354             :             }
    4355             : 
    4356          53 :             if (nIPart == hMMFeature->nNRings - 1)
    4357          41 :                 pCurrentPolHeader->dfArea /= 2;
    4358             : 
    4359          53 :             pFlushPAL->SizeOfBlockToBeSaved = 1;
    4360          53 :             pFlushPAL->pBlockToBeSaved = (void *)&VFG;
    4361          53 :             if (MMAppendBlockToBuffer(pFlushPAL))
    4362             :             {
    4363           0 :                 CPLDebugOnly("MiraMon", "Error in MMAppendBlockToBuffer()");
    4364           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4365             :             }
    4366             : 
    4367          53 :             if (MMAppendIntegerDependingOnVersion(hMiraMonLayer, pFlushPAL,
    4368             :                                                   &UnsignedLongNumber,
    4369             :                                                   pArcTopHeader->nElemCount))
    4370             :             {
    4371           0 :                 CPLDebugOnly("MiraMon",
    4372             :                              "Error in MMAppendIntegerDependingOnVersion()");
    4373           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4374             :             }
    4375             : 
    4376             :             // 8bytes alignment
    4377          53 :             if (nIPart == hMMFeature->nNRings - 1)
    4378             :             {
    4379          41 :                 nOffsetTmp = pFlushPAL->TotalSavedBytes + pFlushPAL->nNumBytes;
    4380          41 :                 MMGetOffsetAlignedTo8(&nOffsetTmp);
    4381             : 
    4382          41 :                 if (nOffsetTmp !=
    4383          41 :                     pFlushPAL->TotalSavedBytes + pFlushPAL->nNumBytes)
    4384             :                 {
    4385          41 :                     pFlushPAL->SizeOfBlockToBeSaved =
    4386          41 :                         (size_t)(nOffsetTmp - (pFlushPAL->TotalSavedBytes +
    4387          41 :                                                pFlushPAL->nNumBytes));
    4388          41 :                     pFlushPAL->pBlockToBeSaved = (void *)nullptr;
    4389          41 :                     if (MMAppendBlockToBuffer(pFlushPAL))
    4390             :                     {
    4391           0 :                         CPLDebugOnly("MiraMon",
    4392             :                                      "Error in MMAppendBlockToBuffer()");
    4393           0 :                         return MM_FATAL_ERROR_WRITING_FEATURES;
    4394             :                     }
    4395             :                 }
    4396             :             }
    4397             : 
    4398          53 :             MMUpdateBoundingBox(&pCurrentPolHeader->dfBB,
    4399             :                                 &pCurrentArcHeader->dfBB);
    4400          53 :             pCurrentPolHeader->dfPerimeter += pCurrentArcHeader->dfLength;
    4401             :         }
    4402             :     }
    4403             : 
    4404             :     // Updating element count and if the polygon is multipart.
    4405             :     // MiraMon does not accept multipoints or multilines, only multipolygons.
    4406          90 :     if (hMiraMonLayer->bIsPolygon)
    4407             :     {
    4408          41 :         if (MMAddPolygonRecordToMMDB(hMiraMonLayer, hMMFeature,
    4409             :                                      hMiraMonLayer->TopHeader.nElemCount,
    4410             :                                      nPolVertices, pCurrentPolHeader))
    4411             :         {
    4412           0 :             CPLDebugOnly("MiraMon", "Error in MMAddPolygonRecordToMMDB()");
    4413           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    4414             :         }
    4415          41 :         hMiraMonLayer->TopHeader.nElemCount++;
    4416             : 
    4417          41 :         if (nExternalRingsCount > 1)
    4418           4 :             hMiraMonLayer->TopHeader.bIsMultipolygon = TRUE;
    4419             :     }
    4420             : 
    4421          90 :     return MM_CONTINUE_WRITING_FEATURES;
    4422             : }  // End of de MMCreateFeaturePolOrArc()
    4423             : 
    4424             : // Creates a MiraMon DBF record when not associated with a geometric feature.
    4425          34 : static int MMCreateRecordDBF(struct MiraMonVectLayerInfo *hMiraMonLayer,
    4426             :                              struct MiraMonFeature *hMMFeature)
    4427             : {
    4428             :     int result;
    4429             : 
    4430          34 :     if (!hMiraMonLayer)
    4431           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    4432             : 
    4433          34 :     if (hMiraMonLayer->TopHeader.nElemCount == 0)
    4434             :     {
    4435          17 :         if (MMCreateMMDB(hMiraMonLayer, nullptr))
    4436             :         {
    4437           0 :             MMDestroyMMDB(hMiraMonLayer);
    4438           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    4439             :         }
    4440             :     }
    4441             : 
    4442          34 :     result = MMAddDBFRecordToMMDB(hMiraMonLayer, hMMFeature);
    4443          34 :     if (result == MM_FATAL_ERROR_WRITING_FEATURES ||
    4444             :         result == MM_STOP_WRITING_FEATURES)
    4445           0 :         return result;
    4446             : 
    4447             :     // Everything OK.
    4448          34 :     return MM_CONTINUE_WRITING_FEATURES;
    4449             : }  // End of de MMCreateRecordDBF()
    4450             : 
    4451             : // Creates a MiraMon point feature.
    4452          89 : static int MMCreateFeaturePoint(struct MiraMonVectLayerInfo *hMiraMonLayer,
    4453             :                                 struct MiraMonFeature *hMMFeature)
    4454             : {
    4455          89 :     double *pZ = nullptr;
    4456             :     struct MM_POINT_2D *pCoord;
    4457             :     MM_POLYGON_RINGS_COUNT nIPart;
    4458             :     MM_N_VERTICES_TYPE nIVertice, nCoord;
    4459          89 :     struct MM_ZD *pZDescription = nullptr;
    4460             :     MM_INTERNAL_FID nElemCount;
    4461             :     int result;
    4462             : 
    4463          89 :     if (!hMiraMonLayer)
    4464           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    4465             : 
    4466          89 :     if (!hMMFeature)
    4467           0 :         return MM_STOP_WRITING_FEATURES;
    4468             : 
    4469          89 :     if (hMiraMonLayer->TopHeader.bIs3d)
    4470          89 :         pZ = hMMFeature->pZCoord;
    4471             : 
    4472          89 :     nElemCount = hMiraMonLayer->TopHeader.nElemCount;
    4473         178 :     for (nIPart = 0, pCoord = hMMFeature->pCoord; nIPart < hMMFeature->nNRings;
    4474          89 :          nIPart++, nElemCount++)
    4475             :     {
    4476          89 :         nCoord = hMMFeature->pNCoordRing[nIPart];
    4477             : 
    4478             :         // Checking if its possible continue writing the file due
    4479             :         // to version limitations.
    4480          89 :         if (MMCheckVersionForFID(hMiraMonLayer,
    4481          89 :                                  hMiraMonLayer->TopHeader.nElemCount + nCoord))
    4482             :         {
    4483           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    4484             :                      "Error in MMCheckVersionForFID() (5)");
    4485           0 :             return MM_STOP_WRITING_FEATURES;
    4486             :         }
    4487             : 
    4488          89 :         if (hMiraMonLayer->TopHeader.bIs3d)
    4489             :         {
    4490          89 :             if (nElemCount == 0)
    4491             :             {
    4492          34 :                 if (MMCheckVersionFor3DOffset(hMiraMonLayer, (nElemCount + 1),
    4493             :                                               0, 0))
    4494           0 :                     return MM_STOP_WRITING_FEATURES;
    4495             :             }
    4496             :             else
    4497             :             {
    4498          55 :                 pZDescription = hMiraMonLayer->MMPoint.pZSection.pZDescription;
    4499          55 :                 if (!pZDescription)
    4500             :                 {
    4501           0 :                     CPLError(CE_Failure, CPLE_ObjectNull,
    4502             :                              "Error: pZDescription should not be nullptr");
    4503           0 :                     return MM_STOP_WRITING_FEATURES;
    4504             :                 }
    4505             : 
    4506          55 :                 if (MMCheckVersionFor3DOffset(
    4507             :                         hMiraMonLayer, nElemCount + 1, 0,
    4508          55 :                         pZDescription[nElemCount - 1].nOffsetZ + sizeof(*pZ)))
    4509           0 :                     return MM_STOP_WRITING_FEATURES;
    4510             :             }
    4511             :         }
    4512             : 
    4513             :         // Doing real job
    4514             :         // Memory issues
    4515          89 :         if (hMiraMonLayer->TopHeader.bIs3d && pZ)
    4516             :         {
    4517          89 :             if (MMResizeZSectionDescrPointer(
    4518             :                     &hMiraMonLayer->MMPoint.pZSection.pZDescription,
    4519             :                     &hMiraMonLayer->MMPoint.pZSection.nMaxZDescription,
    4520             :                     nElemCount, MM_INCR_NUMBER_OF_POINTS, 0))
    4521             :             {
    4522           0 :                 CPLError(CE_Failure, CPLE_OutOfMemory,
    4523             :                          "Memory error in MiraMon "
    4524             :                          "driver (MMCreateFeaturePoint())");
    4525           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4526             :             }
    4527             : 
    4528          89 :             pZDescription = hMiraMonLayer->MMPoint.pZSection.pZDescription;
    4529          89 :             if (!pZDescription)
    4530             :             {
    4531           0 :                 CPLError(CE_Failure, CPLE_ObjectNull,
    4532             :                          "Error: pZDescription should not be nullptr");
    4533           0 :                 return MM_STOP_WRITING_FEATURES;
    4534             :             }
    4535             : 
    4536          89 :             pZDescription[nElemCount].dfBBminz = *pZ;
    4537          89 :             pZDescription[nElemCount].dfBBmaxz = *pZ;
    4538             : 
    4539          89 :             if (hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBminz > *pZ)
    4540          41 :                 hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBminz = *pZ;
    4541          89 :             if (hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBmaxz < *pZ)
    4542          38 :                 hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBmaxz = *pZ;
    4543             : 
    4544             :             // Specification ask for a negative number.
    4545          89 :             pZDescription[nElemCount].nZCount = -1;
    4546          89 :             if (nElemCount == 0)
    4547          34 :                 pZDescription[nElemCount].nOffsetZ = 0;
    4548             :             else
    4549          55 :                 pZDescription[nElemCount].nOffsetZ =
    4550          55 :                     pZDescription[nElemCount - 1].nOffsetZ + sizeof(*pZ);
    4551             :         }
    4552             : 
    4553             :         // Flush settings
    4554          89 :         hMiraMonLayer->MMPoint.FlushTL.pBlockWhereToSaveOrRead =
    4555          89 :             (void *)hMiraMonLayer->MMPoint.pTL;
    4556          89 :         if (hMiraMonLayer->TopHeader.bIs3d)
    4557          89 :             hMiraMonLayer->MMPoint.pZSection.FlushZL.pBlockWhereToSaveOrRead =
    4558          89 :                 (void *)hMiraMonLayer->MMPoint.pZSection.pZL;
    4559             : 
    4560             :         // Dump point or points (MiraMon does not have multiple points)
    4561         178 :         for (nIVertice = 0; nIVertice < nCoord; nIVertice++, pCoord++)
    4562             :         {
    4563             :             // Updating the bounding box of the layer
    4564          89 :             MMUpdateBoundingBoxXY(&hMiraMonLayer->TopHeader.hBB, pCoord);
    4565             : 
    4566             :             // Adding the point at the memory block
    4567          89 :             hMiraMonLayer->MMPoint.FlushTL.SizeOfBlockToBeSaved =
    4568             :                 sizeof(pCoord->dfX);
    4569          89 :             hMiraMonLayer->MMPoint.FlushTL.pBlockToBeSaved =
    4570          89 :                 (void *)&pCoord->dfX;
    4571          89 :             if (MMAppendBlockToBuffer(&hMiraMonLayer->MMPoint.FlushTL))
    4572           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4573          89 :             hMiraMonLayer->MMPoint.FlushTL.pBlockToBeSaved =
    4574          89 :                 (void *)&pCoord->dfY;
    4575          89 :             if (MMAppendBlockToBuffer(&hMiraMonLayer->MMPoint.FlushTL))
    4576           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4577             : 
    4578             :             // Adding the 3D part, if exists, at the memory block
    4579          89 :             if (hMiraMonLayer->TopHeader.bIs3d && pZ)
    4580             :             {
    4581          89 :                 hMiraMonLayer->MMPoint.pZSection.FlushZL.SizeOfBlockToBeSaved =
    4582             :                     sizeof(*pZ);
    4583          89 :                 hMiraMonLayer->MMPoint.pZSection.FlushZL.pBlockToBeSaved =
    4584             :                     (void *)pZ;
    4585          89 :                 if (MMAppendBlockToBuffer(
    4586             :                         &hMiraMonLayer->MMPoint.pZSection.FlushZL))
    4587           0 :                     return MM_FATAL_ERROR_WRITING_FEATURES;
    4588             : 
    4589          89 :                 if (!pZDescription)
    4590             :                 {
    4591           0 :                     CPLError(CE_Failure, CPLE_ObjectNull,
    4592             :                              "Error: pZDescription should not be nullptr");
    4593           0 :                     return MM_STOP_WRITING_FEATURES;
    4594             :                 }
    4595             : 
    4596          89 :                 if (pZDescription[nElemCount].dfBBminz > *pZ)
    4597           0 :                     pZDescription[nElemCount].dfBBminz = *pZ;
    4598          89 :                 if (pZDescription[nElemCount].dfBBmaxz < *pZ)
    4599           0 :                     pZDescription[nElemCount].dfBBmaxz = *pZ;
    4600             : 
    4601          89 :                 if (hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBminz > *pZ)
    4602           0 :                     hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBminz = *pZ;
    4603          89 :                 if (hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBmaxz < *pZ)
    4604           0 :                     hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBmaxz = *pZ;
    4605             : 
    4606          89 :                 pZ++;
    4607             :             }
    4608             :         }
    4609             : 
    4610          89 :         if (hMiraMonLayer->TopHeader.nElemCount == 0)
    4611             :         {
    4612          34 :             if (MMCreateMMDB(hMiraMonLayer, hMMFeature->pCoord))
    4613           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4614             :         }
    4615             : 
    4616          89 :         result = MMAddPointRecordToMMDB(hMiraMonLayer, hMMFeature, nElemCount);
    4617          89 :         if (result == MM_FATAL_ERROR_WRITING_FEATURES ||
    4618             :             result == MM_STOP_WRITING_FEATURES)
    4619           0 :             return result;
    4620             :     }
    4621             :     // Updating nElemCount at the header of the layer
    4622          89 :     hMiraMonLayer->TopHeader.nElemCount = nElemCount;
    4623             : 
    4624             :     // Everything OK.
    4625          89 :     return MM_CONTINUE_WRITING_FEATURES;
    4626             : }  // End of de MMCreateFeaturePoint()
    4627             : 
    4628             : // Checks whether a given Feature ID (FID) exceeds the maximum allowed
    4629             : // index for 2 GB vectors in a specific MiraMon layer.
    4630         804 : int MMCheckVersionForFID(struct MiraMonVectLayerInfo *hMiraMonLayer,
    4631             :                          MM_INTERNAL_FID FID)
    4632             : {
    4633         804 :     if (!hMiraMonLayer)
    4634           0 :         return 1;
    4635             : 
    4636         804 :     if (hMiraMonLayer->LayerVersion != MM_32BITS_VERSION)
    4637          56 :         return 0;
    4638             : 
    4639         748 :     if (FID >= MAXIMUM_OBJECT_INDEX_IN_2GB_VECTORS)
    4640           0 :         return 1;
    4641         748 :     return 0;
    4642             : }
    4643             : 
    4644             : // Checks whether a given offset exceeds the maximum allowed
    4645             : // index for 2 GB vectors in a specific MiraMon layer.
    4646         217 : int MMCheckVersionOffset(struct MiraMonVectLayerInfo *hMiraMonLayer,
    4647             :                          MM_FILE_OFFSET OffsetToCheck)
    4648             : {
    4649         217 :     if (!hMiraMonLayer)
    4650           0 :         return 1;
    4651             : 
    4652             :     // Checking if the final version is 1.1 or 2.0
    4653         217 :     if (hMiraMonLayer->LayerVersion != MM_32BITS_VERSION)
    4654           0 :         return 0;
    4655             : 
    4656             :     // User decided that if necessary, output version can be 2.0
    4657         217 :     if (OffsetToCheck < MAXIMUM_OFFSET_IN_2GB_VECTORS)
    4658         217 :         return 0;
    4659             : 
    4660           0 :     return 1;
    4661             : }
    4662             : 
    4663             : // Checks whether a given offset in 3D section exceeds the maximum allowed
    4664             : // index for 2 GB vectors in a specific MiraMon layer.
    4665         177 : int MMCheckVersionFor3DOffset(struct MiraMonVectLayerInfo *hMiraMonLayer,
    4666             :                               MM_INTERNAL_FID nElemCount,
    4667             :                               MM_FILE_OFFSET nOffsetAL,
    4668             :                               MM_FILE_OFFSET nZLOffset)
    4669             : {
    4670             :     MM_FILE_OFFSET LastOffset;
    4671             : 
    4672         177 :     if (!hMiraMonLayer)
    4673           0 :         return 1;
    4674             : 
    4675             :     // Checking if the final version is 1.1 or 2.0
    4676         177 :     if (hMiraMonLayer->LayerVersion != MM_32BITS_VERSION)
    4677           6 :         return 0;
    4678             : 
    4679             :     // User decided that if necessary, output version can be 2.0
    4680         171 :     if (hMiraMonLayer->bIsPoint)
    4681          83 :         LastOffset = MM_HEADER_SIZE_32_BITS + nElemCount * MM_SIZE_OF_TL;
    4682             :     else  // Arc case
    4683             :     {
    4684          88 :         LastOffset = MM_HEADER_SIZE_32_BITS +
    4685          88 :                      nElemCount * MM_SIZE_OF_AH_32BITS + +nOffsetAL;
    4686             :     }
    4687             : 
    4688         171 :     LastOffset += MM_SIZE_OF_ZH;
    4689         171 :     LastOffset += nElemCount * MM_SIZE_OF_ZD_32_BITS;
    4690         171 :     LastOffset += nZLOffset;
    4691             : 
    4692         171 :     if (LastOffset < MAXIMUM_OFFSET_IN_2GB_VECTORS)
    4693         171 :         return 0;
    4694             : 
    4695           0 :     return 1;
    4696             : }
    4697             : 
    4698             : // Adds a feature in a MiraMon layer.
    4699         213 : int MMAddFeature(struct MiraMonVectLayerInfo *hMiraMonLayer,
    4700             :                  struct MiraMonFeature *hMiraMonFeature)
    4701             : {
    4702             :     int re;
    4703         213 :     MM_INTERNAL_FID previousFID = 0;
    4704             : 
    4705         213 :     if (!hMiraMonLayer)
    4706           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    4707             : 
    4708         213 :     if (!hMiraMonLayer->bIsBeenInit)
    4709             :     {
    4710           0 :         if (MMInitLayerByType(hMiraMonLayer))
    4711             :         {
    4712           0 :             CPLDebugOnly("MiraMon", "Error in MMInitLayerByType()");
    4713           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    4714             :         }
    4715           0 :         hMiraMonLayer->bIsBeenInit = 1;
    4716             :     }
    4717             : 
    4718         213 :     if (hMiraMonFeature)
    4719         213 :         previousFID = hMiraMonLayer->TopHeader.nElemCount;
    4720             : 
    4721         213 :     if (hMiraMonLayer->bIsPoint)
    4722             :     {
    4723          89 :         re = MMCreateFeaturePoint(hMiraMonLayer, hMiraMonFeature);
    4724          89 :         if (hMiraMonFeature)
    4725             :         {
    4726          89 :             hMiraMonFeature->nReadFeatures =
    4727          89 :                 hMiraMonLayer->TopHeader.nElemCount - previousFID;
    4728             :         }
    4729          89 :         return re;
    4730             :     }
    4731         124 :     if (hMiraMonLayer->bIsArc || hMiraMonLayer->bIsPolygon)
    4732             :     {
    4733          90 :         re = MMCreateFeaturePolOrArc(hMiraMonLayer, hMiraMonFeature);
    4734          90 :         if (hMiraMonFeature)
    4735             :         {
    4736          90 :             hMiraMonFeature->nReadFeatures =
    4737          90 :                 hMiraMonLayer->TopHeader.nElemCount - previousFID;
    4738             :         }
    4739          90 :         return re;
    4740             :     }
    4741          34 :     if (hMiraMonLayer->bIsDBF)
    4742             :     {
    4743             :         // Adding a record to DBF file
    4744          34 :         re = MMCreateRecordDBF(hMiraMonLayer, hMiraMonFeature);
    4745          34 :         if (hMiraMonFeature)
    4746             :         {
    4747          34 :             hMiraMonFeature->nReadFeatures =
    4748          34 :                 hMiraMonLayer->TopHeader.nElemCount - previousFID;
    4749             :         }
    4750          34 :         return re;
    4751             :     }
    4752             : 
    4753           0 :     return MM_CONTINUE_WRITING_FEATURES;
    4754             : }
    4755             : 
    4756             : /* -------------------------------------------------------------------- */
    4757             : /*      Tools used by MiraMon.                                          */
    4758             : /* -------------------------------------------------------------------- */
    4759             : 
    4760         320 : void MMInitBoundingBox(struct MMBoundingBox *dfBB)
    4761             : {
    4762         320 :     if (!dfBB)
    4763           0 :         return;
    4764         320 :     dfBB->dfMinX = STATISTICAL_UNDEF_VALUE;
    4765         320 :     dfBB->dfMaxX = -STATISTICAL_UNDEF_VALUE;
    4766         320 :     dfBB->dfMinY = STATISTICAL_UNDEF_VALUE;
    4767         320 :     dfBB->dfMaxY = -STATISTICAL_UNDEF_VALUE;
    4768             : }
    4769             : 
    4770         208 : void MMUpdateBoundingBox(struct MMBoundingBox *dfBBToBeAct,
    4771             :                          struct MMBoundingBox *dfBBWithData)
    4772             : {
    4773         208 :     if (!dfBBToBeAct)
    4774           0 :         return;
    4775             : 
    4776         208 :     if (dfBBToBeAct->dfMinX > dfBBWithData->dfMinX)
    4777         133 :         dfBBToBeAct->dfMinX = dfBBWithData->dfMinX;
    4778             : 
    4779         208 :     if (dfBBToBeAct->dfMinY > dfBBWithData->dfMinY)
    4780         148 :         dfBBToBeAct->dfMinY = dfBBWithData->dfMinY;
    4781             : 
    4782         208 :     if (dfBBToBeAct->dfMaxX < dfBBWithData->dfMaxX)
    4783         147 :         dfBBToBeAct->dfMaxX = dfBBWithData->dfMaxX;
    4784             : 
    4785         208 :     if (dfBBToBeAct->dfMaxY < dfBBWithData->dfMaxY)
    4786         145 :         dfBBToBeAct->dfMaxY = dfBBWithData->dfMaxY;
    4787             : }
    4788             : 
    4789         763 : void MMUpdateBoundingBoxXY(struct MMBoundingBox *dfBB,
    4790             :                            struct MM_POINT_2D *pCoord)
    4791             : {
    4792         763 :     if (!pCoord)
    4793           0 :         return;
    4794             : 
    4795         763 :     if (pCoord->dfX < dfBB->dfMinX)
    4796         269 :         dfBB->dfMinX = pCoord->dfX;
    4797             : 
    4798         763 :     if (pCoord->dfY < dfBB->dfMinY)
    4799         294 :         dfBB->dfMinY = pCoord->dfY;
    4800             : 
    4801         763 :     if (pCoord->dfX > dfBB->dfMaxX)
    4802         398 :         dfBB->dfMaxX = pCoord->dfX;
    4803             : 
    4804         763 :     if (pCoord->dfY > dfBB->dfMaxY)
    4805         358 :         dfBB->dfMaxY = pCoord->dfY;
    4806             : }
    4807             : 
    4808             : /* -------------------------------------------------------------------- */
    4809             : /*      Resize structures for reuse                                     */
    4810             : /* -------------------------------------------------------------------- */
    4811        1398 : int MMResizeMiraMonFieldValue(struct MiraMonFieldValue **pFieldValue,
    4812             :                               MM_EXT_DBF_N_MULTIPLE_RECORDS *nMax,
    4813             :                               MM_EXT_DBF_N_MULTIPLE_RECORDS nNum,
    4814             :                               MM_EXT_DBF_N_MULTIPLE_RECORDS nIncr,
    4815             :                               MM_EXT_DBF_N_MULTIPLE_RECORDS nProposedMax)
    4816             : {
    4817             :     MM_EXT_DBF_N_MULTIPLE_RECORDS nPrevMax;
    4818             :     MM_EXT_DBF_N_MULTIPLE_RECORDS nNewMax;
    4819             :     void *pTmp;
    4820             : 
    4821        1398 :     if (nNum < *nMax)
    4822        1379 :         return 0;
    4823             : 
    4824          19 :     nPrevMax = *nMax;
    4825          19 :     nNewMax = MAX(nNum + nIncr, nProposedMax);
    4826          19 :     if (MMCheckSize_t(nNewMax, sizeof(**pFieldValue)))
    4827             :     {
    4828           0 :         return 1;
    4829             :     }
    4830          19 :     if ((pTmp = VSIRealloc(*pFieldValue,
    4831          19 :                            (size_t)nNewMax * sizeof(**pFieldValue))) == nullptr)
    4832             :     {
    4833           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    4834             :                  "Memory error in MiraMon "
    4835             :                  "driver (MMResizeMiraMonFieldValue())");
    4836           0 :         return 1;
    4837             :     }
    4838          19 :     *nMax = nNewMax;
    4839          19 :     *pFieldValue = pTmp;
    4840             : 
    4841          19 :     memset((*pFieldValue) + nPrevMax, 0,
    4842          19 :            (size_t)(*nMax - nPrevMax) * sizeof(**pFieldValue));
    4843          19 :     return 0;
    4844             : }
    4845             : 
    4846         352 : int MMResizeMiraMonPolygonArcs(struct MM_PAL_MEM **pFID,
    4847             :                                MM_POLYGON_ARCS_COUNT *nMax,
    4848             :                                MM_POLYGON_ARCS_COUNT nNum,
    4849             :                                MM_POLYGON_ARCS_COUNT nIncr,
    4850             :                                MM_POLYGON_ARCS_COUNT nProposedMax)
    4851             : {
    4852             :     MM_POLYGON_ARCS_COUNT nPrevMax;
    4853             :     MM_POLYGON_ARCS_COUNT nNewMax;
    4854             :     void *pTmp;
    4855             : 
    4856         352 :     if (nNum < *nMax)
    4857          32 :         return 0;
    4858             : 
    4859         320 :     nPrevMax = *nMax;
    4860         320 :     nNewMax = MAX(nNum + nIncr, nProposedMax);
    4861         320 :     if (MMCheckSize_t(nNewMax, sizeof(**pFID)))
    4862             :     {
    4863           0 :         return 1;
    4864             :     }
    4865         320 :     if (nNewMax == 0 && *pFID)
    4866           0 :         return 0;
    4867         320 :     if ((pTmp = VSIRealloc(*pFID, (size_t)nNewMax * sizeof(**pFID))) == nullptr)
    4868             :     {
    4869           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    4870             :                  "Memory error in MiraMon "
    4871             :                  "driver (MMResizeMiraMonPolygonArcs())");
    4872           0 :         return 1;
    4873             :     }
    4874         320 :     *nMax = nNewMax;
    4875         320 :     *pFID = pTmp;
    4876             : 
    4877         320 :     memset((*pFID) + nPrevMax, 0, (size_t)(*nMax - nPrevMax) * sizeof(**pFID));
    4878         320 :     return 0;
    4879             : }
    4880             : 
    4881          88 : int MMResizeMiraMonRecord(struct MiraMonRecord **pMiraMonRecord,
    4882             :                           MM_EXT_DBF_N_MULTIPLE_RECORDS *nMax,
    4883             :                           MM_EXT_DBF_N_MULTIPLE_RECORDS nNum,
    4884             :                           MM_EXT_DBF_N_MULTIPLE_RECORDS nIncr,
    4885             :                           MM_EXT_DBF_N_MULTIPLE_RECORDS nProposedMax)
    4886             : {
    4887             :     MM_EXT_DBF_N_MULTIPLE_RECORDS nPrevMax;
    4888             :     MM_EXT_DBF_N_MULTIPLE_RECORDS nNewMax;
    4889             :     void *pTmp;
    4890             : 
    4891          88 :     if (nNum < *nMax)
    4892          72 :         return 0;
    4893             : 
    4894          16 :     nPrevMax = *nMax;
    4895          16 :     nNewMax = MAX(nNum + nIncr, nProposedMax);
    4896          16 :     if (MMCheckSize_t(nNewMax, sizeof(**pMiraMonRecord)))
    4897             :     {
    4898           0 :         return 1;
    4899             :     }
    4900          16 :     if (nNewMax == 0 && *pMiraMonRecord)
    4901           0 :         return 0;
    4902          16 :     if ((pTmp = VSIRealloc(*pMiraMonRecord,
    4903          16 :                            (size_t)nNewMax * sizeof(**pMiraMonRecord))) ==
    4904             :         nullptr)
    4905             :     {
    4906           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    4907             :                  "Memory error in MiraMon "
    4908             :                  "driver (MMResizeMiraMonRecord())");
    4909           0 :         return 1;
    4910             :     }
    4911          16 :     *nMax = nNewMax;
    4912          16 :     *pMiraMonRecord = pTmp;
    4913             : 
    4914          16 :     memset((*pMiraMonRecord) + nPrevMax, 0,
    4915          16 :            (size_t)(*nMax - nPrevMax) * sizeof(**pMiraMonRecord));
    4916          16 :     return 0;
    4917             : }
    4918             : 
    4919         191 : int MMResizeZSectionDescrPointer(struct MM_ZD **pZDescription, GUInt64 *nMax,
    4920             :                                  GUInt64 nNum, GUInt64 nIncr,
    4921             :                                  GUInt64 nProposedMax)
    4922             : {
    4923             :     GUInt64 nNewMax, nPrevMax;
    4924             :     void *pTmp;
    4925             : 
    4926         191 :     if (nNum < *nMax)
    4927         133 :         return 0;
    4928             : 
    4929          58 :     nPrevMax = *nMax;
    4930          58 :     nNewMax = MAX(nNum + nIncr, nProposedMax);
    4931          58 :     if (MMCheckSize_t(nNewMax, sizeof(**pZDescription)))
    4932             :     {
    4933           0 :         return 1;
    4934             :     }
    4935          58 :     if (nNewMax == 0 && *pZDescription)
    4936           0 :         return 0;
    4937          58 :     if ((pTmp = VSIRealloc(*pZDescription,
    4938             :                            (size_t)nNewMax * sizeof(**pZDescription))) ==
    4939             :         nullptr)
    4940             :     {
    4941           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    4942             :                  "Memory error in MiraMon "
    4943             :                  "driver (MMResizeZSectionDescrPointer())");
    4944           0 :         return 1;
    4945             :     }
    4946          58 :     *nMax = nNewMax;
    4947          58 :     *pZDescription = pTmp;
    4948             : 
    4949          58 :     memset((*pZDescription) + nPrevMax, 0,
    4950          58 :            (size_t)(*nMax - nPrevMax) * sizeof(**pZDescription));
    4951          58 :     return 0;
    4952             : }
    4953             : 
    4954         102 : int MMResizeNodeHeaderPointer(struct MM_NH **pNodeHeader, GUInt64 *nMax,
    4955             :                               GUInt64 nNum, GUInt64 nIncr, GUInt64 nProposedMax)
    4956             : {
    4957             :     GUInt64 nNewMax, nPrevMax;
    4958             :     void *pTmp;
    4959             : 
    4960         102 :     if (nNum < *nMax)
    4961         102 :         return 0;
    4962             : 
    4963           0 :     nPrevMax = *nMax;
    4964           0 :     nNewMax = MAX(nNum + nIncr, nProposedMax);
    4965           0 :     if (MMCheckSize_t(nNewMax, sizeof(**pNodeHeader)))
    4966             :     {
    4967           0 :         return 1;
    4968             :     }
    4969           0 :     if (nNewMax == 0 && *pNodeHeader)
    4970           0 :         return 0;
    4971           0 :     if ((pTmp = VSIRealloc(*pNodeHeader,
    4972             :                            (size_t)nNewMax * sizeof(**pNodeHeader))) == nullptr)
    4973             :     {
    4974           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    4975             :                  "Memory error in MiraMon "
    4976             :                  "driver (MMResizeNodeHeaderPointer())");
    4977           0 :         return 1;
    4978             :     }
    4979           0 :     *nMax = nNewMax;
    4980           0 :     *pNodeHeader = pTmp;
    4981             : 
    4982           0 :     memset((*pNodeHeader) + nPrevMax, 0,
    4983           0 :            (size_t)(*nMax - nPrevMax) * sizeof(**pNodeHeader));
    4984           0 :     return 0;
    4985             : }
    4986             : 
    4987         102 : int MMResizeArcHeaderPointer(struct MM_AH **pArcHeader, GUInt64 *nMax,
    4988             :                              GUInt64 nNum, GUInt64 nIncr, GUInt64 nProposedMax)
    4989             : {
    4990             :     GUInt64 nNewMax, nPrevMax;
    4991             :     void *pTmp;
    4992             : 
    4993         102 :     if (nNum < *nMax)
    4994         102 :         return 0;
    4995             : 
    4996           0 :     nPrevMax = *nMax;
    4997           0 :     nNewMax = MAX(nNum + nIncr, nProposedMax);
    4998           0 :     if (MMCheckSize_t(nNewMax, sizeof(**pArcHeader)))
    4999             :     {
    5000           0 :         return 1;
    5001             :     }
    5002           0 :     if (nNewMax == 0 && *pArcHeader)
    5003           0 :         return 0;
    5004           0 :     if ((pTmp = VSIRealloc(*pArcHeader,
    5005             :                            (size_t)nNewMax * sizeof(**pArcHeader))) == nullptr)
    5006             :     {
    5007           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    5008             :                  "Memory error in MiraMon "
    5009             :                  "driver (MMResizeArcHeaderPointer())");
    5010           0 :         return 1;
    5011             :     }
    5012           0 :     *nMax = nNewMax;
    5013           0 :     *pArcHeader = pTmp;
    5014             : 
    5015           0 :     memset((*pArcHeader) + nPrevMax, 0,
    5016           0 :            (size_t)(*nMax - nPrevMax) * sizeof(**pArcHeader));
    5017           0 :     return 0;
    5018             : }
    5019             : 
    5020          41 : int MMResizePolHeaderPointer(struct MM_PH **pPolHeader, GUInt64 *nMax,
    5021             :                              GUInt64 nNum, GUInt64 nIncr, GUInt64 nProposedMax)
    5022             : {
    5023             :     GUInt64 nNewMax, nPrevMax;
    5024             :     void *pTmp;
    5025             : 
    5026          41 :     if (nNum < *nMax)
    5027          41 :         return 0;
    5028             : 
    5029           0 :     nPrevMax = *nMax;
    5030           0 :     nNewMax = MAX(nNum + nIncr, nProposedMax);
    5031           0 :     if (MMCheckSize_t(nNewMax, sizeof(**pPolHeader)))
    5032             :     {
    5033           0 :         return 1;
    5034             :     }
    5035           0 :     if (nNewMax == 0 && *pPolHeader)
    5036           0 :         return 0;
    5037           0 :     if ((pTmp = VSIRealloc(*pPolHeader,
    5038             :                            (size_t)nNewMax * sizeof(**pPolHeader))) == nullptr)
    5039             :     {
    5040           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    5041             :                  "Memory error in MiraMon "
    5042             :                  "driver (MMResizePolHeaderPointer())");
    5043           0 :         return 1;
    5044             :     }
    5045           0 :     *nMax = nNewMax;
    5046           0 :     *pPolHeader = pTmp;
    5047             : 
    5048           0 :     memset((*pPolHeader) + nPrevMax, 0,
    5049           0 :            (size_t)(*nMax - nPrevMax) * sizeof(**pPolHeader));
    5050           0 :     return 0;
    5051             : }
    5052             : 
    5053        2747 : int MMResize_MM_N_VERTICES_TYPE_Pointer(MM_N_VERTICES_TYPE **pVrt,
    5054             :                                         MM_N_VERTICES_TYPE *nMax,
    5055             :                                         MM_N_VERTICES_TYPE nNum,
    5056             :                                         MM_N_VERTICES_TYPE nIncr,
    5057             :                                         MM_N_VERTICES_TYPE nProposedMax)
    5058             : {
    5059             :     MM_N_VERTICES_TYPE nNewMax, nPrevMax;
    5060             :     void *pTmp;
    5061             : 
    5062        2747 :     if (nNum < *nMax)
    5063        1234 :         return 0;
    5064             : 
    5065        1513 :     nPrevMax = *nMax;
    5066        1513 :     nNewMax = MAX(nNum + nIncr, nProposedMax);
    5067        1513 :     if (MMCheckSize_t(nNewMax, sizeof(**pVrt)))
    5068             :     {
    5069           0 :         return 1;
    5070             :     }
    5071        1513 :     if (nNewMax == 0 && *pVrt)
    5072           0 :         return 0;
    5073        1513 :     if ((pTmp = VSIRealloc(*pVrt, (size_t)nNewMax * sizeof(**pVrt))) == nullptr)
    5074             :     {
    5075           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    5076             :                  "Memory error in MiraMon "
    5077             :                  "driver (MMResize_MM_N_VERTICES_TYPE_Pointer())");
    5078           0 :         return 1;
    5079             :     }
    5080        1513 :     *nMax = nNewMax;
    5081        1513 :     *pVrt = pTmp;
    5082             : 
    5083        1513 :     memset((*pVrt) + nPrevMax, 0, (size_t)(*nMax - nPrevMax) * sizeof(**pVrt));
    5084        1513 :     return 0;
    5085             : }
    5086             : 
    5087         399 : int MMResizeVFGPointer(char **pInt, MM_INTERNAL_FID *nMax, MM_INTERNAL_FID nNum,
    5088             :                        MM_INTERNAL_FID nIncr, MM_INTERNAL_FID nProposedMax)
    5089             : {
    5090             :     MM_N_VERTICES_TYPE nNewMax, nPrevMax;
    5091             :     void *pTmp;
    5092             : 
    5093         399 :     if (nNum < *nMax)
    5094          58 :         return 0;
    5095             : 
    5096         341 :     nPrevMax = *nMax;
    5097         341 :     nNewMax = MAX(nNum + nIncr, nProposedMax);
    5098         341 :     if (MMCheckSize_t(nNewMax, sizeof(**pInt)))
    5099             :     {
    5100           0 :         return 1;
    5101             :     }
    5102         341 :     if (nNewMax == 0 && *pInt)
    5103           0 :         return 0;
    5104         341 :     if ((pTmp = VSIRealloc(*pInt, (size_t)nNewMax * sizeof(**pInt))) == nullptr)
    5105             :     {
    5106           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    5107             :                  "Memory error in MiraMon "
    5108             :                  "driver (MMResizeVFGPointer())");
    5109           0 :         return 1;
    5110             :     }
    5111         341 :     *nMax = nNewMax;
    5112         341 :     *pInt = pTmp;
    5113             : 
    5114         341 :     memset((*pInt) + nPrevMax, 0, (size_t)(*nMax - nPrevMax) * sizeof(**pInt));
    5115         341 :     return 0;
    5116             : }
    5117             : 
    5118        2760 : int MMResizeMM_POINT2DPointer(struct MM_POINT_2D **pPoint2D,
    5119             :                               MM_N_VERTICES_TYPE *nMax, MM_N_VERTICES_TYPE nNum,
    5120             :                               MM_N_VERTICES_TYPE nIncr,
    5121             :                               MM_N_VERTICES_TYPE nProposedMax)
    5122             : {
    5123             :     MM_N_VERTICES_TYPE nNewMax, nPrevMax;
    5124             :     void *pTmp;
    5125             : 
    5126        2760 :     if (nNum < *nMax)
    5127        2367 :         return 0;
    5128             : 
    5129         393 :     nPrevMax = *nMax;
    5130         393 :     nNewMax = MAX(nNum + nIncr, nProposedMax);
    5131         393 :     if (MMCheckSize_t(nNewMax, sizeof(**pPoint2D)))
    5132             :     {
    5133           0 :         return 1;
    5134             :     }
    5135         393 :     if (nNewMax == 0 && *pPoint2D)
    5136           0 :         return 0;
    5137         393 :     if ((pTmp = VSIRealloc(*pPoint2D, (size_t)nNewMax * sizeof(**pPoint2D))) ==
    5138             :         nullptr)
    5139             :     {
    5140           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    5141             :                  "Memory error in MiraMon "
    5142             :                  "driver (MMResizeMM_POINT2DPointer())");
    5143           0 :         return 1;
    5144             :     }
    5145         393 :     *nMax = nNewMax;
    5146         393 :     *pPoint2D = pTmp;
    5147             : 
    5148         393 :     memset((*pPoint2D) + nPrevMax, 0,
    5149         393 :            (size_t)(*nMax - nPrevMax) * sizeof(**pPoint2D));
    5150         393 :     return 0;
    5151             : }
    5152             : 
    5153        1787 : int MMResizeDoublePointer(MM_COORD_TYPE **pDouble, MM_N_VERTICES_TYPE *nMax,
    5154             :                           MM_N_VERTICES_TYPE nNum, MM_N_VERTICES_TYPE nIncr,
    5155             :                           MM_N_VERTICES_TYPE nProposedMax)
    5156             : {
    5157             :     MM_N_VERTICES_TYPE nNewMax, nPrevMax;
    5158             :     void *pTmp;
    5159             : 
    5160        1787 :     if (nNum < *nMax)
    5161        1619 :         return 0;
    5162             : 
    5163         168 :     nPrevMax = *nMax;
    5164         168 :     nNewMax = MAX(nNum + nIncr, nProposedMax);
    5165         168 :     if (MMCheckSize_t(nNewMax, sizeof(**pDouble)))
    5166             :     {
    5167           0 :         return 1;
    5168             :     }
    5169         168 :     if (nNewMax == 0 && *pDouble)
    5170           0 :         return 0;
    5171         168 :     if ((pTmp = VSIRealloc(*pDouble, (size_t)nNewMax * sizeof(**pDouble))) ==
    5172             :         nullptr)
    5173             :     {
    5174           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    5175             :                  "Memory error in MiraMon "
    5176             :                  "driver (MMResizeDoublePointer())");
    5177           0 :         return 1;
    5178             :     }
    5179         168 :     *nMax = nNewMax;
    5180         168 :     *pDouble = pTmp;
    5181             : 
    5182         168 :     memset((*pDouble) + nPrevMax, 0,
    5183         168 :            (size_t)(*nMax - nPrevMax) * sizeof(**pDouble));
    5184         168 :     return 0;
    5185             : }
    5186             : 
    5187       23549 : int MMResizeStringToOperateIfNeeded(struct MiraMonVectLayerInfo *hMiraMonLayer,
    5188             :                                     MM_EXT_DBF_N_FIELDS nNewSize)
    5189             : {
    5190       23549 :     if (!hMiraMonLayer)
    5191           0 :         return 1;
    5192             : 
    5193       23549 :     if (nNewSize >= hMiraMonLayer->nNumStringToOperate)
    5194             :     {
    5195             :         char *p;
    5196         449 :         if (MMCheckSize_t(nNewSize, 1))
    5197           0 :             return 1;
    5198         449 :         p = (char *)VSICalloc(1, (size_t)nNewSize);
    5199         449 :         if (!p)
    5200             :         {
    5201           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
    5202             :                      "Memory error in MiraMon "
    5203             :                      "driver (MMResizeStringToOperateIfNeeded())");
    5204           0 :             return 1;
    5205             :         }
    5206         449 :         VSIFree(hMiraMonLayer->szStringToOperate);
    5207         449 :         hMiraMonLayer->szStringToOperate = p;
    5208         449 :         hMiraMonLayer->nNumStringToOperate = nNewSize;
    5209             :     }
    5210       23549 :     return 0;
    5211             : }
    5212             : 
    5213             : /* -------------------------------------------------------------------- */
    5214             : /*      Metadata Functions                                              */
    5215             : /* -------------------------------------------------------------------- */
    5216             : 
    5217             : #define LineReturn "\r\n"
    5218             : 
    5219             : // Generates an identifier that REL 4 MiraMon metadata needs.
    5220         177 : static void MMGenerateFileIdentifierFromMetadataFileName(char *pMMFN,
    5221             :                                                          char *aFileIdentifier)
    5222             : {
    5223             :     char aCharRand[8];
    5224             :     static const char aCharset[] =
    5225             :         "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    5226             :     int i, len_charset;
    5227             : 
    5228         177 :     memset(aFileIdentifier, '\0', MM_MAX_LEN_LAYER_IDENTIFIER);
    5229             : 
    5230         177 :     aCharRand[0] = '_';
    5231         177 :     len_charset = (int)strlen(aCharset);
    5232        1239 :     for (i = 1; i < 7; i++)
    5233             :     {
    5234             : #ifndef __COVERITY__
    5235        1062 :         aCharRand[i] = aCharset[rand() % (len_charset - 1)];
    5236             : #else
    5237             :         aCharRand[i] = aCharset[i % (len_charset - 1)];
    5238             : #endif
    5239             :     }
    5240         177 :     aCharRand[7] = '\0';
    5241         177 :     CPLStrlcpy(aFileIdentifier, pMMFN, MM_MAX_LEN_LAYER_IDENTIFIER - 7);
    5242         177 :     strcat(aFileIdentifier, aCharRand);
    5243         177 :     return;
    5244             : }
    5245             : 
    5246             : // Converts a string from UTF-8 to ANSI to be written in a REL 4 file
    5247         759 : static void MMWrite_ANSI_MetadataKeyDescriptor(
    5248             :     struct MiraMonVectorMetaData *hMMMD, VSILFILE *pF, const char *pszEng,
    5249             :     const char *pszCat, const char *pszEsp, const char *pszCurrentEncoding)
    5250             : {
    5251         759 :     if (!EQUAL(pszCurrentEncoding, CPL_ENC_ISO8859_1))
    5252             :     {
    5253          99 :         char *pszString = nullptr;
    5254             : 
    5255          99 :         switch (hMMMD->nMMLanguage)
    5256             :         {
    5257           2 :             case MM_CAT_LANGUAGE:
    5258             :                 pszString =
    5259           2 :                     CPLRecode(pszCat, pszCurrentEncoding, CPL_ENC_ISO8859_1);
    5260           2 :                 break;
    5261           2 :             case MM_SPA_LANGUAGE:
    5262             :                 pszString =
    5263           2 :                     CPLRecode(pszEsp, pszCurrentEncoding, CPL_ENC_ISO8859_1);
    5264           2 :                 break;
    5265          95 :             default:
    5266             :             case MM_ENG_LANGUAGE:
    5267             :                 pszString =
    5268          95 :                     CPLRecode(pszEng, pszCurrentEncoding, CPL_ENC_ISO8859_1);
    5269          95 :                 break;
    5270             :         }
    5271          99 :         if (pszString)
    5272             :         {
    5273          99 :             VSIFPrintfL(pF, "%s", KEY_descriptor);
    5274          99 :             VSIFPrintfL(pF, "=");
    5275          99 :             VSIFPrintfL(pF, "%s", pszString);
    5276          99 :             VSIFPrintfL(pF, "%s", LineReturn);
    5277          99 :             CPLFree(pszString);
    5278             :         }
    5279             :     }
    5280             :     else
    5281             :     {
    5282             :         const char *pszString;
    5283         660 :         switch (hMMMD->nMMLanguage)
    5284             :         {
    5285           1 :             case MM_CAT_LANGUAGE:
    5286           1 :                 pszString = pszCat;
    5287           1 :                 break;
    5288           1 :             case MM_SPA_LANGUAGE:
    5289           1 :                 pszString = pszEsp;
    5290           1 :                 break;
    5291         658 :             default:
    5292             :             case MM_ENG_LANGUAGE:
    5293         658 :                 pszString = pszEng;
    5294         658 :                 break;
    5295             :         }
    5296         660 :         if (pszString)
    5297             :         {
    5298         660 :             VSIFPrintfL(pF, "%s", KEY_descriptor);
    5299         660 :             VSIFPrintfL(pF, "=");
    5300         660 :             VSIFPrintfL(pF, "%s", pszString);
    5301         660 :             VSIFPrintfL(pF, "%s", LineReturn);
    5302             :         }
    5303             :     }
    5304         759 : }
    5305             : 
    5306             : /*
    5307             :     Writes a MiraMon REL 4 metadata file. Next sections are included:
    5308             :     VERSION, METADADES, IDENTIFICATION, EXTENT, OVERVIEW,
    5309             :     TAULA_PRINCIPAL and GEOMETRIA_I_TOPOLOGIA
    5310             : 
    5311             :     Please, consult the meaning of all them at:
    5312             :     https://www.miramon.cat/help/eng/GeMPlus/ClausREL.htm
    5313             : 
    5314             :     This file must be written in ANSI encoding; therefore, some
    5315             :     conversions are performed for strings that may originally
    5316             :     be in UTF-8.
    5317             : */
    5318         177 : static int MMWriteMetadataFile(struct MiraMonVectorMetaData *hMMMD)
    5319             : {
    5320             :     char aMessage[MM_MESSAGE_LENGTH],
    5321             :         aFileIdentifier[MM_MAX_LEN_LAYER_IDENTIFIER], aMMIDSRS[MM_MAX_ID_SNY];
    5322             :     char *pszChaiCP1252;
    5323             :     MM_EXT_DBF_N_FIELDS nIField;
    5324             :     VSILFILE *pF;
    5325             :     time_t currentTime;
    5326             :     char aTimeString[200];
    5327             : 
    5328         177 :     if (!hMMMD->aLayerName)
    5329           0 :         return 0;
    5330             : 
    5331         177 :     if (nullptr == (pF = VSIFOpenL(hMMMD->aLayerName, "wb")))
    5332             :     {
    5333           0 :         CPLError(CE_Failure, CPLE_OpenFailed, "The file %s must exist.",
    5334             :                  hMMMD->aLayerName);
    5335           0 :         return 1;
    5336             :     }
    5337             : 
    5338             :     // Writing MiraMon version section
    5339         177 :     VSIFPrintfL(pF, "[%s]" LineReturn, SECTION_VERSIO);
    5340             : 
    5341         177 :     VSIFPrintfL(pF, "%s=%u" LineReturn, KEY_Vers, (unsigned)MM_VERS);
    5342         177 :     VSIFPrintfL(pF, "%s=%u" LineReturn, KEY_SubVers, (unsigned)MM_SUBVERS);
    5343             : 
    5344         177 :     VSIFPrintfL(pF, "%s=%u" LineReturn, KEY_VersMetaDades,
    5345             :                 (unsigned)MM_VERS_METADADES);
    5346         177 :     VSIFPrintfL(pF, "%s=%u" LineReturn, KEY_SubVersMetaDades,
    5347             :                 (unsigned)MM_SUBVERS_METADADES);
    5348             : 
    5349             :     // Writing METADADES section
    5350         177 :     VSIFPrintfL(pF, "\r\n[%s]" LineReturn, SECTION_METADADES);
    5351         177 :     CPLStrlcpy(aMessage, hMMMD->aLayerName, sizeof(aMessage));
    5352         177 :     MMGenerateFileIdentifierFromMetadataFileName(aMessage, aFileIdentifier);
    5353             : 
    5354         177 :     pszChaiCP1252 = CPLRecode(aFileIdentifier, CPL_ENC_UTF8, "CP1252");
    5355         177 :     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_FileIdentifier,
    5356             :                 pszChaiCP1252 ? pszChaiCP1252 : aFileIdentifier);
    5357         177 :     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_language, KEY_Value_eng);
    5358         177 :     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_MDIdiom, KEY_Value_eng);
    5359         177 :     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_characterSet,
    5360             :                 KEY_Value_characterSet);
    5361             : 
    5362             :     // Writing IDENTIFICATION section
    5363         177 :     VSIFPrintfL(pF, LineReturn "[%s]" LineReturn, SECTION_IDENTIFICATION);
    5364         177 :     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_code,
    5365             :                 pszChaiCP1252 ? pszChaiCP1252 : aFileIdentifier);
    5366         177 :     VSIFPrintfL(pF, "%s=" LineReturn, KEY_codeSpace);
    5367         177 :     CPLFree(pszChaiCP1252);  // Not needed
    5368         177 :     if (hMMMD->szLayerTitle && !MMIsEmptyString(hMMMD->szLayerTitle))
    5369             :     {
    5370         177 :         pszChaiCP1252 = CPLRecode(hMMMD->szLayerTitle, CPL_ENC_UTF8, "CP1252");
    5371         177 :         if (hMMMD->ePlainLT == MM_LayerType_Point)
    5372          34 :             VSIFPrintfL(pF, "%s=%s (pnt)" LineReturn, KEY_DatasetTitle,
    5373             :                         pszChaiCP1252 ? pszChaiCP1252 : hMMMD->szLayerTitle);
    5374         177 :         if (hMMMD->ePlainLT == MM_LayerType_Arc)
    5375          58 :             VSIFPrintfL(pF, "%s=%s (arc)" LineReturn, KEY_DatasetTitle,
    5376             :                         pszChaiCP1252 ? pszChaiCP1252 : hMMMD->szLayerTitle);
    5377         177 :         if (hMMMD->ePlainLT == MM_LayerType_Pol)
    5378          27 :             VSIFPrintfL(pF, "%s=%s (pol)" LineReturn, KEY_DatasetTitle,
    5379             :                         pszChaiCP1252 ? pszChaiCP1252 : hMMMD->szLayerTitle);
    5380         177 :         CPLFree(pszChaiCP1252);
    5381             :     }
    5382         177 :     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_language, KEY_Value_eng);
    5383             : 
    5384         177 :     if (hMMMD->ePlainLT != MM_LayerType_Node &&
    5385         119 :         hMMMD->ePlainLT != MM_LayerType_Pol)
    5386             :     {
    5387             :         // SPATIAL_REFERENCE_SYSTEM:HORIZONTAL
    5388          92 :         VSIFPrintfL(pF, LineReturn "[%s:%s]" LineReturn,
    5389             :                     SECTION_SPATIAL_REFERENCE_SYSTEM, SECTION_HORIZONTAL);
    5390         113 :         if (!ReturnMMIDSRSFromEPSGCodeSRS(hMMMD->pSRS, aMMIDSRS) &&
    5391          21 :             !MMIsEmptyString(aMMIDSRS))
    5392          21 :             VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_HorizontalSystemIdentifier,
    5393             :                         aMMIDSRS);
    5394             :         else
    5395             :         {
    5396          71 :             CPLError(CE_Warning, CPLE_NotSupported,
    5397             :                      "The MiraMon driver cannot assign any HRS.");
    5398             :             // Horizontal Reference System
    5399          71 :             VSIFPrintfL(pF, "%s=plane" LineReturn,
    5400             :                         KEY_HorizontalSystemIdentifier);
    5401          71 :             VSIFPrintfL(pF, "%s=local" LineReturn,
    5402             :                         KEY_HorizontalSystemDefinition);
    5403          71 :             if (hMMMD->pXUnit)
    5404           0 :                 VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_unitats, hMMMD->pXUnit);
    5405          71 :             if (hMMMD->pYUnit)
    5406             :             {
    5407           0 :                 if (!hMMMD->pXUnit || strcasecmp(hMMMD->pXUnit, hMMMD->pYUnit))
    5408           0 :                     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_unitatsY,
    5409             :                                 hMMMD->pYUnit);
    5410             :             }
    5411             :         }
    5412             : 
    5413             :         // SPATIAL_REFERENCE_SYSTEM:VERTICAL
    5414             :         // Llegim les unitats del Sist. ref. vertical
    5415          92 :         if (hMMMD->pZUnit)
    5416             :         {
    5417           0 :             VSIFPrintfL(pF, LineReturn "[%s:%s]" LineReturn,
    5418             :                         SECTION_SPATIAL_REFERENCE_SYSTEM, SECTION_VERTICAL);
    5419           0 :             VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_unitats, hMMMD->pZUnit);
    5420             :         }
    5421             :     }
    5422             : 
    5423         177 :     if (hMMMD->ePlainLT == MM_LayerType_Pol && hMMMD->aArcFile)
    5424             :     {
    5425             :         // Writing OVERVIEW:ASPECTES_TECNICS in polygon metadata file.
    5426             :         // ArcSource=fitx_pol.arc
    5427          27 :         pszChaiCP1252 = CPLRecode(hMMMD->aArcFile, CPL_ENC_UTF8, "CP1252");
    5428          27 :         VSIFPrintfL(pF, LineReturn "[%s]" LineReturn,
    5429             :                     SECTION_OVVW_ASPECTES_TECNICS);
    5430          27 :         VSIFPrintfL(pF, "%s=\"%s\"" LineReturn, KEY_ArcSource, pszChaiCP1252);
    5431          27 :         CPLFree(pszChaiCP1252);
    5432             :     }
    5433         150 :     else if (hMMMD->ePlainLT == MM_LayerType_Arc && hMMMD->aArcFile)
    5434             :     {
    5435          27 :         pszChaiCP1252 = CPLRecode(hMMMD->aArcFile, CPL_ENC_UTF8, "CP1252");
    5436             :         // Writing OVERVIEW:ASPECTES_TECNICS in arc metadata file.
    5437             :         // Ciclat1=fitx_arc.pol
    5438          27 :         VSIFPrintfL(pF, LineReturn "[%s]" LineReturn,
    5439             :                     SECTION_OVVW_ASPECTES_TECNICS);
    5440          27 :         VSIFPrintfL(pF, "Ciclat1=\"%s\"" LineReturn, pszChaiCP1252);
    5441          27 :         CPLFree(pszChaiCP1252);
    5442             :     }
    5443             : 
    5444             :     // Writing EXTENT section
    5445         177 :     VSIFPrintfL(pF, LineReturn "[%s]" LineReturn, SECTION_EXTENT);
    5446         177 :     VSIFPrintfL(pF, "%s=0" LineReturn, KEY_toler_env);
    5447             : 
    5448         177 :     if (hMMMD->hBB.dfMinX != MM_UNDEFINED_STATISTICAL_VALUE &&
    5449         177 :         hMMMD->hBB.dfMaxX != -MM_UNDEFINED_STATISTICAL_VALUE &&
    5450         177 :         hMMMD->hBB.dfMinY != MM_UNDEFINED_STATISTICAL_VALUE &&
    5451         177 :         hMMMD->hBB.dfMaxY != -MM_UNDEFINED_STATISTICAL_VALUE)
    5452             :     {
    5453         177 :         VSIFPrintfL(pF, "%s=%lf" LineReturn, KEY_MinX, hMMMD->hBB.dfMinX);
    5454         177 :         VSIFPrintfL(pF, "%s=%lf" LineReturn, KEY_MaxX, hMMMD->hBB.dfMaxX);
    5455         177 :         VSIFPrintfL(pF, "%s=%lf" LineReturn, KEY_MinY, hMMMD->hBB.dfMinY);
    5456         177 :         VSIFPrintfL(pF, "%s=%lf" LineReturn, KEY_MaxY, hMMMD->hBB.dfMaxY);
    5457             :     }
    5458             : 
    5459             :     // Writing OVERVIEW section
    5460         177 :     VSIFPrintfL(pF, LineReturn "[%s]" LineReturn, SECTION_OVERVIEW);
    5461             : 
    5462         177 :     currentTime = time(nullptr);
    5463             : 
    5464             :     struct tm ltime;
    5465         177 :     VSILocalTime(&currentTime, &ltime);
    5466         177 :     snprintf(aTimeString, sizeof(aTimeString), "%04d%02d%02d %02d%02d%02d%02d",
    5467         177 :              ltime.tm_year + 1900, ltime.tm_mon + 1, ltime.tm_mday,
    5468             :              ltime.tm_hour, ltime.tm_min, ltime.tm_sec, 0);
    5469         177 :     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_CreationDate, aTimeString);
    5470         177 :     VSIFPrintfL(pF, LineReturn);
    5471             : 
    5472             :     // Writing TAULA_PRINCIPAL section
    5473         177 :     VSIFPrintfL(pF, "[%s]" LineReturn, SECTION_TAULA_PRINCIPAL);
    5474         177 :     VSIFPrintfL(pF, "IdGrafic=%s" LineReturn, szMMNomCampIdGraficDefecte);
    5475         177 :     VSIFPrintfL(pF, "TipusRelacio=RELACIO_1_1_DICC" LineReturn);
    5476             : 
    5477         177 :     VSIFPrintfL(pF, LineReturn);
    5478         177 :     VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5479             :                 szMMNomCampIdGraficDefecte);
    5480         177 :     VSIFPrintfL(pF, "visible=0" LineReturn);
    5481         177 :     VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5482             : 
    5483         177 :     MMWrite_ANSI_MetadataKeyDescriptor(
    5484             :         hMMMD, pF, szInternalGraphicIdentifierEng,
    5485             :         szInternalGraphicIdentifierCat, szInternalGraphicIdentifierSpa,
    5486             :         CPL_ENC_ISO8859_1);
    5487             : 
    5488         177 :     if (hMMMD->ePlainLT == MM_LayerType_Arc)
    5489             :     {
    5490          58 :         VSIFPrintfL(pF, LineReturn);
    5491          58 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5492             :                     szMMNomCampNVertexsDefecte);
    5493          58 :         VSIFPrintfL(pF, "visible=0" LineReturn);
    5494          58 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5495          58 :         MMWrite_ANSI_MetadataKeyDescriptor(
    5496             :             hMMMD, pF, szNumberOfVerticesEng, szNumberOfVerticesCat,
    5497             :             szNumberOfVerticesSpa, CPL_ENC_ISO8859_1);
    5498             : 
    5499          58 :         VSIFPrintfL(pF, LineReturn);
    5500          58 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5501             :                     szMMNomCampLongitudArcDefecte);
    5502          58 :         MMWrite_ANSI_MetadataKeyDescriptor(hMMMD, pF, szLengthOfAarcEng,
    5503             :                                            szLengthOfAarcCat, szLengthOfAarcSpa,
    5504             :                                            CPL_ENC_ISO8859_1);
    5505             : 
    5506          58 :         VSIFPrintfL(pF, LineReturn);
    5507          58 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5508             :                     szMMNomCampNodeIniDefecte);
    5509          58 :         VSIFPrintfL(pF, "visible=0" LineReturn);
    5510          58 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5511          58 :         MMWrite_ANSI_MetadataKeyDescriptor(hMMMD, pF, szInitialNodeEng,
    5512             :                                            szInitialNodeCat, szInitialNodeSpa,
    5513             :                                            CPL_ENC_ISO8859_1);
    5514             : 
    5515          58 :         VSIFPrintfL(pF, LineReturn);
    5516          58 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5517             :                     szMMNomCampNodeFiDefecte);
    5518          58 :         VSIFPrintfL(pF, "visible=0" LineReturn);
    5519          58 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5520          58 :         MMWrite_ANSI_MetadataKeyDescriptor(hMMMD, pF, szFinalNodeEng,
    5521             :                                            szFinalNodeCat, szFinalNodeSpa,
    5522             :                                            CPL_ENC_ISO8859_1);
    5523             : 
    5524          58 :         VSIFPrintfL(pF, LineReturn);
    5525          58 :         VSIFPrintfL(pF, "[GEOMETRIA_I_TOPOLOGIA]" LineReturn);
    5526          58 :         VSIFPrintfL(pF, "NomCampNVertexs=%s" LineReturn,
    5527             :                     szMMNomCampNVertexsDefecte);
    5528          58 :         VSIFPrintfL(pF, "NomCampLongitudArc=%s" LineReturn,
    5529             :                     szMMNomCampLongitudArcDefecte);
    5530          58 :         VSIFPrintfL(pF, "NomCampNodeIni=%s" LineReturn,
    5531             :                     szMMNomCampNodeIniDefecte);
    5532          58 :         VSIFPrintfL(pF, "NomCampNodeFi=%s" LineReturn,
    5533             :                     szMMNomCampNodeFiDefecte);
    5534             :     }
    5535         119 :     else if (hMMMD->ePlainLT == MM_LayerType_Node)
    5536             :     {
    5537          58 :         VSIFPrintfL(pF, LineReturn);
    5538          58 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5539             :                     szMMNomCampArcsANodeDefecte);
    5540          58 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5541          58 :         MMWrite_ANSI_MetadataKeyDescriptor(
    5542             :             hMMMD, pF, szNumberOfArcsToNodeEng, szNumberOfArcsToNodeCat,
    5543             :             szNumberOfArcsToNodeSpa, CPL_ENC_ISO8859_1);
    5544             : 
    5545          58 :         VSIFPrintfL(pF, LineReturn);
    5546          58 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5547             :                     szMMNomCampTipusNodeDefecte);
    5548          58 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5549          58 :         MMWrite_ANSI_MetadataKeyDescriptor(hMMMD, pF, szNodeTypeEng,
    5550             :                                            szNodeTypeCat, szNodeTypeSpa,
    5551             :                                            CPL_ENC_ISO8859_1);
    5552             : 
    5553          58 :         VSIFPrintfL(pF, LineReturn);
    5554          58 :         VSIFPrintfL(pF, "[GEOMETRIA_I_TOPOLOGIA]" LineReturn);
    5555          58 :         VSIFPrintfL(pF, "NomCampArcsANode=%s" LineReturn,
    5556             :                     szMMNomCampArcsANodeDefecte);
    5557          58 :         VSIFPrintfL(pF, "NomCampTipusNode=%s" LineReturn,
    5558             :                     szMMNomCampTipusNodeDefecte);
    5559             :     }
    5560          61 :     else if (hMMMD->ePlainLT == MM_LayerType_Pol)
    5561             :     {
    5562          27 :         VSIFPrintfL(pF, LineReturn);
    5563          27 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5564             :                     szMMNomCampNVertexsDefecte);
    5565          27 :         VSIFPrintfL(pF, "visible=0" LineReturn);
    5566          27 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5567          27 :         MMWrite_ANSI_MetadataKeyDescriptor(
    5568             :             hMMMD, pF, szNumberOfVerticesEng, szNumberOfVerticesCat,
    5569             :             szNumberOfVerticesSpa, CPL_ENC_ISO8859_1);
    5570             : 
    5571          27 :         VSIFPrintfL(pF, LineReturn);
    5572          27 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5573             :                     szMMNomCampPerimetreDefecte);
    5574          27 :         MMWrite_ANSI_MetadataKeyDescriptor(
    5575             :             hMMMD, pF, szPerimeterOfThePolygonEng, szPerimeterOfThePolygonCat,
    5576             :             szPerimeterOfThePolygonSpa, CPL_ENC_ISO8859_1);
    5577             : 
    5578          27 :         VSIFPrintfL(pF, LineReturn);
    5579          27 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5580             :                     szMMNomCampAreaDefecte);
    5581          27 :         MMWrite_ANSI_MetadataKeyDescriptor(
    5582             :             hMMMD, pF, szAreaOfThePolygonEng, szAreaOfThePolygonCat,
    5583             :             szAreaOfThePolygonSpa, CPL_ENC_ISO8859_1);
    5584             : 
    5585          27 :         VSIFPrintfL(pF, LineReturn);
    5586          27 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5587             :                     szMMNomCampNArcsDefecte);
    5588          27 :         VSIFPrintfL(pF, "visible=0" LineReturn);
    5589          27 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5590          27 :         MMWrite_ANSI_MetadataKeyDescriptor(hMMMD, pF, szNumberOfArcsEng,
    5591             :                                            szNumberOfArcsCat, szNumberOfArcsSpa,
    5592             :                                            CPL_ENC_ISO8859_1);
    5593             : 
    5594          27 :         VSIFPrintfL(pF, LineReturn);
    5595          27 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5596             :                     szMMNomCampNPoligonsDefecte);
    5597          27 :         VSIFPrintfL(pF, "visible=0" LineReturn);
    5598          27 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5599          27 :         MMWrite_ANSI_MetadataKeyDescriptor(
    5600             :             hMMMD, pF, szNumberOfElementaryPolygonsEng,
    5601             :             szNumberOfElementaryPolygonsCat, szNumberOfElementaryPolygonsSpa,
    5602             :             CPL_ENC_ISO8859_1);
    5603             : 
    5604          27 :         VSIFPrintfL(pF, LineReturn);
    5605          27 :         VSIFPrintfL(pF, "[GEOMETRIA_I_TOPOLOGIA]" LineReturn);
    5606          27 :         VSIFPrintfL(pF, "NomCampNVertexs=%s" LineReturn,
    5607             :                     szMMNomCampNVertexsDefecte);
    5608          27 :         VSIFPrintfL(pF, "NomCampPerimetre=%s" LineReturn,
    5609             :                     szMMNomCampPerimetreDefecte);
    5610          27 :         VSIFPrintfL(pF, "NomCampArea=%s" LineReturn, szMMNomCampAreaDefecte);
    5611          27 :         VSIFPrintfL(pF, "NomCampNArcs=%s" LineReturn, szMMNomCampNArcsDefecte);
    5612          27 :         VSIFPrintfL(pF, "NomCampNPoligons=%s" LineReturn,
    5613             :                     szMMNomCampNPoligonsDefecte);
    5614             :     }
    5615             : 
    5616         177 :     if (hMMMD->pLayerDB && hMMMD->pLayerDB->nNFields > 0)
    5617             :     {
    5618             :         // For each field of the databes
    5619         586 :         for (nIField = 0; nIField < hMMMD->pLayerDB->nNFields; nIField++)
    5620             :         {
    5621         495 :             VSIFPrintfL(pF, LineReturn "[%s:%s]" LineReturn,
    5622             :                         SECTION_TAULA_PRINCIPAL,
    5623         495 :                         hMMMD->pLayerDB->pFields[nIField].pszFieldName);
    5624             : 
    5625         495 :             if (!MMIsEmptyString(
    5626         594 :                     hMMMD->pLayerDB->pFields[nIField].pszFieldDescription) &&
    5627          99 :                 !MMIsEmptyString(
    5628          99 :                     hMMMD->pLayerDB->pFields[nIField].pszFieldName))
    5629             :             {
    5630          99 :                 MMWrite_ANSI_MetadataKeyDescriptor(
    5631             :                     hMMMD, pF,
    5632          99 :                     hMMMD->pLayerDB->pFields[nIField].pszFieldDescription,
    5633          99 :                     hMMMD->pLayerDB->pFields[nIField].pszFieldDescription,
    5634          99 :                     hMMMD->pLayerDB->pFields[nIField].pszFieldDescription,
    5635             :                     CPL_ENC_UTF8);
    5636             :             }
    5637             : 
    5638             :             // Exception in a particular case: "altura" is a catalan word that means
    5639             :             // "height". Its unit by default will be "m" instead of "unknown".
    5640             :             // The same goes for "z", which easily means height.
    5641         495 :             if (EQUAL("altura",
    5642         495 :                       hMMMD->pLayerDB->pFields[nIField].pszFieldName) ||
    5643         495 :                 EQUAL("z", hMMMD->pLayerDB->pFields[nIField].pszFieldName))
    5644             :             {
    5645           0 :                 VSIFPrintfL(pF, "unitats=m" LineReturn);
    5646             :             }
    5647             :             else
    5648             :             {
    5649             :                 // By default units of field values will not be shown.
    5650         495 :                 VSIFPrintfL(pF, "MostrarUnitats=0" LineReturn);
    5651             :             }
    5652             :         }
    5653             :     }
    5654         177 :     VSIFCloseL(pF);
    5655         177 :     return 0;
    5656             : }
    5657             : 
    5658             : // Writes metadata files for MiraMon vector layers
    5659         194 : static int MMWriteVectorMetadataFile(struct MiraMonVectLayerInfo *hMiraMonLayer,
    5660             :                                      int layerPlainType, int layerMainPlainType)
    5661             : {
    5662             :     struct MiraMonVectorMetaData hMMMD;
    5663             : 
    5664         194 :     if (!hMiraMonLayer)
    5665           0 :         return 1;
    5666             : 
    5667             :     // MiraMon writes a REL file of each .pnt, .arc, .nod or .pol
    5668         194 :     memset(&hMMMD, 0, sizeof(hMMMD));
    5669         194 :     hMMMD.ePlainLT = layerPlainType;
    5670         194 :     hMMMD.pSRS = hMiraMonLayer->pSRS;
    5671         194 :     hMMMD.pZUnit = hMiraMonLayer->pZUnit;
    5672         194 :     hMMMD.nMMLanguage = hMiraMonLayer->nMMLanguage;
    5673             : 
    5674         194 :     hMMMD.szLayerTitle = hMiraMonLayer->szLayerTitle;
    5675         194 :     if (layerPlainType == MM_LayerType_Point)
    5676             :     {
    5677          34 :         hMMMD.aLayerName = hMiraMonLayer->MMPoint.pszREL_LayerName;
    5678          34 :         if (MMIsEmptyString(hMMMD.aLayerName))
    5679           0 :             return 0;  // If no file, no error. Just continue.
    5680          34 :         memcpy(&hMMMD.hBB, &hMiraMonLayer->TopHeader.hBB, sizeof(hMMMD.hBB));
    5681          34 :         hMMMD.pLayerDB = hMiraMonLayer->pLayerDB;
    5682          34 :         return MMWriteMetadataFile(&hMMMD);
    5683             :     }
    5684         160 :     else if (layerPlainType == MM_LayerType_Arc)
    5685             :     {
    5686             :         int nResult;
    5687             : 
    5688             :         // Arcs and not polygons
    5689          58 :         if (layerMainPlainType == MM_LayerType_Arc)
    5690             :         {
    5691          31 :             hMMMD.aLayerName = hMiraMonLayer->MMArc.pszREL_LayerName;
    5692          31 :             if (MMIsEmptyString(hMMMD.aLayerName))
    5693           0 :                 return 0;  // If no file, no error. Just continue.
    5694          31 :             memcpy(&hMMMD.hBB, &hMiraMonLayer->TopHeader.hBB,
    5695             :                    sizeof(hMMMD.hBB));
    5696          31 :             hMMMD.pLayerDB = hMiraMonLayer->pLayerDB;
    5697             :         }
    5698             :         // Arcs and polygons
    5699             :         else
    5700             :         {
    5701             :             // Arc from polygon
    5702          27 :             hMMMD.aLayerName = hMiraMonLayer->MMPolygon.MMArc.pszREL_LayerName;
    5703          27 :             if (MMIsEmptyString(hMMMD.aLayerName))
    5704           0 :                 return 0;  // If no file, no error. Just continue.
    5705             : 
    5706          27 :             memcpy(&hMMMD.hBB, &hMiraMonLayer->MMPolygon.TopArcHeader.hBB,
    5707             :                    sizeof(hMMMD.hBB));
    5708          27 :             hMMMD.pLayerDB = nullptr;
    5709          27 :             hMMMD.aArcFile = CPLStrdup(
    5710          27 :                 CPLGetFilename(hMiraMonLayer->MMPolygon.pszLayerName));
    5711             :         }
    5712          58 :         nResult = MMWriteMetadataFile(&hMMMD);
    5713          58 :         VSIFree(hMMMD.aArcFile);
    5714          58 :         return nResult;
    5715             :     }
    5716         102 :     else if (layerPlainType == MM_LayerType_Pol)
    5717             :     {
    5718             :         int nResult;
    5719             : 
    5720          27 :         hMMMD.aLayerName = hMiraMonLayer->MMPolygon.pszREL_LayerName;
    5721             : 
    5722          27 :         if (MMIsEmptyString(hMMMD.aLayerName))
    5723           0 :             return 0;  // If no file, no error. Just continue.
    5724             : 
    5725          27 :         memcpy(&hMMMD.hBB, &hMiraMonLayer->TopHeader.hBB, sizeof(hMMMD.hBB));
    5726          27 :         hMMMD.pLayerDB = hMiraMonLayer->pLayerDB;
    5727          27 :         hMMMD.aArcFile = CPLStrdup(
    5728          27 :             CPLGetFilename(hMiraMonLayer->MMPolygon.MMArc.pszLayerName));
    5729          27 :         nResult = MMWriteMetadataFile(&hMMMD);
    5730          27 :         VSIFree(hMMMD.aArcFile);
    5731          27 :         return nResult;
    5732             :     }
    5733          75 :     else if (layerPlainType == MM_LayerType_Node)
    5734             :     {
    5735             :         // Node from arc
    5736          58 :         if (layerMainPlainType == MM_LayerType_Arc)
    5737             :         {
    5738          31 :             hMMMD.aLayerName = hMiraMonLayer->MMArc.MMNode.pszREL_LayerName;
    5739          31 :             if (MMIsEmptyString(hMMMD.aLayerName))
    5740           0 :                 return 0;  // If no file, no error. Just continue.
    5741          31 :             memcpy(&hMMMD.hBB, &hMiraMonLayer->MMArc.TopNodeHeader.hBB,
    5742             :                    sizeof(hMMMD.hBB));
    5743             :         }
    5744             :         else  // Node from polygon
    5745             :         {
    5746          27 :             hMMMD.aLayerName =
    5747          27 :                 hMiraMonLayer->MMPolygon.MMArc.MMNode.pszREL_LayerName;
    5748          27 :             if (MMIsEmptyString(hMMMD.aLayerName))
    5749           0 :                 return 0;  // If no file, no error. Just continue.
    5750          27 :             memcpy(&hMMMD.hBB,
    5751          27 :                    &hMiraMonLayer->MMPolygon.MMArc.TopNodeHeader.hBB,
    5752             :                    sizeof(hMMMD.hBB));
    5753             :         }
    5754          58 :         hMMMD.pLayerDB = nullptr;
    5755          58 :         return MMWriteMetadataFile(&hMMMD);
    5756             :     }
    5757          17 :     return 0;
    5758             : }
    5759             : 
    5760         109 : int MMWriteVectorMetadata(struct MiraMonVectLayerInfo *hMiraMonLayer)
    5761             : {
    5762         109 :     if (!hMiraMonLayer)
    5763           0 :         return 1;
    5764             : 
    5765         109 :     if (hMiraMonLayer->bIsPoint)
    5766          34 :         return MMWriteVectorMetadataFile(hMiraMonLayer, MM_LayerType_Point,
    5767             :                                          MM_LayerType_Point);
    5768          75 :     if (hMiraMonLayer->bIsArc && !hMiraMonLayer->bIsPolygon)
    5769             :     {
    5770          31 :         if (MMWriteVectorMetadataFile(hMiraMonLayer, MM_LayerType_Node,
    5771             :                                       MM_LayerType_Arc))
    5772           0 :             return 1;
    5773          31 :         return MMWriteVectorMetadataFile(hMiraMonLayer, MM_LayerType_Arc,
    5774             :                                          MM_LayerType_Arc);
    5775             :     }
    5776          44 :     if (hMiraMonLayer->bIsPolygon)
    5777             :     {
    5778          27 :         if (MMWriteVectorMetadataFile(hMiraMonLayer, MM_LayerType_Node,
    5779             :                                       MM_LayerType_Pol))
    5780           0 :             return 1;
    5781          27 :         if (MMWriteVectorMetadataFile(hMiraMonLayer, MM_LayerType_Arc,
    5782             :                                       MM_LayerType_Pol))
    5783           0 :             return 1;
    5784          27 :         return MMWriteVectorMetadataFile(hMiraMonLayer, MM_LayerType_Pol,
    5785             :                                          MM_LayerType_Pol);
    5786             :     }
    5787          17 :     if (hMiraMonLayer->bIsDBF)
    5788             :     {
    5789          17 :         return MMWriteVectorMetadataFile(hMiraMonLayer, MM_LayerType_Unknown,
    5790             :                                          MM_LayerType_Unknown);
    5791             :     }
    5792           0 :     return 0;
    5793             : }
    5794             : 
    5795             : /* -------------------------------------------------------------------- */
    5796             : /*      MiraMon database functions                                      */
    5797             : /* -------------------------------------------------------------------- */
    5798             : 
    5799             : // Initializes a MiraMon database associated with a vector layer:
    5800             : // Sets the usual fields that MiraMon needs and after them, adds
    5801             : // all fields of the input layer
    5802         194 : static int MMInitMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    5803             :                       struct MMAdmDatabase *pMMAdmDB)
    5804             : {
    5805         194 :     if (!hMiraMonLayer || !pMMAdmDB)
    5806           0 :         return 1;
    5807             : 
    5808         194 :     if (MMIsEmptyString(pMMAdmDB->pszExtDBFLayerName))
    5809           0 :         return 0;  // No file, no error. Just continue
    5810             : 
    5811         194 :     strcpy(pMMAdmDB->pMMBDXP->ReadingMode, "wb+");
    5812         194 :     if (FALSE == MM_CreateAndOpenDBFFile(pMMAdmDB->pMMBDXP,
    5813         194 :                                          pMMAdmDB->pszExtDBFLayerName))
    5814             :     {
    5815           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
    5816             :                  "Error pMMAdmDB: Cannot create or open file %s.",
    5817           0 :                  pMMAdmDB->pszExtDBFLayerName);
    5818           0 :         return 1;
    5819             :     }
    5820             : 
    5821         194 :     VSIFSeekL(pMMAdmDB->pMMBDXP->pfDataBase,
    5822         194 :               pMMAdmDB->pMMBDXP->FirstRecordOffset, SEEK_SET);
    5823             : 
    5824         194 :     if (MMInitFlush(&pMMAdmDB->FlushRecList, pMMAdmDB->pMMBDXP->pfDataBase,
    5825             :                     MM_1MB, &pMMAdmDB->pRecList,
    5826         194 :                     pMMAdmDB->pMMBDXP->FirstRecordOffset, 0))
    5827           0 :         return 1;
    5828             : 
    5829         194 :     pMMAdmDB->nNumRecordOnCourse =
    5830         194 :         (GUInt64)pMMAdmDB->pMMBDXP->BytesPerRecord + 1;
    5831         194 :     if (MMCheckSize_t(pMMAdmDB->nNumRecordOnCourse, 1))
    5832           0 :         return 1;
    5833         194 :     pMMAdmDB->szRecordOnCourse =
    5834         194 :         VSICalloc(1, (size_t)pMMAdmDB->nNumRecordOnCourse);
    5835         194 :     if (!pMMAdmDB->szRecordOnCourse)
    5836             :     {
    5837           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    5838             :                  "Memory error in MiraMon "
    5839             :                  "driver (MMInitMMDB())");
    5840           0 :         return 1;
    5841             :     }
    5842         194 :     return 0;
    5843             : }
    5844             : 
    5845             : // Creates a MiraMon database associated with a vector layer.
    5846             : // It determines the number of fields and initializes the database header
    5847             : // accordingly. Depending on the layer type (point, arc, polygon, or generic),
    5848             : // it defines the fields and initializes the corresponding MiraMon database
    5849             : // structures.
    5850         109 : int MMCreateMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    5851             :                  struct MM_POINT_2D *pFirstCoord)
    5852             : {
    5853         109 :     struct MM_DATA_BASE_XP *pBD_XP = nullptr, *pBD_XP_Aux = nullptr;
    5854             :     struct MM_FIELD MMField;
    5855             :     size_t nIFieldLayer;
    5856         109 :     MM_EXT_DBF_N_FIELDS nIField = 0;
    5857             :     MM_EXT_DBF_N_FIELDS nNFields;
    5858             : 
    5859         109 :     if (!hMiraMonLayer)
    5860           0 :         return 1;
    5861             : 
    5862             :     // If the SRS is unknown, we attempt to deduce the appropriate number
    5863             :     // of decimals to be used in the reserved fields as LONG_ARC, PERIMETRE,
    5864             :     // or AREA using the coordinate values. It's not 100% reliable, but it's a
    5865             :     // good approximation.
    5866         109 :     if (hMiraMonLayer->nSRSType == MM_SRS_LAYER_IS_UNKNOWN_TYPE && pFirstCoord)
    5867             :     {
    5868          71 :         if (pFirstCoord->dfX < -360 || pFirstCoord->dfX > 360)
    5869           8 :             hMiraMonLayer->nSRSType = MM_SRS_LAYER_IS_PROJECTED_TYPE;
    5870             :         else
    5871          63 :             hMiraMonLayer->nSRSType = MM_SRS_LAYER_IS_GEOGRAPHIC_TYPE;
    5872             :     }
    5873             : 
    5874         109 :     if (hMiraMonLayer->bIsPoint)
    5875             :     {
    5876          34 :         if (hMiraMonLayer->pLayerDB)
    5877          34 :             nNFields =
    5878          34 :                 MM_PRIVATE_POINT_DB_FIELDS + hMiraMonLayer->pLayerDB->nNFields;
    5879             :         else
    5880           0 :             nNFields = MM_PRIVATE_POINT_DB_FIELDS;
    5881             : 
    5882             :         // Before allocating new memory, there might be some previously allocated but unused memory.
    5883             :         // Let's free that memory first.
    5884          34 :         if (hMiraMonLayer->MMPoint.MMAdmDB.pMMBDXP)
    5885           0 :             MM_ReleaseDBFHeader(&hMiraMonLayer->MMPoint.MMAdmDB.pMMBDXP);
    5886             : 
    5887          34 :         pBD_XP = hMiraMonLayer->MMPoint.MMAdmDB.pMMBDXP =
    5888          34 :             MM_CreateDBFHeader(nNFields, hMiraMonLayer->nCharSet);
    5889             : 
    5890          34 :         if (!pBD_XP)
    5891           0 :             return 1;
    5892             : 
    5893          34 :         if (0 == (nIField = (MM_EXT_DBF_N_FIELDS)MM_DefineFirstPointFieldsDB_XP(
    5894             :                       pBD_XP)))
    5895           0 :             return 1;
    5896             :     }
    5897          75 :     else if (hMiraMonLayer->bIsArc && !hMiraMonLayer->bIsPolygon)
    5898             :     {
    5899          31 :         if (hMiraMonLayer->pLayerDB)
    5900          30 :             nNFields =
    5901          30 :                 MM_PRIVATE_ARC_DB_FIELDS + hMiraMonLayer->pLayerDB->nNFields;
    5902             :         else
    5903           1 :             nNFields = MM_PRIVATE_ARC_DB_FIELDS;
    5904             : 
    5905             :         // Before allocating new memory, there might be some previously allocated but unused memory.
    5906             :         // Let's free that memory first.
    5907          31 :         if (hMiraMonLayer->MMArc.MMAdmDB.pMMBDXP)
    5908           0 :             MM_ReleaseDBFHeader(&hMiraMonLayer->MMArc.MMAdmDB.pMMBDXP);
    5909             : 
    5910          31 :         pBD_XP = hMiraMonLayer->MMArc.MMAdmDB.pMMBDXP =
    5911          31 :             MM_CreateDBFHeader(nNFields, hMiraMonLayer->nCharSet);
    5912             : 
    5913          31 :         if (!pBD_XP)
    5914           0 :             return 1;
    5915             : 
    5916          31 :         if (0 == (nIField = (MM_EXT_DBF_N_FIELDS)MM_DefineFirstArcFieldsDB_XP(
    5917             :                       pBD_XP,
    5918          31 :                       hMiraMonLayer->nSRSType == MM_SRS_LAYER_IS_PROJECTED_TYPE
    5919             :                           ? 3
    5920             :                           : 9)))
    5921           0 :             return 1;
    5922             : 
    5923             :         // Before allocating new memory, there might be some previously allocated but unused memory.
    5924             :         // Let's free that memory first.
    5925          31 :         if (hMiraMonLayer->MMArc.MMNode.MMAdmDB.pMMBDXP)
    5926           0 :             MM_ReleaseDBFHeader(&hMiraMonLayer->MMArc.MMNode.MMAdmDB.pMMBDXP);
    5927             : 
    5928          31 :         pBD_XP_Aux = hMiraMonLayer->MMArc.MMNode.MMAdmDB.pMMBDXP =
    5929          31 :             MM_CreateDBFHeader(3, hMiraMonLayer->nCharSet);
    5930             : 
    5931          31 :         if (!pBD_XP_Aux)
    5932           0 :             return 1;
    5933             : 
    5934          31 :         if (0 == MM_DefineFirstNodeFieldsDB_XP(pBD_XP_Aux))
    5935           0 :             return 1;
    5936             :     }
    5937          44 :     else if (hMiraMonLayer->bIsPolygon)
    5938             :     {
    5939          27 :         if (hMiraMonLayer->pLayerDB)
    5940          27 :             nNFields = MM_PRIVATE_POLYGON_DB_FIELDS +
    5941          27 :                        hMiraMonLayer->pLayerDB->nNFields;
    5942             :         else
    5943           0 :             nNFields = MM_PRIVATE_POLYGON_DB_FIELDS;
    5944             : 
    5945             :         // Before allocating new memory, there might be some previously allocated but unused memory.
    5946             :         // Let's free that memory first.
    5947          27 :         if (hMiraMonLayer->MMPolygon.MMAdmDB.pMMBDXP)
    5948           0 :             MM_ReleaseDBFHeader(&hMiraMonLayer->MMPolygon.MMAdmDB.pMMBDXP);
    5949             : 
    5950          27 :         pBD_XP = hMiraMonLayer->MMPolygon.MMAdmDB.pMMBDXP =
    5951          27 :             MM_CreateDBFHeader(nNFields, hMiraMonLayer->nCharSet);
    5952             : 
    5953          27 :         if (!pBD_XP)
    5954           0 :             return 1;
    5955             : 
    5956          27 :         if (0 ==
    5957          54 :             (nIField = (MM_EXT_DBF_N_FIELDS)MM_DefineFirstPolygonFieldsDB_XP(
    5958             :                  pBD_XP,
    5959          27 :                  hMiraMonLayer->nSRSType == MM_SRS_LAYER_IS_PROJECTED_TYPE ? 3
    5960             :                                                                            : 9,
    5961          27 :                  hMiraMonLayer->nSRSType == MM_SRS_LAYER_IS_PROJECTED_TYPE
    5962             :                      ? 3
    5963             :                      : 12)))
    5964           0 :             return 1;
    5965             : 
    5966             :         // Before allocating new memory, there might be some previously allocated but unused memory.
    5967             :         // Let's free that memory first.
    5968          27 :         if (hMiraMonLayer->MMPolygon.MMArc.MMAdmDB.pMMBDXP)
    5969           0 :             MM_ReleaseDBFHeader(
    5970             :                 &hMiraMonLayer->MMPolygon.MMArc.MMAdmDB.pMMBDXP);
    5971             : 
    5972          27 :         pBD_XP_Aux = hMiraMonLayer->MMPolygon.MMArc.MMAdmDB.pMMBDXP =
    5973          27 :             MM_CreateDBFHeader(5, hMiraMonLayer->nCharSet);
    5974             : 
    5975          27 :         if (!pBD_XP_Aux)
    5976           0 :             return 1;
    5977             : 
    5978          27 :         if (0 == MM_DefineFirstArcFieldsDB_XP(
    5979             :                      pBD_XP_Aux,
    5980          27 :                      hMiraMonLayer->nSRSType == MM_SRS_LAYER_IS_PROJECTED_TYPE
    5981             :                          ? 3
    5982             :                          : 9))
    5983           0 :             return 1;
    5984             : 
    5985             :         // Before allocating new memory, there might be some previously allocated but unused memory.
    5986             :         // Let's free that memory first.
    5987          27 :         if (hMiraMonLayer->MMPolygon.MMArc.MMNode.MMAdmDB.pMMBDXP)
    5988           0 :             MM_ReleaseDBFHeader(
    5989             :                 &hMiraMonLayer->MMPolygon.MMArc.MMNode.MMAdmDB.pMMBDXP);
    5990             : 
    5991          27 :         pBD_XP_Aux = hMiraMonLayer->MMPolygon.MMArc.MMNode.MMAdmDB.pMMBDXP =
    5992          27 :             MM_CreateDBFHeader(3, hMiraMonLayer->nCharSet);
    5993             : 
    5994          27 :         if (!pBD_XP_Aux)
    5995           0 :             return 1;
    5996             : 
    5997          27 :         if (0 == MM_DefineFirstNodeFieldsDB_XP(pBD_XP_Aux))
    5998           0 :             return 1;
    5999             :     }
    6000          17 :     else if (hMiraMonLayer->bIsDBF)
    6001             :     {
    6002             :         // Creating only a DBF
    6003          17 :         if (hMiraMonLayer->pLayerDB)
    6004          17 :             nNFields = hMiraMonLayer->pLayerDB->nNFields;
    6005             :         else
    6006           0 :             nNFields = 0;
    6007             : 
    6008          17 :         pBD_XP = hMiraMonLayer->MMAdmDBWriting.pMMBDXP =
    6009          17 :             MM_CreateDBFHeader(nNFields, hMiraMonLayer->nCharSet);
    6010             : 
    6011          17 :         if (!pBD_XP)
    6012           0 :             return 1;
    6013             :     }
    6014             :     else
    6015           0 :         return 0;
    6016             : 
    6017             :     // After private MiraMon fields, other fields are added.
    6018             :     // If names are no compatible, some changes are done.
    6019         109 :     if (hMiraMonLayer->pLayerDB)
    6020             :     {
    6021         684 :         for (nIFieldLayer = 0; nIField < nNFields; nIField++, nIFieldLayer++)
    6022             :         {
    6023         576 :             MM_InitializeField(&MMField);
    6024         576 :             CPLStrlcpy(
    6025             :                 MMField.FieldName,
    6026         576 :                 hMiraMonLayer->pLayerDB->pFields[nIFieldLayer].pszFieldName,
    6027             :                 MM_MAX_LON_FIELD_NAME_DBF);
    6028             : 
    6029         576 :             CPLStrlcpy(MMField.FieldDescription[0],
    6030         576 :                        hMiraMonLayer->pLayerDB->pFields[nIFieldLayer]
    6031         576 :                            .pszFieldDescription,
    6032             :                        MM_MAX_BYTES_FIELD_DESC);
    6033             : 
    6034         576 :             MMField.BytesPerField =
    6035         576 :                 hMiraMonLayer->pLayerDB->pFields[nIFieldLayer].nFieldSize;
    6036         576 :             switch (hMiraMonLayer->pLayerDB->pFields[nIFieldLayer].eFieldType)
    6037             :             {
    6038         283 :                 case MM_Numeric:
    6039         283 :                     MMField.FieldType = 'N';
    6040         283 :                     if (hMiraMonLayer->pLayerDB->pFields[nIFieldLayer]
    6041         283 :                             .bIs64BitInteger)
    6042          79 :                         MMField.Is64 = 1;
    6043         283 :                     if (MMField.BytesPerField == 0)
    6044           0 :                         MMField.BytesPerField = MM_MAX_AMPLADA_CAMP_N_DBF;
    6045         283 :                     break;
    6046         192 :                 case MM_Character:
    6047         192 :                     MMField.FieldType = 'C';
    6048         192 :                     if (MMField.BytesPerField == 0)
    6049           0 :                         MMField.BytesPerField = MM_MAX_AMPLADA_CAMP_C_DBF;
    6050         192 :                     break;
    6051          68 :                 case MM_Data:
    6052          68 :                     MMField.FieldType = 'D';
    6053          68 :                     if (MMField.BytesPerField == 0)
    6054           0 :                         MMField.BytesPerField = MM_MAX_AMPLADA_CAMP_D_DBF;
    6055          68 :                     break;
    6056          33 :                 case MM_Logic:
    6057          33 :                     MMField.FieldType = 'L';
    6058          33 :                     if (MMField.BytesPerField == 0)
    6059           0 :                         MMField.BytesPerField = 1;
    6060          33 :                     break;
    6061           0 :                 default:
    6062           0 :                     MMField.FieldType = 'C';
    6063           0 :                     if (MMField.BytesPerField == 0)
    6064           0 :                         MMField.BytesPerField = MM_MAX_AMPLADA_CAMP_C_DBF;
    6065             :             };
    6066             : 
    6067         576 :             MMField.DecimalsIfFloat =
    6068         576 :                 (MM_BYTE)hMiraMonLayer->pLayerDB->pFields[nIFieldLayer]
    6069         576 :                     .nNumberOfDecimals;
    6070             : 
    6071         576 :             MM_DuplicateFieldDBXP(pBD_XP->pField + nIField, &MMField);
    6072         576 :             MM_ModifyFieldNameAndDescriptorIfPresentBD_XP(
    6073         576 :                 pBD_XP->pField + nIField, pBD_XP, FALSE, 0);
    6074         576 :             if (pBD_XP->pField[nIField].FieldType == 'F')
    6075           0 :                 pBD_XP->pField[nIField].FieldType = 'N';
    6076             :         }
    6077             :     }
    6078             : 
    6079         109 :     if (hMiraMonLayer->bIsPoint)
    6080             :     {
    6081          34 :         if (MMInitMMDB(hMiraMonLayer, &hMiraMonLayer->MMPoint.MMAdmDB))
    6082           0 :             return 1;
    6083             :     }
    6084          75 :     else if (hMiraMonLayer->bIsArc && !hMiraMonLayer->bIsPolygon)
    6085             :     {
    6086          31 :         if (MMInitMMDB(hMiraMonLayer, &hMiraMonLayer->MMArc.MMAdmDB))
    6087           0 :             return 1;
    6088             : 
    6089          31 :         if (MMInitMMDB(hMiraMonLayer, &hMiraMonLayer->MMArc.MMNode.MMAdmDB))
    6090           0 :             return 1;
    6091             :     }
    6092          44 :     else if (hMiraMonLayer->bIsPolygon)
    6093             :     {
    6094          27 :         if (MMInitMMDB(hMiraMonLayer, &hMiraMonLayer->MMPolygon.MMAdmDB))
    6095           0 :             return 1;
    6096             : 
    6097          27 :         if (MMInitMMDB(hMiraMonLayer, &hMiraMonLayer->MMPolygon.MMArc.MMAdmDB))
    6098           0 :             return 1;
    6099             : 
    6100          27 :         if (MMInitMMDB(hMiraMonLayer,
    6101             :                        &hMiraMonLayer->MMPolygon.MMArc.MMNode.MMAdmDB))
    6102           0 :             return 1;
    6103             :     }
    6104          17 :     else if (hMiraMonLayer->bIsDBF)
    6105             :     {
    6106          17 :         if (MMInitMMDB(hMiraMonLayer, &hMiraMonLayer->MMAdmDBWriting))
    6107           0 :             return 1;
    6108             :     }
    6109         109 :     return 0;
    6110             : }
    6111             : 
    6112             : // Checks and fits the width of a specific field in a MiraMon database
    6113             : // associated with a vector layer. It examines the length of the provided
    6114             : // value and resizes the field width, if necessary, to accommodate the new
    6115             : // value. If the new width exceeds the current width of the field,
    6116             : // it updates the database structure, including the field width and
    6117             : // the size of the record. Additionally, it reallocates memory if needed
    6118             : // for the record handling buffer.
    6119             : 
    6120             : static int
    6121        2977 : MMTestAndFixValueToRecordDBXP(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6122             :                               struct MMAdmDatabase *pMMAdmDB,
    6123             :                               MM_EXT_DBF_N_FIELDS nIField, char *szValue)
    6124             : {
    6125             :     struct MM_FIELD *camp;
    6126             :     MM_BYTES_PER_FIELD_TYPE_DBF nNewWidth;
    6127             : 
    6128        2977 :     if (!hMiraMonLayer || !pMMAdmDB || !pMMAdmDB->pMMBDXP ||
    6129        2977 :         !pMMAdmDB->pMMBDXP->pField || !pMMAdmDB->pMMBDXP->pfDataBase)
    6130           0 :         return 1;
    6131             : 
    6132        2977 :     camp = pMMAdmDB->pMMBDXP->pField + nIField;
    6133             : 
    6134        2977 :     if (!szValue)
    6135         282 :         return 0;
    6136             : 
    6137        2695 :     nNewWidth = (MM_BYTES_PER_FIELD_TYPE_DBF)strlen(szValue);
    6138        2695 :     if (MMResizeStringToOperateIfNeeded(hMiraMonLayer, nNewWidth + 1))
    6139           0 :         return 1;
    6140             : 
    6141        2695 :     if (nNewWidth > camp->BytesPerField)
    6142             :     {
    6143         117 :         if (MM_WriteNRecordsMMBD_XPFile(pMMAdmDB))
    6144           0 :             return 1;
    6145             : 
    6146             :         // Flushing all to be flushed
    6147         117 :         pMMAdmDB->FlushRecList.SizeOfBlockToBeSaved = 0;
    6148         117 :         if (MMAppendBlockToBuffer(&pMMAdmDB->FlushRecList))
    6149           0 :             return 1;
    6150             : 
    6151         117 :         if (MM_ChangeDBFWidthField(
    6152             :                 pMMAdmDB->pMMBDXP, nIField, nNewWidth,
    6153         117 :                 pMMAdmDB->pMMBDXP->pField[nIField].DecimalsIfFloat))
    6154           0 :             return 1;
    6155             : 
    6156             :         // The record on course also has to change its size.
    6157         117 :         if ((GUInt64)pMMAdmDB->pMMBDXP->BytesPerRecord + 1 >=
    6158         117 :             pMMAdmDB->nNumRecordOnCourse)
    6159             :         {
    6160             :             void *pTmp;
    6161         117 :             if (nullptr == (pTmp = VSIRealloc(
    6162         117 :                                 pMMAdmDB->szRecordOnCourse,
    6163         117 :                                 (size_t)pMMAdmDB->pMMBDXP->BytesPerRecord + 1)))
    6164             :             {
    6165           0 :                 CPLError(CE_Failure, CPLE_OutOfMemory,
    6166             :                          "Memory error in MiraMon "
    6167             :                          "driver (MMTestAndFixValueToRecordDBXP())");
    6168           0 :                 return 1;
    6169             :             }
    6170         117 :             pMMAdmDB->szRecordOnCourse = pTmp;
    6171             :         }
    6172             : 
    6173             :         // File has changed its size, so it has to be updated
    6174             :         // at the Flush tool
    6175         117 :         VSIFSeekL(pMMAdmDB->pMMBDXP->pfDataBase, 0, SEEK_END);
    6176         117 :         pMMAdmDB->FlushRecList.OffsetWhereToFlush =
    6177         117 :             VSIFTellL(pMMAdmDB->pMMBDXP->pfDataBase);
    6178             :     }
    6179        2695 :     return 0;
    6180             : }
    6181             : 
    6182             : static int
    6183        3460 : MMWriteValueToszStringToOperate(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6184             :                                 const struct MM_FIELD *camp, const void *valor,
    6185             :                                 MM_BOOLEAN is_64)
    6186             : {
    6187        3460 :     if (!hMiraMonLayer)
    6188           0 :         return 1;
    6189             : 
    6190        3460 :     if (!camp)
    6191           0 :         return 0;
    6192             : 
    6193        3460 :     if (MMResizeStringToOperateIfNeeded(hMiraMonLayer,
    6194        3460 :                                         camp->BytesPerField + 10))
    6195           0 :         return 1;
    6196             : 
    6197        3460 :     if (!valor)
    6198           0 :         *hMiraMonLayer->szStringToOperate = '\0';
    6199             :     else
    6200             :     {
    6201        3460 :         if (camp->FieldType == 'N')
    6202             :         {
    6203        2862 :             if (!is_64)
    6204             :             {
    6205         972 :                 snprintf(hMiraMonLayer->szStringToOperate,
    6206         972 :                          (size_t)hMiraMonLayer->nNumStringToOperate, "%*.*f",
    6207         972 :                          camp->BytesPerField, camp->DecimalsIfFloat,
    6208             :                          *(const double *)valor);
    6209             :             }
    6210             :             else
    6211             :             {
    6212        1890 :                 snprintf(hMiraMonLayer->szStringToOperate,
    6213        1890 :                          (size_t)hMiraMonLayer->nNumStringToOperate, "%*lld",
    6214             :                          camp->BytesPerField, *(const GInt64 *)valor);
    6215             :             }
    6216             :         }
    6217             :         else
    6218             :         {
    6219         598 :             snprintf(hMiraMonLayer->szStringToOperate,
    6220         598 :                      (size_t)hMiraMonLayer->nNumStringToOperate, "%-*s",
    6221             :                      camp->BytesPerField, (const char *)valor);
    6222             :         }
    6223             :     }
    6224             : 
    6225        3460 :     return 0;
    6226             : }
    6227             : 
    6228         559 : int MMWritePreformatedNumberValueToRecordDBXP(
    6229             :     struct MiraMonVectLayerInfo *hMiraMonLayer, char *registre,
    6230             :     const struct MM_FIELD *camp, const char *valor)
    6231             : {
    6232         559 :     if (!hMiraMonLayer)
    6233           0 :         return 1;
    6234             : 
    6235         559 :     if (!camp)
    6236           0 :         return 0;
    6237             : 
    6238         559 :     if (MMResizeStringToOperateIfNeeded(hMiraMonLayer,
    6239         559 :                                         camp->BytesPerField + 10))
    6240           0 :         return 1;
    6241             : 
    6242         559 :     if (!valor)
    6243           0 :         memset(hMiraMonLayer->szStringToOperate, 0, camp->BytesPerField);
    6244             :     else
    6245             :     {
    6246         559 :         snprintf(hMiraMonLayer->szStringToOperate,
    6247         559 :                  (size_t)hMiraMonLayer->nNumStringToOperate, "%*s",
    6248             :                  camp->BytesPerField, valor);
    6249             :     }
    6250             : 
    6251         559 :     memcpy(registre + camp->AccumulatedBytes, hMiraMonLayer->szStringToOperate,
    6252         559 :            camp->BytesPerField);
    6253         559 :     return 0;
    6254             : }
    6255             : 
    6256        2135 : int MMWriteValueToRecordDBXP(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6257             :                              char *registre, const struct MM_FIELD *camp,
    6258             :                              const void *valor, MM_BOOLEAN is_64)
    6259             : {
    6260        2135 :     if (!hMiraMonLayer)
    6261           0 :         return 1;
    6262             : 
    6263        2135 :     if (!camp)
    6264           0 :         return 0;
    6265             : 
    6266        2135 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, camp, valor, is_64))
    6267           0 :         return 1;
    6268             : 
    6269        2135 :     memcpy(registre + camp->AccumulatedBytes, hMiraMonLayer->szStringToOperate,
    6270        2135 :            camp->BytesPerField);
    6271        2135 :     return 0;
    6272             : }
    6273             : 
    6274         213 : static int MMAddFeatureRecordToMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6275             :                                     struct MiraMonFeature *hMMFeature,
    6276             :                                     struct MMAdmDatabase *pMMAdmDB,
    6277             :                                     char *pszRecordOnCourse,
    6278             :                                     struct MM_FLUSH_INFO *pFlushRecList,
    6279             :                                     MM_EXT_DBF_N_RECORDS *nNumRecords,
    6280             :                                     MM_EXT_DBF_N_FIELDS nNumPrivateMMField)
    6281             : {
    6282             :     MM_EXT_DBF_N_MULTIPLE_RECORDS nIRecord;
    6283             :     MM_EXT_DBF_N_FIELDS nIField;
    6284         213 :     struct MM_DATA_BASE_XP *pBD_XP = nullptr;
    6285             : 
    6286         213 :     if (!hMiraMonLayer)
    6287           0 :         return 1;
    6288             : 
    6289         213 :     if (!hMMFeature)
    6290           0 :         return 1;
    6291             : 
    6292         213 :     pBD_XP = pMMAdmDB->pMMBDXP;
    6293         453 :     for (nIRecord = 0; nIRecord < hMMFeature->nNumMRecords; nIRecord++)
    6294             :     {
    6295        1892 :         for (nIField = 0; nIField < hMMFeature->pRecords[nIRecord].nNumField;
    6296        1652 :              nIField++)
    6297             :         {
    6298             :             // A field with no valid value is written as blank
    6299        1652 :             if (!hMMFeature->pRecords[nIRecord].pField[nIField].bIsValid)
    6300             :             {
    6301         283 :                 memset(
    6302         283 :                     pszRecordOnCourse +
    6303         283 :                         pBD_XP->pField[nIField + nNumPrivateMMField]
    6304         283 :                             .AccumulatedBytes,
    6305             :                     ' ',
    6306         283 :                     pBD_XP->pField[nIField + nNumPrivateMMField].BytesPerField);
    6307             : 
    6308         283 :                 continue;
    6309             :             }
    6310        1369 :             if (pBD_XP->pField[nIField + nNumPrivateMMField].FieldType == 'C' ||
    6311         983 :                 pBD_XP->pField[nIField + nNumPrivateMMField].FieldType == 'L' ||
    6312         880 :                 pBD_XP->pField[nIField + nNumPrivateMMField].FieldType == 'D')
    6313             :             {
    6314         598 :                 if (MMWriteValueToRecordDBXP(hMiraMonLayer, pszRecordOnCourse,
    6315         598 :                                              pBD_XP->pField + nIField +
    6316             :                                                  nNumPrivateMMField,
    6317         598 :                                              hMMFeature->pRecords[nIRecord]
    6318         598 :                                                  .pField[nIField]
    6319         598 :                                                  .pDinValue,
    6320             :                                              FALSE))
    6321           0 :                     return 1;
    6322             :             }
    6323         771 :             else if (pBD_XP->pField[nIField + nNumPrivateMMField].FieldType ==
    6324         771 :                          'N' &&
    6325         771 :                      !pBD_XP->pField[nIField + nNumPrivateMMField].Is64)
    6326             :             {
    6327         559 :                 if (MMWritePreformatedNumberValueToRecordDBXP(
    6328             :                         hMiraMonLayer, pszRecordOnCourse,
    6329         559 :                         pBD_XP->pField + nIField + nNumPrivateMMField,
    6330         559 :                         hMMFeature->pRecords[nIRecord]
    6331         559 :                             .pField[nIField]
    6332         559 :                             .pDinValue))
    6333           0 :                     return 1;
    6334             :             }
    6335         212 :             else if (pBD_XP->pField[nIField + nNumPrivateMMField].FieldType ==
    6336             :                      'N')
    6337             :             {
    6338         212 :                 if (pBD_XP->pField[nIField + nNumPrivateMMField].Is64)
    6339             :                 {
    6340         212 :                     if (MMWriteValueToRecordDBXP(
    6341             :                             hMiraMonLayer, pszRecordOnCourse,
    6342         212 :                             pBD_XP->pField + nIField + nNumPrivateMMField,
    6343         212 :                             &hMMFeature->pRecords[nIRecord]
    6344         212 :                                  .pField[nIField]
    6345             :                                  .iValue,
    6346             :                             TRUE))
    6347           0 :                         return 1;
    6348             :                 }
    6349             :             }
    6350             :         }
    6351             : 
    6352         240 :         if (MMAppendBlockToBuffer(pFlushRecList))
    6353           0 :             return 1;
    6354             : 
    6355         240 :         (*nNumRecords)++;
    6356             :     }
    6357         213 :     return 0;
    6358             : }
    6359             : 
    6360             : // Adds feature records to a MiraMon database associated with a vector layer.
    6361        1652 : static int MMDetectAndFixDBFWidthChange(
    6362             :     struct MiraMonVectLayerInfo *hMiraMonLayer,
    6363             :     struct MiraMonFeature *hMMFeature, struct MMAdmDatabase *pMMAdmDB,
    6364             :     MM_EXT_DBF_N_FIELDS nNumPrivateMMField,
    6365             :     MM_EXT_DBF_N_MULTIPLE_RECORDS nIRecord, MM_EXT_DBF_N_FIELDS nIField)
    6366             : {
    6367        1652 :     if (!hMiraMonLayer)
    6368           0 :         return 1;
    6369             : 
    6370        1652 :     if (!hMMFeature)
    6371           0 :         return 1;
    6372             : 
    6373        1652 :     if (nIRecord >= hMMFeature->nNumMRecords)
    6374           0 :         return 1;
    6375             : 
    6376        1652 :     if (nIField >= hMMFeature->pRecords[nIRecord].nNumField)
    6377           0 :         return 1;
    6378             : 
    6379        1652 :     if (MMTestAndFixValueToRecordDBXP(
    6380             :             hMiraMonLayer, pMMAdmDB, nIField + nNumPrivateMMField,
    6381        1652 :             hMMFeature->pRecords[nIRecord].pField[nIField].pDinValue))
    6382           0 :         return 1;
    6383             : 
    6384             :     // We analyze next fields
    6385        1652 :     if (nIField == hMMFeature->pRecords[nIRecord].nNumField - 1)
    6386             :     {
    6387         239 :         if (nIRecord + 1 < hMMFeature->nNumMRecords)
    6388             :         {
    6389          27 :             if (MMDetectAndFixDBFWidthChange(hMiraMonLayer, hMMFeature,
    6390             :                                              pMMAdmDB, nNumPrivateMMField,
    6391             :                                              nIRecord + 1, 0))
    6392           0 :                 return 1;
    6393             :         }
    6394             :         else
    6395         212 :             return 0;
    6396             :     }
    6397             :     else
    6398             :     {
    6399        1413 :         if (nIField + 1 < hMMFeature->pRecords[nIRecord].nNumField)
    6400             :         {
    6401        1413 :             if (MMDetectAndFixDBFWidthChange(hMiraMonLayer, hMMFeature,
    6402             :                                              pMMAdmDB, nNumPrivateMMField,
    6403             :                                              nIRecord, nIField + 1))
    6404           0 :                 return 1;
    6405             :         }
    6406             :         else
    6407           0 :             return 0;
    6408             :     }
    6409        1440 :     return 0;
    6410             : }  // End of MMDetectAndFixDBFWidthChange()
    6411             : 
    6412             : // Adds a DBF record to a MiraMon table associated with a vector layer.
    6413             : // It sets up flush settings for writing to the table and initializes
    6414             : // variables needed for the process. Then, it checks and fixes the width
    6415             : // change if necessary.
    6416          34 : int MMAddDBFRecordToMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6417             :                          struct MiraMonFeature *hMMFeature)
    6418             : {
    6419          34 :     struct MM_DATA_BASE_XP *pBD_XP = nullptr;
    6420          34 :     MM_EXT_DBF_N_FIELDS nNumPrivateMMField = 0;
    6421             :     struct MM_FLUSH_INFO *pFlushRecList;
    6422             : 
    6423          34 :     if (!hMiraMonLayer)
    6424           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6425             : 
    6426          34 :     pBD_XP = hMiraMonLayer->MMAdmDBWriting.pMMBDXP;
    6427             : 
    6428             :     // Test length
    6429          34 :     if (hMMFeature && hMMFeature->nNumMRecords &&
    6430          34 :         hMMFeature->pRecords[0].nNumField)
    6431             :     {
    6432          34 :         if (MMDetectAndFixDBFWidthChange(hMiraMonLayer, hMMFeature,
    6433             :                                          &hMiraMonLayer->MMAdmDBWriting,
    6434             :                                          nNumPrivateMMField, 0, 0))
    6435           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6436             :     }
    6437             : 
    6438             :     // Adding record to the MiraMon table (extended DBF)
    6439             :     // Flush settings
    6440          34 :     pFlushRecList = &hMiraMonLayer->MMAdmDBWriting.FlushRecList;
    6441          34 :     pFlushRecList->pBlockWhereToSaveOrRead =
    6442          34 :         (void *)hMiraMonLayer->MMAdmDBWriting.pRecList;
    6443             : 
    6444          34 :     pFlushRecList->pBlockToBeSaved =
    6445          34 :         (void *)hMiraMonLayer->MMAdmDBWriting.szRecordOnCourse;
    6446          34 :     pFlushRecList->SizeOfBlockToBeSaved = pBD_XP->BytesPerRecord;
    6447             : 
    6448          34 :     if (MMAddFeatureRecordToMMDB(
    6449             :             hMiraMonLayer, hMMFeature, &hMiraMonLayer->MMAdmDBWriting,
    6450             :             hMiraMonLayer->MMAdmDBWriting.szRecordOnCourse, pFlushRecList,
    6451          34 :             &hMiraMonLayer->MMAdmDBWriting.pMMBDXP->nRecords,
    6452             :             nNumPrivateMMField))
    6453           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6454             : 
    6455             :     // In this case, the number of features is also updated
    6456          34 :     hMiraMonLayer->TopHeader.nElemCount =
    6457          34 :         hMiraMonLayer->MMAdmDBWriting.pMMBDXP->nRecords;
    6458             : 
    6459          34 :     return MM_CONTINUE_WRITING_FEATURES;
    6460             : }
    6461             : 
    6462             : // Adds a point record to a MiraMon table associated with a vector layer.
    6463          89 : int MMAddPointRecordToMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6464             :                            struct MiraMonFeature *hMMFeature,
    6465             :                            MM_INTERNAL_FID nElemCount)
    6466             : {
    6467          89 :     struct MM_DATA_BASE_XP *pBD_XP = nullptr;
    6468          89 :     MM_EXT_DBF_N_FIELDS nNumPrivateMMField = MM_PRIVATE_POINT_DB_FIELDS;
    6469             :     struct MM_FLUSH_INFO *pFlushRecList;
    6470             : 
    6471          89 :     if (!hMiraMonLayer)
    6472           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6473             : 
    6474          89 :     if (!hMMFeature)
    6475           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6476             : 
    6477             :     // In V1.1 only _UI32_MAX records number is allowed
    6478          89 :     if (MMCheckVersionForFID(hMiraMonLayer,
    6479          89 :                              hMiraMonLayer->MMPoint.MMAdmDB.pMMBDXP->nRecords +
    6480          89 :                                  hMMFeature->nNumMRecords))
    6481             :     {
    6482           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    6483             :                  "Error in MMCheckVersionForFID() (6)");
    6484           0 :         return MM_STOP_WRITING_FEATURES;
    6485             :     }
    6486             : 
    6487          89 :     pBD_XP = hMiraMonLayer->MMPoint.MMAdmDB.pMMBDXP;
    6488             : 
    6489             :     // Test length
    6490             :     // Private fields
    6491             :     // ID_GRAFIC
    6492          89 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField,
    6493             :                                         &nElemCount, TRUE))
    6494           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6495          89 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer,
    6496             :                                       &hMiraMonLayer->MMPoint.MMAdmDB, 0,
    6497             :                                       hMiraMonLayer->szStringToOperate))
    6498           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6499             : 
    6500             :     // GDAL fields
    6501          89 :     if (hMMFeature->nNumMRecords && hMMFeature->pRecords[0].nNumField)
    6502             :     {
    6503          89 :         if (MMDetectAndFixDBFWidthChange(hMiraMonLayer, hMMFeature,
    6504             :                                          &hMiraMonLayer->MMPoint.MMAdmDB,
    6505             :                                          nNumPrivateMMField, 0, 0))
    6506           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6507             :     }
    6508             : 
    6509             :     // Now length is sure, write
    6510          89 :     memset(hMiraMonLayer->MMPoint.MMAdmDB.szRecordOnCourse, 0,
    6511          89 :            pBD_XP->BytesPerRecord);
    6512          89 :     MMWriteValueToRecordDBXP(hMiraMonLayer,
    6513             :                              hMiraMonLayer->MMPoint.MMAdmDB.szRecordOnCourse,
    6514          89 :                              pBD_XP->pField, &nElemCount, TRUE);
    6515             : 
    6516             :     // Adding record to the MiraMon table (extended DBF)
    6517             :     // Flush settings
    6518          89 :     pFlushRecList = &hMiraMonLayer->MMPoint.MMAdmDB.FlushRecList;
    6519          89 :     pFlushRecList->pBlockWhereToSaveOrRead =
    6520          89 :         (void *)hMiraMonLayer->MMPoint.MMAdmDB.pRecList;
    6521             : 
    6522          89 :     pFlushRecList->pBlockToBeSaved =
    6523          89 :         (void *)hMiraMonLayer->MMPoint.MMAdmDB.szRecordOnCourse;
    6524          89 :     pFlushRecList->SizeOfBlockToBeSaved = pBD_XP->BytesPerRecord;
    6525             : 
    6526          89 :     if (MMAddFeatureRecordToMMDB(
    6527             :             hMiraMonLayer, hMMFeature, &hMiraMonLayer->MMPoint.MMAdmDB,
    6528             :             hMiraMonLayer->MMPoint.MMAdmDB.szRecordOnCourse, pFlushRecList,
    6529          89 :             &hMiraMonLayer->MMPoint.MMAdmDB.pMMBDXP->nRecords,
    6530             :             nNumPrivateMMField))
    6531           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6532          89 :     return MM_CONTINUE_WRITING_FEATURES;
    6533             : }
    6534             : 
    6535             : // Adds a stringline record to a MiraMon table associated with a vector layer.
    6536         102 : int MMAddArcRecordToMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6537             :                          struct MiraMonFeature *hMMFeature,
    6538             :                          MM_INTERNAL_FID nElemCount, struct MM_AH *pArcHeader)
    6539             : {
    6540         102 :     struct MM_DATA_BASE_XP *pBD_XP = nullptr;
    6541             :     struct MiraMonArcLayer *pMMArcLayer;
    6542         102 :     MM_EXT_DBF_N_FIELDS nNumPrivateMMField = MM_PRIVATE_ARC_DB_FIELDS;
    6543             :     struct MM_FLUSH_INFO *pFlushRecList;
    6544             : 
    6545         102 :     if (!hMiraMonLayer)
    6546           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6547             : 
    6548         102 :     if (hMiraMonLayer->bIsPolygon)
    6549          53 :         pMMArcLayer = &hMiraMonLayer->MMPolygon.MMArc;
    6550             :     else
    6551          49 :         pMMArcLayer = &hMiraMonLayer->MMArc;
    6552             : 
    6553             :     // In V1.1 only _UI32_MAX records number is allowed
    6554         102 :     if (hMiraMonLayer->bIsPolygon)
    6555             :     {
    6556          53 :         if (MMCheckVersionForFID(hMiraMonLayer,
    6557          53 :                                  pMMArcLayer->MMAdmDB.pMMBDXP->nRecords + 1))
    6558             :         {
    6559           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    6560             :                      "Error in MMCheckVersionForFID() (7)");
    6561           0 :             return MM_STOP_WRITING_FEATURES;
    6562             :         }
    6563             :     }
    6564             :     else
    6565             :     {
    6566          49 :         if (MMCheckVersionForFID(hMiraMonLayer,
    6567          49 :                                  pMMArcLayer->MMAdmDB.pMMBDXP->nRecords +
    6568          49 :                                      hMMFeature->nNumMRecords))
    6569             :         {
    6570           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    6571             :                      "Error in MMCheckVersionForFID() (8)");
    6572           0 :             return MM_STOP_WRITING_FEATURES;
    6573             :         }
    6574             :     }
    6575             : 
    6576         102 :     pBD_XP = pMMArcLayer->MMAdmDB.pMMBDXP;
    6577             : 
    6578             :     // Test length
    6579             :     // Private fields
    6580             :     // ID_GRAFIC
    6581         102 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField,
    6582             :                                         &nElemCount, TRUE))
    6583           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6584         102 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMArcLayer->MMAdmDB, 0,
    6585             :                                       hMiraMonLayer->szStringToOperate))
    6586           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6587             : 
    6588             :     // N_VERTEXS
    6589         102 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 1,
    6590         102 :                                         &pArcHeader->nElemCount, TRUE))
    6591           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6592         102 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMArcLayer->MMAdmDB, 1,
    6593             :                                       hMiraMonLayer->szStringToOperate))
    6594           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6595             : 
    6596             :     // LENGTH
    6597         102 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 2,
    6598         102 :                                         &pArcHeader->dfLength, FALSE))
    6599           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6600         102 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMArcLayer->MMAdmDB, 2,
    6601             :                                       hMiraMonLayer->szStringToOperate))
    6602           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6603             : 
    6604             :     // NODE_INI
    6605         102 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 3,
    6606         102 :                                         &pArcHeader->nFirstIdNode, TRUE))
    6607           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6608         102 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMArcLayer->MMAdmDB, 3,
    6609             :                                       hMiraMonLayer->szStringToOperate))
    6610           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6611             : 
    6612             :     // NODE_FI
    6613         102 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 4,
    6614         102 :                                         &pArcHeader->nLastIdNode, TRUE))
    6615           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6616         102 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMArcLayer->MMAdmDB, 4,
    6617             :                                       hMiraMonLayer->szStringToOperate))
    6618           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6619             : 
    6620             :     // GDAL fields
    6621         102 :     if (!hMiraMonLayer->bIsPolygon)
    6622             :     {
    6623          49 :         if (hMMFeature->nNumMRecords && hMMFeature->pRecords[0].nNumField)
    6624             :         {
    6625          48 :             if (MMDetectAndFixDBFWidthChange(hMiraMonLayer, hMMFeature,
    6626             :                                              &pMMArcLayer->MMAdmDB,
    6627             :                                              nNumPrivateMMField, 0, 0))
    6628           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    6629             :         }
    6630             :     }
    6631             : 
    6632             :     // Now length is sure, write
    6633         102 :     memset(pMMArcLayer->MMAdmDB.szRecordOnCourse, 0, pBD_XP->BytesPerRecord);
    6634         102 :     MMWriteValueToRecordDBXP(hMiraMonLayer,
    6635             :                              pMMArcLayer->MMAdmDB.szRecordOnCourse,
    6636         102 :                              pBD_XP->pField, &nElemCount, TRUE);
    6637             : 
    6638         102 :     MMWriteValueToRecordDBXP(hMiraMonLayer,
    6639             :                              pMMArcLayer->MMAdmDB.szRecordOnCourse,
    6640         102 :                              pBD_XP->pField + 1, &pArcHeader->nElemCount, TRUE);
    6641             : 
    6642         102 :     MMWriteValueToRecordDBXP(hMiraMonLayer,
    6643             :                              pMMArcLayer->MMAdmDB.szRecordOnCourse,
    6644         102 :                              pBD_XP->pField + 2, &pArcHeader->dfLength, FALSE);
    6645             : 
    6646         102 :     MMWriteValueToRecordDBXP(
    6647             :         hMiraMonLayer, pMMArcLayer->MMAdmDB.szRecordOnCourse,
    6648         102 :         pBD_XP->pField + 3, &pArcHeader->nFirstIdNode, TRUE);
    6649             : 
    6650         102 :     MMWriteValueToRecordDBXP(
    6651             :         hMiraMonLayer, pMMArcLayer->MMAdmDB.szRecordOnCourse,
    6652         102 :         pBD_XP->pField + 4, &pArcHeader->nLastIdNode, TRUE);
    6653             : 
    6654             :     // Adding record to the MiraMon table (extended DBF)
    6655             :     // Flush settings
    6656         102 :     pFlushRecList = &pMMArcLayer->MMAdmDB.FlushRecList;
    6657         102 :     pFlushRecList->pBlockWhereToSaveOrRead =
    6658         102 :         (void *)pMMArcLayer->MMAdmDB.pRecList;
    6659             : 
    6660         102 :     pFlushRecList->SizeOfBlockToBeSaved = pBD_XP->BytesPerRecord;
    6661         102 :     pFlushRecList->pBlockToBeSaved =
    6662         102 :         (void *)pMMArcLayer->MMAdmDB.szRecordOnCourse;
    6663             : 
    6664         102 :     if (hMiraMonLayer->bIsPolygon)
    6665             :     {
    6666          53 :         if (MMAppendBlockToBuffer(pFlushRecList))
    6667           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6668          53 :         pMMArcLayer->MMAdmDB.pMMBDXP->nRecords++;
    6669          53 :         return MM_CONTINUE_WRITING_FEATURES;
    6670             :     }
    6671             : 
    6672          49 :     pFlushRecList->SizeOfBlockToBeSaved = pBD_XP->BytesPerRecord;
    6673          49 :     if (MMAddFeatureRecordToMMDB(
    6674             :             hMiraMonLayer, hMMFeature, &pMMArcLayer->MMAdmDB,
    6675             :             pMMArcLayer->MMAdmDB.szRecordOnCourse, pFlushRecList,
    6676          49 :             &pMMArcLayer->MMAdmDB.pMMBDXP->nRecords, nNumPrivateMMField))
    6677           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6678          49 :     return MM_CONTINUE_WRITING_FEATURES;
    6679             : }
    6680             : 
    6681             : // Adds a node record to a MiraMon table associated with a vector layer.
    6682         151 : int MMAddNodeRecordToMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6683             :                           MM_INTERNAL_FID nElemCount, struct MM_NH *pNodeHeader)
    6684             : {
    6685         151 :     struct MM_DATA_BASE_XP *pBD_XP = nullptr;
    6686             :     struct MiraMonNodeLayer *pMMNodeLayer;
    6687             :     double nDoubleValue;
    6688             : 
    6689         151 :     if (!hMiraMonLayer)
    6690           0 :         return 1;
    6691             : 
    6692         151 :     if (hMiraMonLayer->bIsPolygon)
    6693          53 :         pMMNodeLayer = &hMiraMonLayer->MMPolygon.MMArc.MMNode;
    6694             :     else
    6695          98 :         pMMNodeLayer = &hMiraMonLayer->MMArc.MMNode;
    6696             : 
    6697         151 :     if (!pMMNodeLayer)
    6698             :     {
    6699           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Error in pMMNodeLayer() (1)");
    6700           0 :         return MM_STOP_WRITING_FEATURES;
    6701             :     }
    6702             : 
    6703             :     // In V1.1 only _UI32_MAX records number is allowed
    6704         151 :     if (MMCheckVersionForFID(hMiraMonLayer,
    6705         151 :                              pMMNodeLayer->MMAdmDB.pMMBDXP->nRecords + 1))
    6706             :     {
    6707           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    6708             :                  "Error in MMCheckVersionForFID() (9)");
    6709           0 :         return MM_STOP_WRITING_FEATURES;
    6710             :     }
    6711             : 
    6712             :     // Test length
    6713             :     // Private fields
    6714             :     // ID_GRAFIC
    6715         151 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer,
    6716         151 :                                         pMMNodeLayer->MMAdmDB.pMMBDXP->pField,
    6717             :                                         &nElemCount, TRUE))
    6718           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6719         151 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMNodeLayer->MMAdmDB, 0,
    6720             :                                       hMiraMonLayer->szStringToOperate))
    6721           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6722             : 
    6723             :     // ARCS_A_NOD
    6724         151 :     nDoubleValue = pNodeHeader->nArcsCount;
    6725         151 :     if (MMWriteValueToszStringToOperate(
    6726         151 :             hMiraMonLayer, pMMNodeLayer->MMAdmDB.pMMBDXP->pField + 1,
    6727             :             &nDoubleValue, FALSE))
    6728           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6729         151 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMNodeLayer->MMAdmDB, 1,
    6730             :                                       hMiraMonLayer->szStringToOperate))
    6731           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6732             : 
    6733             :     // TIPUS_NODE
    6734         151 :     nDoubleValue = pNodeHeader->cNodeType;
    6735         151 :     if (MMWriteValueToszStringToOperate(
    6736         151 :             hMiraMonLayer, pMMNodeLayer->MMAdmDB.pMMBDXP->pField + 2,
    6737             :             &nDoubleValue, FALSE))
    6738           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6739         151 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMNodeLayer->MMAdmDB, 2,
    6740             :                                       hMiraMonLayer->szStringToOperate))
    6741           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6742             : 
    6743             :     // Adding record to the MiraMon table (extended DBF)
    6744             :     // Flush settings
    6745         151 :     pMMNodeLayer->MMAdmDB.FlushRecList.pBlockWhereToSaveOrRead =
    6746         151 :         (void *)pMMNodeLayer->MMAdmDB.pRecList;
    6747             : 
    6748         151 :     pBD_XP = pMMNodeLayer->MMAdmDB.pMMBDXP;
    6749             : 
    6750         151 :     pMMNodeLayer->MMAdmDB.FlushRecList.SizeOfBlockToBeSaved =
    6751         151 :         pBD_XP->BytesPerRecord;
    6752         151 :     pMMNodeLayer->MMAdmDB.FlushRecList.pBlockToBeSaved =
    6753         151 :         (void *)pMMNodeLayer->MMAdmDB.szRecordOnCourse;
    6754             : 
    6755         151 :     memset(pMMNodeLayer->MMAdmDB.szRecordOnCourse, 0, pBD_XP->BytesPerRecord);
    6756         151 :     MMWriteValueToRecordDBXP(hMiraMonLayer,
    6757             :                              pMMNodeLayer->MMAdmDB.szRecordOnCourse,
    6758         151 :                              pBD_XP->pField, &nElemCount, TRUE);
    6759             : 
    6760         151 :     nDoubleValue = pNodeHeader->nArcsCount;
    6761         151 :     MMWriteValueToRecordDBXP(hMiraMonLayer,
    6762             :                              pMMNodeLayer->MMAdmDB.szRecordOnCourse,
    6763         151 :                              pBD_XP->pField + 1, &nDoubleValue, FALSE);
    6764             : 
    6765         151 :     nDoubleValue = pNodeHeader->cNodeType;
    6766         151 :     MMWriteValueToRecordDBXP(hMiraMonLayer,
    6767             :                              pMMNodeLayer->MMAdmDB.szRecordOnCourse,
    6768         151 :                              pBD_XP->pField + 2, &nDoubleValue, FALSE);
    6769             : 
    6770         151 :     if (MMAppendBlockToBuffer(&pMMNodeLayer->MMAdmDB.FlushRecList))
    6771           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6772         151 :     pMMNodeLayer->MMAdmDB.pMMBDXP->nRecords++;
    6773         151 :     return MM_CONTINUE_WRITING_FEATURES;
    6774             : }
    6775             : 
    6776             : // Adds a polygon or multipolygon record to a MiraMon table
    6777             : // associated with a vector layer.
    6778          68 : int MMAddPolygonRecordToMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6779             :                              struct MiraMonFeature *hMMFeature,
    6780             :                              MM_INTERNAL_FID nElemCount,
    6781             :                              MM_N_VERTICES_TYPE nVerticesCount,
    6782             :                              struct MM_PH *pPolHeader)
    6783             : {
    6784          68 :     struct MM_DATA_BASE_XP *pBD_XP = nullptr;
    6785          68 :     MM_EXT_DBF_N_FIELDS nNumPrivateMMField = MM_PRIVATE_POLYGON_DB_FIELDS;
    6786             :     struct MM_FLUSH_INFO *pFlushRecList;
    6787             : 
    6788          68 :     if (!hMiraMonLayer)
    6789           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6790             : 
    6791             :     // In V1.1 only _UI32_MAX records number is allowed
    6792          68 :     if (MMCheckVersionForFID(
    6793          68 :             hMiraMonLayer, hMiraMonLayer->MMPolygon.MMAdmDB.pMMBDXP->nRecords +
    6794          68 :                                (hMMFeature ? hMMFeature->nNumMRecords : 0)))
    6795           0 :         return MM_STOP_WRITING_FEATURES;
    6796             : 
    6797          68 :     pBD_XP = hMiraMonLayer->MMPolygon.MMAdmDB.pMMBDXP;
    6798             : 
    6799             :     // Test length
    6800             :     // Private fields
    6801             :     // ID_GRAFIC
    6802          68 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField,
    6803             :                                         &nElemCount, TRUE))
    6804           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6805          68 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer,
    6806             :                                       &hMiraMonLayer->MMPolygon.MMAdmDB, 0,
    6807             :                                       hMiraMonLayer->szStringToOperate))
    6808           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6809             : 
    6810             :     // The other fields are valid if pPolHeader exists (it is not
    6811             :     // the universal polygon)
    6812          68 :     if (pPolHeader)
    6813             :     {
    6814             :         // N_VERTEXS
    6815          41 :         if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 1,
    6816             :                                             &nVerticesCount, TRUE))
    6817           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6818          41 :         if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer,
    6819             :                                           &hMiraMonLayer->MMPolygon.MMAdmDB, 1,
    6820             :                                           hMiraMonLayer->szStringToOperate))
    6821           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6822             : 
    6823             :         // PERIMETER
    6824          41 :         if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 2,
    6825          41 :                                             &pPolHeader->dfPerimeter, FALSE))
    6826           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6827          41 :         if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer,
    6828             :                                           &hMiraMonLayer->MMPolygon.MMAdmDB, 2,
    6829             :                                           hMiraMonLayer->szStringToOperate))
    6830           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6831             : 
    6832             :         // AREA
    6833          41 :         if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 3,
    6834          41 :                                             &pPolHeader->dfArea, FALSE))
    6835           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6836          41 :         if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer,
    6837             :                                           &hMiraMonLayer->MMPolygon.MMAdmDB, 3,
    6838             :                                           hMiraMonLayer->szStringToOperate))
    6839           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6840             : 
    6841             :         // N_ARCS
    6842          41 :         if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 4,
    6843          41 :                                             &pPolHeader->nArcsCount, TRUE))
    6844           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6845          41 :         if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer,
    6846             :                                           &hMiraMonLayer->MMPolygon.MMAdmDB, 4,
    6847             :                                           hMiraMonLayer->szStringToOperate))
    6848           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6849             : 
    6850             :         // N_POLIG
    6851          41 :         if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 5,
    6852          41 :                                             &pPolHeader->nRingsCount, TRUE))
    6853           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6854          41 :         if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer,
    6855             :                                           &hMiraMonLayer->MMPolygon.MMAdmDB, 5,
    6856             :                                           hMiraMonLayer->szStringToOperate))
    6857           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6858             :     }
    6859             : 
    6860             :     // GDAL fields
    6861          68 :     if (hMMFeature && hMMFeature->nNumMRecords &&
    6862          41 :         hMMFeature->pRecords[0].nNumField)
    6863             :     {
    6864          41 :         if (MMDetectAndFixDBFWidthChange(hMiraMonLayer, hMMFeature,
    6865             :                                          &hMiraMonLayer->MMPolygon.MMAdmDB,
    6866             :                                          nNumPrivateMMField, 0, 0))
    6867           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6868             :     }
    6869             : 
    6870             :     // Adding record to the MiraMon table (extended DBF)
    6871             :     // Flush settings
    6872          68 :     pFlushRecList = &hMiraMonLayer->MMPolygon.MMAdmDB.FlushRecList;
    6873          68 :     pFlushRecList->pBlockWhereToSaveOrRead =
    6874          68 :         (void *)hMiraMonLayer->MMPolygon.MMAdmDB.pRecList;
    6875             : 
    6876          68 :     pFlushRecList->SizeOfBlockToBeSaved = pBD_XP->BytesPerRecord;
    6877          68 :     pFlushRecList->pBlockToBeSaved =
    6878          68 :         (void *)hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse;
    6879             : 
    6880             :     // Now length is sure, write
    6881          68 :     memset(hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse, ' ',
    6882          68 :            pBD_XP->BytesPerRecord);
    6883          68 :     if (MMWriteValueToRecordDBXP(
    6884             :             hMiraMonLayer, hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse,
    6885          68 :             pBD_XP->pField, &nElemCount, TRUE))
    6886           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6887             : 
    6888          68 :     if (!hMMFeature)
    6889             :     {
    6890          27 :         if (MMAppendBlockToBuffer(pFlushRecList))
    6891           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6892          27 :         hMiraMonLayer->MMPolygon.MMAdmDB.pMMBDXP->nRecords++;
    6893          27 :         return MM_CONTINUE_WRITING_FEATURES;
    6894             :     }
    6895             : 
    6896          41 :     if (pPolHeader)
    6897             :     {
    6898          41 :         MMWriteValueToRecordDBXP(
    6899             :             hMiraMonLayer, hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse,
    6900          41 :             pBD_XP->pField + 1, &nVerticesCount, TRUE);
    6901             : 
    6902          41 :         MMWriteValueToRecordDBXP(
    6903             :             hMiraMonLayer, hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse,
    6904          41 :             pBD_XP->pField + 2, &pPolHeader->dfPerimeter, FALSE);
    6905             : 
    6906          41 :         MMWriteValueToRecordDBXP(
    6907             :             hMiraMonLayer, hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse,
    6908          41 :             pBD_XP->pField + 3, &pPolHeader->dfArea, FALSE);
    6909             : 
    6910          41 :         MMWriteValueToRecordDBXP(
    6911             :             hMiraMonLayer, hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse,
    6912          41 :             pBD_XP->pField + 4, &pPolHeader->nArcsCount, TRUE);
    6913             : 
    6914          41 :         MMWriteValueToRecordDBXP(
    6915             :             hMiraMonLayer, hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse,
    6916          41 :             pBD_XP->pField + 5, &pPolHeader->nRingsCount, TRUE);
    6917             :     }
    6918             : 
    6919          41 :     pFlushRecList->SizeOfBlockToBeSaved = pBD_XP->BytesPerRecord;
    6920          41 :     if (MMAddFeatureRecordToMMDB(
    6921             :             hMiraMonLayer, hMMFeature, &hMiraMonLayer->MMPolygon.MMAdmDB,
    6922             :             hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse, pFlushRecList,
    6923          41 :             &hMiraMonLayer->MMPolygon.MMAdmDB.pMMBDXP->nRecords,
    6924             :             nNumPrivateMMField))
    6925           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6926          41 :     return MM_CONTINUE_WRITING_FEATURES;
    6927             : }
    6928             : 
    6929             : // Close the MiraMon database associated with a vector layer.
    6930         442 : static int MMCloseMMBD_XPFile(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6931             :                               struct MMAdmDatabase *MMAdmDB)
    6932             : {
    6933         442 :     int ret_code = 1;
    6934         442 :     if (!hMiraMonLayer)
    6935           0 :         return 1;
    6936             : 
    6937         442 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    6938             :     {
    6939         194 :         if (!MMAdmDB->pMMBDXP ||
    6940         194 :             (MMAdmDB->pMMBDXP && !MMAdmDB->pMMBDXP->pfDataBase))
    6941             :         {
    6942             :             // In case of 0 elements created we have to
    6943             :             // create an empty DBF
    6944           0 :             if (hMiraMonLayer->bIsPolygon)
    6945             :             {
    6946           0 :                 if (hMiraMonLayer->TopHeader.nElemCount <= 1)
    6947             :                 {
    6948           0 :                     if (MMCreateMMDB(hMiraMonLayer, nullptr))
    6949             :                     {
    6950           0 :                         CPLError(CE_Failure, CPLE_OutOfMemory,
    6951             :                                  "Memory error in MiraMon "
    6952             :                                  "driver (MMCreateMMDB())");
    6953           0 :                         goto end_label;
    6954             :                     }
    6955             :                 }
    6956             :             }
    6957           0 :             else if (hMiraMonLayer->bIsPoint || hMiraMonLayer->bIsArc)
    6958             :             {
    6959           0 :                 if (hMiraMonLayer->TopHeader.nElemCount == 0)
    6960             :                 {
    6961           0 :                     if (MMCreateMMDB(hMiraMonLayer, nullptr))
    6962             :                     {
    6963           0 :                         CPLError(CE_Failure, CPLE_OutOfMemory,
    6964             :                                  "Memory error in MiraMon "
    6965             :                                  "driver (MMCreateMMDB())");
    6966           0 :                         goto end_label;
    6967             :                     }
    6968             :                 }
    6969             :             }
    6970             :         }
    6971             : 
    6972         194 :         if (MM_WriteNRecordsMMBD_XPFile(MMAdmDB))
    6973           0 :             goto end_label;
    6974             : 
    6975             :         // Flushing all to be flushed
    6976         194 :         MMAdmDB->FlushRecList.SizeOfBlockToBeSaved = 0;
    6977         194 :         if (MMAppendBlockToBuffer(&MMAdmDB->FlushRecList))
    6978           0 :             goto end_label;
    6979             :     }
    6980             : 
    6981         442 :     ret_code = 0;
    6982         442 : end_label:
    6983             :     // Closing database files
    6984         442 :     if (MMAdmDB && MMAdmDB->pMMBDXP && MMAdmDB->pMMBDXP->pfDataBase)
    6985         194 :         fclose_and_nullify(&MMAdmDB->pMMBDXP->pfDataBase);
    6986             : 
    6987         442 :     return ret_code;
    6988             : }
    6989             : 
    6990         230 : int MMCloseMMBD_XP(struct MiraMonVectLayerInfo *hMiraMonLayer)
    6991             : {
    6992         230 :     int ret_code = 0;
    6993         230 :     if (!hMiraMonLayer)
    6994           0 :         return 1;
    6995             : 
    6996         230 :     if (hMiraMonLayer->pMMBDXP && hMiraMonLayer->pMMBDXP->pfDataBase)
    6997             :     {
    6998         113 :         fclose_and_nullify(&hMiraMonLayer->pMMBDXP->pfDataBase);
    6999             :     }
    7000             : 
    7001         230 :     if (hMiraMonLayer->bIsPoint)
    7002             :         ret_code =
    7003          76 :             MMCloseMMBD_XPFile(hMiraMonLayer, &hMiraMonLayer->MMPoint.MMAdmDB);
    7004         154 :     else if (hMiraMonLayer->bIsArc && !hMiraMonLayer->bIsPolygon)
    7005             :     {
    7006          62 :         if (MMCloseMMBD_XPFile(hMiraMonLayer, &hMiraMonLayer->MMArc.MMAdmDB))
    7007           0 :             ret_code = 1;
    7008          62 :         if (MMCloseMMBD_XPFile(hMiraMonLayer,
    7009             :                                &hMiraMonLayer->MMArc.MMNode.MMAdmDB))
    7010           0 :             ret_code = 1;
    7011             :     }
    7012          92 :     else if (hMiraMonLayer->bIsPolygon)
    7013             :     {
    7014          75 :         if (MMCloseMMBD_XPFile(hMiraMonLayer,
    7015             :                                &hMiraMonLayer->MMPolygon.MMAdmDB))
    7016           0 :             ret_code = 1;
    7017          75 :         if (MMCloseMMBD_XPFile(hMiraMonLayer,
    7018             :                                &hMiraMonLayer->MMPolygon.MMArc.MMAdmDB))
    7019           0 :             ret_code = 1;
    7020          75 :         if (MMCloseMMBD_XPFile(hMiraMonLayer,
    7021             :                                &hMiraMonLayer->MMPolygon.MMArc.MMNode.MMAdmDB))
    7022           0 :             ret_code = 1;
    7023             :     }
    7024          17 :     else if (hMiraMonLayer->bIsDBF)
    7025             :         ret_code =
    7026          17 :             MMCloseMMBD_XPFile(hMiraMonLayer, &hMiraMonLayer->MMAdmDBWriting);
    7027             : 
    7028         230 :     return ret_code;
    7029             : }
    7030             : 
    7031             : // Destroys the memory used to create a MiraMon table associated
    7032             : // with a vector layer.
    7033         442 : static void MMDestroyMMDBFile(struct MiraMonVectLayerInfo *hMiraMonLayer,
    7034             :                               struct MMAdmDatabase *pMMAdmDB)
    7035             : {
    7036         442 :     if (!hMiraMonLayer)
    7037           0 :         return;
    7038             : 
    7039         442 :     if (pMMAdmDB && pMMAdmDB->szRecordOnCourse)
    7040             :     {
    7041          44 :         VSIFree(pMMAdmDB->szRecordOnCourse);
    7042          44 :         pMMAdmDB->szRecordOnCourse = nullptr;
    7043             :     }
    7044         442 :     if (hMiraMonLayer->szStringToOperate)
    7045             :     {
    7046           0 :         VSIFree(hMiraMonLayer->szStringToOperate);
    7047           0 :         hMiraMonLayer->szStringToOperate = nullptr;
    7048           0 :         hMiraMonLayer->nNumStringToOperate = 0;
    7049             :     }
    7050             : 
    7051         442 :     if (pMMAdmDB && pMMAdmDB->pMMBDXP)
    7052             :     {
    7053         312 :         MM_ReleaseDBFHeader(&pMMAdmDB->pMMBDXP);
    7054         312 :         hMiraMonLayer->pMMBDXP = nullptr;
    7055             :     }
    7056         442 :     if (pMMAdmDB && pMMAdmDB->pRecList)
    7057             :     {
    7058          44 :         VSIFree(pMMAdmDB->pRecList);
    7059          44 :         pMMAdmDB->pRecList = nullptr;
    7060             :     }
    7061             : }
    7062             : 
    7063         820 : void MMDestroyMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer)
    7064             : {
    7065         820 :     if (!hMiraMonLayer)
    7066           0 :         return;
    7067             : 
    7068         820 :     if (hMiraMonLayer->bIsPoint)
    7069             :     {
    7070          76 :         MMDestroyMMDBFile(hMiraMonLayer, &hMiraMonLayer->MMPoint.MMAdmDB);
    7071          76 :         return;
    7072             :     }
    7073         744 :     if (hMiraMonLayer->bIsArc && !hMiraMonLayer->bIsPolygon)
    7074             :     {
    7075          62 :         MMDestroyMMDBFile(hMiraMonLayer, &hMiraMonLayer->MMArc.MMAdmDB);
    7076          62 :         MMDestroyMMDBFile(hMiraMonLayer, &hMiraMonLayer->MMArc.MMNode.MMAdmDB);
    7077          62 :         return;
    7078             :     }
    7079         682 :     if (hMiraMonLayer->bIsPolygon)
    7080             :     {
    7081          75 :         MMDestroyMMDBFile(hMiraMonLayer, &hMiraMonLayer->MMPolygon.MMAdmDB);
    7082          75 :         MMDestroyMMDBFile(hMiraMonLayer,
    7083             :                           &hMiraMonLayer->MMPolygon.MMArc.MMAdmDB);
    7084          75 :         MMDestroyMMDBFile(hMiraMonLayer,
    7085             :                           &hMiraMonLayer->MMPolygon.MMArc.MMNode.MMAdmDB);
    7086             :     }
    7087         682 :     if (hMiraMonLayer->bIsDBF)
    7088          17 :         MMDestroyMMDBFile(hMiraMonLayer, &hMiraMonLayer->MMAdmDBWriting);
    7089             : }
    7090             : 
    7091             : // COMING FROM mm_gdal_functions.c/h but only used here
    7092         336 : void MM_FillFieldDescriptorByLanguage(void)
    7093             : {
    7094         336 :     CPLStrlcpy(szInternalGraphicIdentifierEng, "Internal Graphic identifier",
    7095             :                MM_MAX_IDENTIFIER_SIZE);
    7096         336 :     CPLStrlcpy(szInternalGraphicIdentifierCat, "Identificador Grafic intern",
    7097             :                MM_MAX_IDENTIFIER_SIZE);
    7098         336 :     *(unsigned char *)&szInternalGraphicIdentifierCat[16] = MM_a_WITH_GRAVE;
    7099         336 :     CPLStrlcpy(szInternalGraphicIdentifierSpa, "Identificador Grafico interno",
    7100             :                MM_MAX_IDENTIFIER_SIZE);
    7101         336 :     *(unsigned char *)&szInternalGraphicIdentifierSpa[16] = MM_a_WITH_ACUTE;
    7102             : 
    7103         336 :     CPLStrlcpy(szNumberOfVerticesEng, "Number of vertices",
    7104             :                MM_MAX_IDENTIFIER_SIZE);
    7105         336 :     CPLStrlcpy(szNumberOfVerticesCat, "Nombre de vertexs",
    7106             :                MM_MAX_IDENTIFIER_SIZE);
    7107         336 :     CPLStrlcpy(szNumberOfVerticesSpa, "Numero de vertices",
    7108             :                MM_MAX_IDENTIFIER_SIZE);
    7109         336 :     *(unsigned char *)&szNumberOfVerticesCat[11] = MM_e_WITH_GRAVE;
    7110         336 :     *(unsigned char *)&szNumberOfVerticesSpa[1] = MM_u_WITH_ACUTE;
    7111         336 :     *(unsigned char *)&szNumberOfVerticesSpa[11] = MM_e_WITH_ACUTE;
    7112             : 
    7113         336 :     CPLStrlcpy(szLengthOfAarcEng, "Length of arc", MM_MAX_IDENTIFIER_SIZE);
    7114         336 :     CPLStrlcpy(szLengthOfAarcCat, "Longitud de l'arc", MM_MAX_IDENTIFIER_SIZE);
    7115         336 :     CPLStrlcpy(szLengthOfAarcSpa, "Longitud del arco", MM_MAX_IDENTIFIER_SIZE);
    7116             : 
    7117         336 :     CPLStrlcpy(szInitialNodeEng, "Initial node", MM_MAX_IDENTIFIER_SIZE);
    7118         336 :     CPLStrlcpy(szInitialNodeCat, "Node inicial", MM_MAX_IDENTIFIER_SIZE);
    7119         336 :     CPLStrlcpy(szInitialNodeSpa, "Nodo inicial", MM_MAX_IDENTIFIER_SIZE);
    7120             : 
    7121         336 :     CPLStrlcpy(szFinalNodeEng, "Final node", MM_MAX_IDENTIFIER_SIZE);
    7122         336 :     CPLStrlcpy(szFinalNodeCat, "Node final", MM_MAX_IDENTIFIER_SIZE);
    7123         336 :     CPLStrlcpy(szFinalNodeSpa, "Nodo final", MM_MAX_IDENTIFIER_SIZE);
    7124             : 
    7125         336 :     CPLStrlcpy(szNumberOfArcsToNodeEng, "Number of arcs to node",
    7126             :                MM_MAX_IDENTIFIER_SIZE);
    7127         336 :     CPLStrlcpy(szNumberOfArcsToNodeCat, "Nombre d'arcs al node",
    7128             :                MM_MAX_IDENTIFIER_SIZE);
    7129         336 :     CPLStrlcpy(szNumberOfArcsToNodeSpa, "Numero de arcos al nodo",
    7130             :                MM_MAX_IDENTIFIER_SIZE);
    7131         336 :     *(unsigned char *)&szNumberOfArcsToNodeSpa[1] = MM_u_WITH_ACUTE;
    7132             : 
    7133         336 :     CPLStrlcpy(szNodeTypeEng, "Node type", MM_MAX_IDENTIFIER_SIZE);
    7134         336 :     CPLStrlcpy(szNodeTypeCat, "Tipus de node", MM_MAX_IDENTIFIER_SIZE);
    7135         336 :     CPLStrlcpy(szNodeTypeSpa, "Tipo de nodo", MM_MAX_IDENTIFIER_SIZE);
    7136             : 
    7137         336 :     CPLStrlcpy(szPerimeterOfThePolygonEng, "Perimeter of the polygon",
    7138             :                MM_MAX_IDENTIFIER_SIZE);
    7139         336 :     CPLStrlcpy(szPerimeterOfThePolygonCat, "Perimetre del poligon",
    7140             :                MM_MAX_IDENTIFIER_SIZE);
    7141         336 :     CPLStrlcpy(szPerimeterOfThePolygonSpa, "Perimetro del poligono",
    7142             :                MM_MAX_IDENTIFIER_SIZE);
    7143             : 
    7144         336 :     *(unsigned char *)&szPerimeterOfThePolygonCat[3] = MM_i_WITH_ACUTE;
    7145         336 :     *(unsigned char *)&szPerimeterOfThePolygonSpa[3] = MM_i_WITH_ACUTE;
    7146         336 :     *(unsigned char *)&szPerimeterOfThePolygonCat[17] = MM_i_WITH_ACUTE;
    7147         336 :     *(unsigned char *)&szPerimeterOfThePolygonSpa[17] = MM_i_WITH_ACUTE;
    7148             : 
    7149         336 :     CPLStrlcpy(szAreaOfThePolygonEng, "Area of the polygon",
    7150             :                MM_MAX_IDENTIFIER_SIZE);
    7151         336 :     CPLStrlcpy(szAreaOfThePolygonCat, "Area del poligon",
    7152             :                MM_MAX_IDENTIFIER_SIZE);
    7153         336 :     CPLStrlcpy(szAreaOfThePolygonSpa, "Area del poligono",
    7154             :                MM_MAX_IDENTIFIER_SIZE);
    7155             : 
    7156         336 :     *(unsigned char *)&szAreaOfThePolygonCat[0] = MM_A_WITH_GRAVE;
    7157         336 :     *(unsigned char *)&szAreaOfThePolygonSpa[0] = MM_A_WITH_ACUTE;
    7158         336 :     *(unsigned char *)&szAreaOfThePolygonCat[12] = MM_i_WITH_ACUTE;
    7159         336 :     *(unsigned char *)&szAreaOfThePolygonSpa[12] = MM_i_WITH_ACUTE;
    7160             : 
    7161         336 :     CPLStrlcpy(szNumberOfArcsEng, "Number of arcs", MM_MAX_IDENTIFIER_SIZE);
    7162         336 :     CPLStrlcpy(szNumberOfArcsCat, "Nombre d'arcs", MM_MAX_IDENTIFIER_SIZE);
    7163         336 :     CPLStrlcpy(szNumberOfArcsSpa, "Numero de arcos", MM_MAX_IDENTIFIER_SIZE);
    7164             : 
    7165         336 :     *(unsigned char *)&szNumberOfArcsSpa[1] = MM_u_WITH_ACUTE;
    7166             : 
    7167         336 :     CPLStrlcpy(szNumberOfElementaryPolygonsEng, "Number of elementary polygons",
    7168             :                MM_MAX_IDENTIFIER_SIZE);
    7169         336 :     CPLStrlcpy(szNumberOfElementaryPolygonsCat, "Nombre de poligons elementals",
    7170             :                MM_MAX_IDENTIFIER_SIZE);
    7171         336 :     CPLStrlcpy(szNumberOfElementaryPolygonsSpa,
    7172             :                "Numero de poligonos elementales", MM_MAX_IDENTIFIER_SIZE);
    7173             : 
    7174         336 :     *(unsigned char *)&szNumberOfElementaryPolygonsSpa[1] = MM_u_WITH_ACUTE;
    7175         336 :     *(unsigned char *)&szNumberOfElementaryPolygonsCat[13] = MM_i_WITH_ACUTE;
    7176         336 :     *(unsigned char *)&szNumberOfElementaryPolygonsSpa[13] = MM_i_WITH_ACUTE;
    7177         336 : }
    7178             : 
    7179         660 : static MM_BOOLEAN MM_FillFieldDB_XP(
    7180             :     struct MM_FIELD *camp, const char *FieldName,
    7181             :     const char *FieldDescriptionEng, const char *FieldDescriptionCat,
    7182             :     const char *FieldDescriptionSpa, char FieldType,
    7183             :     MM_BYTES_PER_FIELD_TYPE_DBF BytesPerField, MM_BYTE DecimalsIfFloat)
    7184             : {
    7185             :     char nom_temp[MM_MAX_LON_FIELD_NAME_DBF];
    7186             :     int retorn_valida_nom_camp;
    7187             : 
    7188         660 :     if (FieldName)
    7189             :     {
    7190         660 :         retorn_valida_nom_camp = MM_ISExtendedNameBD_XP(FieldName);
    7191         660 :         if (retorn_valida_nom_camp == MM_DBF_NAME_NO_VALID)
    7192           0 :             return FALSE;
    7193         660 :         CPLStrlcpy(camp->FieldName, FieldName, MM_MAX_LON_FIELD_NAME_DBF);
    7194             : 
    7195         660 :         if (retorn_valida_nom_camp == MM_VALID_EXTENDED_DBF_NAME)
    7196             :         {
    7197           0 :             MM_CalculateBytesExtendedFieldName(camp);
    7198           0 :             CPLStrlcpy(nom_temp, FieldName, MM_MAX_LON_FIELD_NAME_DBF);
    7199           0 :             MM_ReturnValidClassicDBFFieldName(nom_temp);
    7200           0 :             nom_temp[MM_MAX_LON_CLASSICAL_FIELD_NAME_DBF] = '\0';
    7201           0 :             CPLStrlcpy(camp->ClassicalDBFFieldName, nom_temp,
    7202             :                        MM_MAX_LON_CLASSICAL_FIELD_NAME_DBF);
    7203             :         }
    7204             :     }
    7205             : 
    7206         660 :     if (FieldDescriptionEng)
    7207         660 :         CPLStrlcpy(camp->FieldDescription[MM_DEF_LANGUAGE], FieldDescriptionEng,
    7208             :                    sizeof(camp->FieldDescription[MM_DEF_LANGUAGE]));
    7209             :     else
    7210           0 :         strcpy(camp->FieldDescription[MM_DEF_LANGUAGE], "\0");
    7211             : 
    7212         660 :     if (FieldDescriptionEng)
    7213         660 :         CPLStrlcpy(camp->FieldDescription[MM_ENG_LANGUAGE], FieldDescriptionEng,
    7214             :                    sizeof(camp->FieldDescription[MM_ENG_LANGUAGE]));
    7215             :     else
    7216           0 :         strcpy(camp->FieldDescription[MM_ENG_LANGUAGE], "\0");
    7217             : 
    7218         660 :     if (FieldDescriptionCat)
    7219         660 :         CPLStrlcpy(camp->FieldDescription[MM_CAT_LANGUAGE], FieldDescriptionCat,
    7220             :                    sizeof(camp->FieldDescription[MM_CAT_LANGUAGE]));
    7221             :     else
    7222           0 :         strcpy(camp->FieldDescription[MM_CAT_LANGUAGE], "\0");
    7223             : 
    7224         660 :     if (FieldDescriptionSpa)
    7225         660 :         CPLStrlcpy(camp->FieldDescription[MM_SPA_LANGUAGE], FieldDescriptionSpa,
    7226             :                    sizeof(camp->FieldDescription[MM_SPA_LANGUAGE]));
    7227             :     else
    7228           0 :         strcpy(camp->FieldDescription[MM_SPA_LANGUAGE], "\0");
    7229             : 
    7230         660 :     camp->FieldType = FieldType;
    7231         660 :     camp->DecimalsIfFloat = DecimalsIfFloat;
    7232         660 :     camp->BytesPerField = BytesPerField;
    7233         660 :     return TRUE;
    7234             : }
    7235             : 
    7236          27 : size_t MM_DefineFirstPolygonFieldsDB_XP(struct MM_DATA_BASE_XP *bd_xp,
    7237             :                                         MM_BYTE n_perimeter_decimals,
    7238             :                                         MM_BYTE n_area_decimals_decimals)
    7239             : {
    7240          27 :     MM_EXT_DBF_N_FIELDS i_camp = 0;
    7241             : 
    7242          27 :     MM_FillFieldDB_XP(
    7243          27 :         bd_xp->pField + i_camp, szMMNomCampIdGraficDefecte,
    7244             :         szInternalGraphicIdentifierEng, szInternalGraphicIdentifierCat,
    7245             :         szInternalGraphicIdentifierSpa, 'N', MM_MIN_WIDTH_ID_GRAFIC, 0);
    7246          27 :     bd_xp->IdGraficField = 0;
    7247          27 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_ID_GRAFIC;
    7248          27 :     i_camp++;
    7249             : 
    7250          27 :     MM_FillFieldDB_XP(bd_xp->pField + i_camp, szMMNomCampNVertexsDefecte,
    7251             :                       szNumberOfVerticesEng, szNumberOfVerticesCat,
    7252             :                       szNumberOfVerticesSpa, 'N', MM_MIN_WIDTH_N_VERTEXS, 0);
    7253          27 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_N_VERTEXS;
    7254          27 :     i_camp++;
    7255             : 
    7256          27 :     MM_FillFieldDB_XP(bd_xp->pField + i_camp, szMMNomCampPerimetreDefecte,
    7257             :                       szPerimeterOfThePolygonEng, szPerimeterOfThePolygonCat,
    7258             :                       szPerimeterOfThePolygonSpa, 'N', MM_MIN_WIDTH_LONG,
    7259             :                       n_perimeter_decimals);
    7260          27 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_PERIMETRE;
    7261          27 :     i_camp++;
    7262             : 
    7263          27 :     MM_FillFieldDB_XP(bd_xp->pField + i_camp, szMMNomCampAreaDefecte,
    7264             :                       szAreaOfThePolygonEng, szAreaOfThePolygonCat,
    7265             :                       szAreaOfThePolygonSpa, 'N', MM_MIN_WIDTH_AREA,
    7266             :                       n_area_decimals_decimals);
    7267          27 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_AREA;
    7268          27 :     i_camp++;
    7269             : 
    7270          27 :     MM_FillFieldDB_XP(bd_xp->pField + i_camp, szMMNomCampNArcsDefecte,
    7271             :                       szNumberOfArcsEng, szNumberOfArcsCat, szNumberOfArcsSpa,
    7272             :                       'N', MM_MIN_WIDTH_N_ARCS, 0);
    7273          27 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_N_ARCS;
    7274          27 :     i_camp++;
    7275             : 
    7276          27 :     MM_FillFieldDB_XP(
    7277          27 :         bd_xp->pField + i_camp, szMMNomCampNPoligonsDefecte,
    7278             :         szNumberOfElementaryPolygonsEng, szNumberOfElementaryPolygonsCat,
    7279             :         szNumberOfElementaryPolygonsSpa, 'N', MM_MIN_WIDTH_N_POLIG, 0);
    7280          27 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_N_POLIG;
    7281          27 :     i_camp++;
    7282             : 
    7283          27 :     return i_camp;
    7284             : }
    7285             : 
    7286          58 : size_t MM_DefineFirstArcFieldsDB_XP(struct MM_DATA_BASE_XP *bd_xp,
    7287             :                                     MM_BYTE n_decimals)
    7288             : {
    7289             :     MM_EXT_DBF_N_FIELDS i_camp;
    7290             : 
    7291          58 :     i_camp = 0;
    7292          58 :     MM_FillFieldDB_XP(
    7293          58 :         bd_xp->pField + i_camp, szMMNomCampIdGraficDefecte,
    7294             :         szInternalGraphicIdentifierEng, szInternalGraphicIdentifierCat,
    7295             :         szInternalGraphicIdentifierSpa, 'N', MM_MIN_WIDTH_ID_GRAFIC, 0);
    7296          58 :     bd_xp->IdGraficField = 0;
    7297          58 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_ID_GRAFIC;
    7298          58 :     i_camp++;
    7299             : 
    7300          58 :     MM_FillFieldDB_XP(bd_xp->pField + i_camp, szMMNomCampNVertexsDefecte,
    7301             :                       szNumberOfVerticesEng, szNumberOfVerticesCat,
    7302             :                       szNumberOfVerticesSpa, 'N', MM_MIN_WIDTH_N_VERTEXS, 0);
    7303          58 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_N_VERTEXS;
    7304          58 :     i_camp++;
    7305             : 
    7306          58 :     MM_FillFieldDB_XP(bd_xp->pField + i_camp, szMMNomCampLongitudArcDefecte,
    7307             :                       szLengthOfAarcEng, szLengthOfAarcCat, szLengthOfAarcSpa,
    7308             :                       'N', MM_MIN_WIDTH_LONG, n_decimals);
    7309          58 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_LONG_ARC;
    7310          58 :     i_camp++;
    7311             : 
    7312          58 :     MM_FillFieldDB_XP(bd_xp->pField + i_camp, szMMNomCampNodeIniDefecte,
    7313             :                       szInitialNodeEng, szInitialNodeCat, szInitialNodeSpa, 'N',
    7314             :                       MM_MIN_WIDTH_INITIAL_NODE, 0);
    7315          58 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_NODE_INI;
    7316          58 :     i_camp++;
    7317             : 
    7318          58 :     MM_FillFieldDB_XP(bd_xp->pField + i_camp, szMMNomCampNodeFiDefecte,
    7319             :                       szFinalNodeEng, szFinalNodeCat, szFinalNodeSpa, 'N',
    7320             :                       MM_MIN_WIDTH_FINAL_NODE, 0);
    7321          58 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_NODE_FI;
    7322          58 :     i_camp++;
    7323             : 
    7324          58 :     return i_camp;
    7325             : }
    7326             : 
    7327          58 : size_t MM_DefineFirstNodeFieldsDB_XP(struct MM_DATA_BASE_XP *bd_xp)
    7328             : {
    7329             :     MM_EXT_DBF_N_FIELDS i_camp;
    7330             : 
    7331          58 :     i_camp = 0;
    7332             : 
    7333          58 :     MM_FillFieldDB_XP(
    7334          58 :         bd_xp->pField + i_camp, szMMNomCampIdGraficDefecte,
    7335             :         szInternalGraphicIdentifierEng, szInternalGraphicIdentifierCat,
    7336             :         szInternalGraphicIdentifierSpa, 'N', MM_MIN_WIDTH_ID_GRAFIC, 0);
    7337          58 :     bd_xp->IdGraficField = 0;
    7338          58 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_ID_GRAFIC;
    7339          58 :     i_camp++;
    7340             : 
    7341          58 :     MM_FillFieldDB_XP(bd_xp->pField + i_camp, szMMNomCampArcsANodeDefecte,
    7342             :                       szNumberOfArcsToNodeEng, szNumberOfArcsToNodeCat,
    7343             :                       szNumberOfArcsToNodeSpa, 'N', MM_MIN_WIDTH_ARCS_TO_NODE,
    7344             :                       0);
    7345          58 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_ARCS_A_NOD;
    7346          58 :     i_camp++;
    7347             : 
    7348          58 :     MM_FillFieldDB_XP(bd_xp->pField + i_camp, szMMNomCampTipusNodeDefecte,
    7349             :                       szNodeTypeEng, szNodeTypeCat, szNodeTypeSpa, 'N', 1, 0);
    7350          58 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_TIPUS_NODE;
    7351          58 :     i_camp++;
    7352             : 
    7353          58 :     return i_camp;
    7354             : }
    7355             : 
    7356          34 : size_t MM_DefineFirstPointFieldsDB_XP(struct MM_DATA_BASE_XP *bd_xp)
    7357             : {
    7358          34 :     size_t i_camp = 0;
    7359             : 
    7360          34 :     MM_FillFieldDB_XP(
    7361          34 :         bd_xp->pField + i_camp, szMMNomCampIdGraficDefecte,
    7362             :         szInternalGraphicIdentifierEng, szInternalGraphicIdentifierCat,
    7363             :         szInternalGraphicIdentifierSpa, 'N', MM_MIN_WIDTH_ID_GRAFIC, 0);
    7364          34 :     bd_xp->IdGraficField = 0;
    7365          34 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_ID_GRAFIC;
    7366          34 :     i_camp++;
    7367             : 
    7368          34 :     return i_camp;
    7369             : }
    7370             : 
    7371             : CPL_C_END  // Necessary for compiling in GDAL project

Generated by: LCOV version 1.14