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: 2743 3643 75.3 %
Date: 2025-11-08 06:46:40 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 :         GInt32 nLastZCount = 0;
    3858          76 :         MM_FILE_OFFSET nLastOffsetZ = 0;
    3859          76 :         MM_INTERNAL_FID nLastElemCount = 0;
    3860          76 :         nNodeOffset = pFlushNL->TotalSavedBytes + pFlushNL->nNumBytes;
    3861          76 :         nArcOffset = pMMArc->nOffsetArc;
    3862             : 
    3863          76 :         nArcElemCount = pArcTopHeader->nElemCount;
    3864          76 :         nNodeElemCount = pNodeTopHeader->nElemCount;
    3865         164 :         for (nIPart = 0; nIPart < hMMFeature->nNRings; nIPart++,
    3866          88 :             nArcElemCount++,
    3867          88 :             nNodeElemCount += (hMiraMonLayer->bIsPolygon ? 1 : 2))
    3868             :         {
    3869             :             // There is space for the element that is going to be written?
    3870             :             // Polygon or arc
    3871          88 :             if (MMCheckVersionForFID(hMiraMonLayer,
    3872             :                                      hMiraMonLayer->TopHeader.nElemCount))
    3873             :             {
    3874           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
    3875             :                          "Error in MMCheckVersionForFID() (1)");
    3876           0 :                 return MM_STOP_WRITING_FEATURES;
    3877             :             }
    3878             : 
    3879             :             // Arc if there is no polygon
    3880          88 :             if (MMCheckVersionForFID(hMiraMonLayer, nArcElemCount))
    3881             :             {
    3882           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
    3883             :                          "Error in MMCheckVersionForFID() (2)");
    3884           0 :                 return MM_STOP_WRITING_FEATURES;
    3885             :             }
    3886             : 
    3887             :             // Nodes
    3888          88 :             if (MMCheckVersionForFID(hMiraMonLayer, nNodeElemCount))
    3889             :             {
    3890           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
    3891             :                          "Error in MMCheckVersionForFID() (3)");
    3892           0 :                 return MM_STOP_WRITING_FEATURES;
    3893             :             }
    3894             : 
    3895             :             // There is space for the last node(s) that is(are) going to be written?
    3896          88 :             if (!hMiraMonLayer->bIsPolygon)
    3897             :             {
    3898          41 :                 if (MMCheckVersionForFID(hMiraMonLayer, nNodeElemCount + 1))
    3899             :                 {
    3900           0 :                     CPLError(CE_Failure, CPLE_NotSupported,
    3901             :                              "Error in MMCheckVersionForFID() (4)");
    3902           0 :                     return MM_STOP_WRITING_FEATURES;
    3903             :                 }
    3904             :             }
    3905             : 
    3906             :             // Checking offsets
    3907             :             // AL: check the last point
    3908          88 :             if (MMCheckVersionOffset(hMiraMonLayer, nArcOffset))
    3909             :             {
    3910           0 :                 CPLDebugOnly("MiraMon", "Error in MMCheckVersionOffset() (0)");
    3911           0 :                 return MM_STOP_WRITING_FEATURES;
    3912             :             }
    3913             :             // Setting next offset
    3914          88 :             nArcOffset +=
    3915          88 :                 (hMMFeature->pNCoordRing[nIPart]) * pMMArc->nALElementSize;
    3916             : 
    3917             :             // NL: check the last node
    3918          88 :             if (hMiraMonLayer->bIsPolygon)
    3919          47 :                 nNodeOffset += (hMMFeature->nNRings) * MM_SIZE_OF_NL_32BITS;
    3920             :             else
    3921          41 :                 nNodeOffset += (2 * hMMFeature->nNRings) * MM_SIZE_OF_NL_32BITS;
    3922             : 
    3923          88 :             if (MMCheckVersionOffset(hMiraMonLayer, nNodeOffset))
    3924             :             {
    3925           0 :                 CPLDebugOnly("MiraMon", "Error in MMCheckVersionOffset() (1)");
    3926           0 :                 return MM_STOP_WRITING_FEATURES;
    3927             :             }
    3928             :             // Setting next offset
    3929          88 :             nNodeOffset += MM_SIZE_OF_NL_32BITS;
    3930             : 
    3931          88 :             if (!hMiraMonLayer->bIsPolygon)
    3932             :             {
    3933          41 :                 if (MMCheckVersionOffset(hMiraMonLayer, nNodeOffset))
    3934             :                 {
    3935           0 :                     CPLDebugOnly("MiraMon",
    3936             :                                  "Error in MMCheckVersionOffset() (2)");
    3937           0 :                     return MM_STOP_WRITING_FEATURES;
    3938             :                 }
    3939             :                 // Setting next offset
    3940          41 :                 nNodeOffset += MM_SIZE_OF_NL_32BITS;
    3941             :             }
    3942             : 
    3943             :             // Where 3D part is going to start
    3944          88 :             if (hMiraMonLayer->TopHeader.bIs3d)
    3945             :             {
    3946          88 :                 if (nArcElemCount == 0)
    3947             :                 {
    3948          54 :                     if (MMCheckVersionFor3DOffset(hMiraMonLayer,
    3949             :                                                   nArcElemCount + 1, 0, 0))
    3950           0 :                         return MM_STOP_WRITING_FEATURES;
    3951             :                 }
    3952             :                 else
    3953             :                 {
    3954          34 :                     pZDesc = pMMArc->pZSection.pZDescription;
    3955          34 :                     if (!pZDesc)
    3956             :                     {
    3957           0 :                         CPLError(CE_Failure, CPLE_ObjectNull,
    3958             :                                  "Error: pZDescription should not be nullptr");
    3959           0 :                         return MM_STOP_WRITING_FEATURES;
    3960             :                     }
    3961             : 
    3962          34 :                     if (nIPart == 0)
    3963             :                     {
    3964          22 :                         nLastZCount = pZDesc[nArcElemCount - 1].nZCount;
    3965          22 :                         nLastOffsetZ = pZDesc[nArcElemCount - 1].nOffsetZ;
    3966             :                     }
    3967             : 
    3968          34 :                     if (nLastZCount < 0)
    3969             :                     {
    3970             :                         // One altitude was written on last element
    3971          13 :                         if (MMCheckVersionFor3DOffset(
    3972             :                                 hMiraMonLayer, nArcElemCount + 1, nArcOffset,
    3973             :                                 nLastOffsetZ + sizeof(*pZ)))
    3974           0 :                             return MM_STOP_WRITING_FEATURES;
    3975             : 
    3976             :                         // For the next iteration in this multipart feature
    3977          13 :                         nLastOffsetZ += sizeof(*pZ);
    3978             :                     }
    3979             :                     else
    3980             :                     {
    3981             :                         // One for each vertice altitude was written on last element
    3982          21 :                         if (nIPart == 0)
    3983             :                         {
    3984           9 :                             nLastElemCount = (pMMArc->pArcHeader +
    3985           9 :                                               pArcTopHeader->nElemCount - 1)
    3986             :                                                  ->nElemCount;
    3987             :                         }
    3988             :                         else
    3989             :                         {
    3990          12 :                             nLastElemCount += hMMFeature->pNCoordRing[nIPart];
    3991             :                         }
    3992             : 
    3993          21 :                         if (MMCheckVersionFor3DOffset(
    3994             :                                 hMiraMonLayer, nArcElemCount + 1, nArcOffset,
    3995          21 :                                 nLastOffsetZ + sizeof(*pZ) * nLastElemCount))
    3996           0 :                             return MM_STOP_WRITING_FEATURES;
    3997             : 
    3998             :                         // For the next iteration in this multipart feature
    3999          21 :                         nLastOffsetZ += sizeof(*pZ) * nLastElemCount;
    4000             :                     }
    4001             :                 }
    4002             :             }
    4003             :         }
    4004             :     }
    4005             : 
    4006             :     // Going through parts of the feature.
    4007          90 :     nExternalRingsCount = 0;
    4008          90 :     pCoord = hMMFeature->pCoord;
    4009             : 
    4010          90 :     if (!pCoord)
    4011             :     {
    4012           0 :         if (bPolZeroJustCreated)
    4013             :         {
    4014             :             // Rare case where polygon zero creates the database
    4015             :             // but some error occurs in the creation of the polygon zero.
    4016             :             // The database must be destroyed and created again
    4017             :             // next time the polygon zero is created.
    4018           0 :             MMCloseMMBD_XP(hMiraMonLayer);
    4019           0 :             MMDestroyMMDB(hMiraMonLayer);
    4020             :         }
    4021           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    4022             :     }
    4023             : 
    4024             :     // Doing real job
    4025         192 :     for (nIPart = 0; nIPart < hMMFeature->nNRings; nIPart++,
    4026         102 :         pArcTopHeader->nElemCount++,
    4027         102 :         pNodeTopHeader->nElemCount += (hMiraMonLayer->bIsPolygon ? 1 : 2))
    4028             :     {
    4029             :         // Resize structures if necessary
    4030         102 :         if (MMResizeArcHeaderPointer(
    4031         102 :                 &pMMArc->pArcHeader, &pMMArc->nMaxArcHeader,
    4032         102 :                 pArcTopHeader->nElemCount + 1, MM_INCR_NUMBER_OF_ARCS, 0))
    4033             :         {
    4034           0 :             CPLDebugOnly("MiraMon", "Error in MMResizeArcHeaderPointer()");
    4035           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
    4036             :                      "Memory error in MiraMon "
    4037             :                      "driver (MMCreateFeaturePolOrArc())");
    4038           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    4039             :         }
    4040         102 :         if (MMResizeNodeHeaderPointer(
    4041         102 :                 &pMMNode->pNodeHeader, &pMMNode->nMaxNodeHeader,
    4042         102 :                 hMiraMonLayer->bIsPolygon ? pNodeTopHeader->nElemCount + 1
    4043          49 :                                           : pNodeTopHeader->nElemCount + 2,
    4044             :                 MM_INCR_NUMBER_OF_NODES, 0))
    4045             :         {
    4046           0 :             CPLDebugOnly("MiraMon", "Error in MMResizeNodeHeaderPointer()");
    4047           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
    4048             :                      "Memory error in MiraMon "
    4049             :                      "driver (MMCreateFeaturePolOrArc())");
    4050           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    4051             :         }
    4052             : 
    4053         102 :         if (hMiraMonLayer->TopHeader.bIs3d)
    4054             :         {
    4055         102 :             if (MMResizeZSectionDescrPointer(
    4056             :                     &pMMArc->pZSection.pZDescription,
    4057             :                     &pMMArc->pZSection.nMaxZDescription, pMMArc->nMaxArcHeader,
    4058             :                     MM_INCR_NUMBER_OF_ARCS, 0))
    4059             :             {
    4060           0 :                 CPLDebugOnly("MiraMon",
    4061             :                              "Error in MMResizeZSectionDescrPointer()");
    4062           0 :                 CPLError(CE_Failure, CPLE_OutOfMemory,
    4063             :                          "Memory error in MiraMon "
    4064             :                          "driver (MMCreateFeaturePolOrArc())");
    4065           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4066             :             }
    4067         102 :             pZDesc = pMMArc->pZSection.pZDescription;
    4068             :         }
    4069             : 
    4070             :         // Setting pointers to current headers
    4071         102 :         pCurrentArcHeader = pMMArc->pArcHeader + pArcTopHeader->nElemCount;
    4072         102 :         MMInitBoundingBox(&pCurrentArcHeader->dfBB);
    4073             : 
    4074         102 :         pCurrentNodeHeader = pMMNode->pNodeHeader + pNodeTopHeader->nElemCount;
    4075         102 :         if (!hMiraMonLayer->bIsPolygon)
    4076          49 :             pCurrentNodeHeaderPlus1 = pCurrentNodeHeader + 1;
    4077             : 
    4078             :         // Initializing feature information (section AH/PH)
    4079         102 :         pCurrentArcHeader->nElemCount = hMMFeature->pNCoordRing[nIPart];
    4080         102 :         pCurrentArcHeader->dfLength = 0.0;
    4081         102 :         pCurrentArcHeader->nOffset =
    4082         102 :             pFlushAL->TotalSavedBytes + pFlushAL->nNumBytes;
    4083             : 
    4084             :         // Dumping vertices and calculating stuff that
    4085             :         // MiraMon needs (longitude/perimeter, area)
    4086         102 :         bReverseArc = FALSE;
    4087         102 :         if (hMiraMonLayer->bIsPolygon)
    4088             :         {
    4089          53 :             VFG = hMMFeature->flag_VFG[nIPart];
    4090          53 :             bReverseArc = (VFG & MM_ROTATE_ARC) ? TRUE : FALSE;
    4091             :         }
    4092             : 
    4093         102 :         if (bReverseArc)
    4094             :         {
    4095           1 :             prevCoord = 1;  // to find previous coordinate
    4096           1 :             pCoordReal = pCoord + pCurrentArcHeader->nElemCount - 1;
    4097             :         }
    4098             :         else
    4099             :         {
    4100         101 :             prevCoord = -1;  // to find previous coordinate
    4101         101 :             pCoordReal = pCoord;
    4102             :         }
    4103             : 
    4104         572 :         for (nIVertice = 0; nIVertice < pCurrentArcHeader->nElemCount;
    4105         470 :              nIVertice++, (bReverseArc) ? pCoordReal-- : pCoordReal++)
    4106             :         {
    4107             :             // Writing the arc in the normal way
    4108         470 :             pFlushAL->SizeOfBlockToBeSaved = sizeof(pCoordReal->dfX);
    4109         470 :             pFlushAL->pBlockToBeSaved = (void *)&(pCoord + nIVertice)->dfX;
    4110         470 :             if (MMAppendBlockToBuffer(pFlushAL))
    4111             :             {
    4112           0 :                 CPLDebugOnly("MiraMon", "Error in MMAppendBlockToBuffer() (1)");
    4113           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4114             :             }
    4115             : 
    4116         470 :             pFlushAL->pBlockToBeSaved = (void *)&(pCoord + nIVertice)->dfY;
    4117         470 :             if (MMAppendBlockToBuffer(pFlushAL))
    4118             :             {
    4119           0 :                 CPLDebugOnly("MiraMon", "Error in MMAppendBlockToBuffer() (2)");
    4120           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4121             :             }
    4122             : 
    4123             :             // Calculating stuff using the inverse coordinates if it's needed
    4124         470 :             MMUpdateBoundingBoxXY(&pCurrentArcHeader->dfBB, pCoordReal);
    4125         470 :             if (nIVertice == 0 ||
    4126         368 :                 nIVertice == pCurrentArcHeader->nElemCount - 1)
    4127         204 :                 MMUpdateBoundingBoxXY(&pNodeTopHeader->hBB, pCoordReal);
    4128         470 :             if (nIVertice > 0)
    4129             :             {
    4130         368 :                 dtempx = pCoordReal->dfX - (pCoordReal + prevCoord)->dfX;
    4131         368 :                 dtempy = pCoordReal->dfY - (pCoordReal + prevCoord)->dfY;
    4132         368 :                 pCurrentArcHeader->dfLength +=
    4133         368 :                     sqrt(dtempx * dtempx + dtempy * dtempy);
    4134         368 :                 if (hMiraMonLayer->bIsPolygon && pCurrentPolHeader)
    4135             :                 {
    4136         262 :                     pCurrentPolHeader->dfArea +=
    4137         262 :                         (pCoordReal->dfX * (pCoordReal + prevCoord)->dfY -
    4138         262 :                          (pCoordReal + prevCoord)->dfX * pCoordReal->dfY);
    4139             :                 }
    4140             :             }
    4141             :         }
    4142         102 :         if (bReverseArc)
    4143           1 :             pCoord = pCoordReal + pCurrentArcHeader->nElemCount + 1;
    4144             :         else
    4145         101 :             pCoord += pCurrentArcHeader->nElemCount;
    4146             : 
    4147         102 :         nPolVertices += pCurrentArcHeader->nElemCount;
    4148             : 
    4149             :         // Updating bounding boxes
    4150         102 :         MMUpdateBoundingBox(&pArcTopHeader->hBB, &pCurrentArcHeader->dfBB);
    4151         102 :         if (hMiraMonLayer->bIsPolygon)
    4152          53 :             MMUpdateBoundingBox(&hMiraMonLayer->TopHeader.hBB,
    4153             :                                 &pCurrentArcHeader->dfBB);
    4154             : 
    4155         102 :         pMMArc->nOffsetArc +=
    4156         102 :             (pCurrentArcHeader->nElemCount) * pMMArc->nALElementSize;
    4157             : 
    4158         102 :         pCurrentArcHeader->nFirstIdNode = (2 * pArcTopHeader->nElemCount);
    4159         102 :         if (hMiraMonLayer->bIsPolygon)
    4160             :         {
    4161          53 :             pCurrentArcHeader->nFirstIdNode = pArcTopHeader->nElemCount;
    4162          53 :             pCurrentArcHeader->nLastIdNode = pArcTopHeader->nElemCount;
    4163             :         }
    4164             :         else
    4165             :         {
    4166          49 :             pCurrentArcHeader->nFirstIdNode = (2 * pArcTopHeader->nElemCount);
    4167          49 :             pCurrentArcHeader->nLastIdNode =
    4168          49 :                 (2 * pArcTopHeader->nElemCount + 1);
    4169             :         }
    4170         102 :         if (MMAddArcRecordToMMDB(hMiraMonLayer, hMMFeature,
    4171             :                                  pArcTopHeader->nElemCount, pCurrentArcHeader))
    4172             :         {
    4173           0 :             CPLDebugOnly("MiraMon", "Error in MMAddArcRecordToMMDB()");
    4174           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    4175             :         }
    4176             : 
    4177             :         // Node Stuff: writing NL section
    4178         102 :         pCurrentNodeHeader->nArcsCount = 1;
    4179         102 :         if (hMiraMonLayer->bIsPolygon)
    4180          53 :             pCurrentNodeHeader->cNodeType = MM_RING_NODE;
    4181             :         else
    4182          49 :             pCurrentNodeHeader->cNodeType = MM_FINAL_NODE;
    4183             : 
    4184         102 :         pCurrentNodeHeader->nOffset =
    4185         102 :             pFlushNL->TotalSavedBytes + pFlushNL->nNumBytes;
    4186         102 :         if (MMAppendIntegerDependingOnVersion(hMiraMonLayer, pFlushNL,
    4187             :                                               &UnsignedLongNumber,
    4188             :                                               pArcTopHeader->nElemCount))
    4189             :         {
    4190           0 :             CPLDebugOnly("MiraMon",
    4191             :                          "Error in MMAppendIntegerDependingOnVersion()");
    4192           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    4193             :         }
    4194             : 
    4195             :         // 8bytes alignment
    4196         102 :         nOffsetTmp = pFlushNL->TotalSavedBytes + pFlushNL->nNumBytes;
    4197         102 :         MMGetOffsetAlignedTo8(&nOffsetTmp);
    4198         102 :         if (nOffsetTmp != pFlushNL->TotalSavedBytes + pFlushNL->nNumBytes)
    4199             :         {
    4200          88 :             pFlushNL->SizeOfBlockToBeSaved =
    4201          88 :                 (size_t)(nOffsetTmp -
    4202          88 :                          (pFlushNL->TotalSavedBytes + pFlushNL->nNumBytes));
    4203          88 :             pFlushNL->pBlockToBeSaved = (void *)nullptr;
    4204          88 :             if (MMAppendBlockToBuffer(pFlushNL))
    4205             :             {
    4206           0 :                 CPLDebugOnly("MiraMon", "Error in MMAppendBlockToBuffer() (3)");
    4207           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4208             :             }
    4209             :         }
    4210         102 :         if (MMAddNodeRecordToMMDB(hMiraMonLayer, pNodeTopHeader->nElemCount,
    4211             :                                   pCurrentNodeHeader))
    4212             :         {
    4213           0 :             CPLDebugOnly("MiraMon", "Error in MMAddNodeRecordToMMDB()");
    4214           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    4215             :         }
    4216             : 
    4217         102 :         if (!hMiraMonLayer->bIsPolygon)
    4218             :         {
    4219          49 :             pCurrentNodeHeaderPlus1->nArcsCount = 1;
    4220          49 :             if (hMiraMonLayer->bIsPolygon)
    4221           0 :                 pCurrentNodeHeaderPlus1->cNodeType = MM_RING_NODE;
    4222             :             else
    4223          49 :                 pCurrentNodeHeaderPlus1->cNodeType = MM_FINAL_NODE;
    4224             : 
    4225          49 :             pCurrentNodeHeaderPlus1->nOffset =
    4226          49 :                 pFlushNL->TotalSavedBytes + pFlushNL->nNumBytes;
    4227             : 
    4228          49 :             if (MMAppendIntegerDependingOnVersion(hMiraMonLayer, pFlushNL,
    4229             :                                                   &UnsignedLongNumber,
    4230             :                                                   pArcTopHeader->nElemCount))
    4231             :             {
    4232           0 :                 CPLDebugOnly("MiraMon",
    4233             :                              "Error in MMAppendIntegerDependingOnVersion()");
    4234           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4235             :             }
    4236             : 
    4237             :             // 8bytes alignment
    4238          49 :             nOffsetTmp = pFlushNL->TotalSavedBytes + pFlushNL->nNumBytes;
    4239          49 :             MMGetOffsetAlignedTo8(&nOffsetTmp);
    4240          49 :             if (nOffsetTmp != pFlushNL->TotalSavedBytes + pFlushNL->nNumBytes)
    4241             :             {
    4242          41 :                 pFlushNL->SizeOfBlockToBeSaved =
    4243          41 :                     (size_t)(nOffsetTmp -
    4244          41 :                              (pFlushNL->TotalSavedBytes + pFlushNL->nNumBytes));
    4245          41 :                 pFlushNL->pBlockToBeSaved = (void *)nullptr;
    4246          41 :                 if (MMAppendBlockToBuffer(pFlushNL))
    4247             :                 {
    4248           0 :                     CPLDebugOnly("MiraMon", "Error in MMAppendBlockToBuffer()");
    4249           0 :                     return MM_FATAL_ERROR_WRITING_FEATURES;
    4250             :                 }
    4251             :             }
    4252          49 :             if (MMAddNodeRecordToMMDB(hMiraMonLayer,
    4253          49 :                                       pNodeTopHeader->nElemCount + 1,
    4254             :                                       pCurrentNodeHeaderPlus1))
    4255             :             {
    4256           0 :                 CPLDebugOnly("MiraMon", "Error in MMAddNodeRecordToMMDB()");
    4257           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4258             :             }
    4259             :         }
    4260             : 
    4261             :         // 3D stuff
    4262         102 :         if (hMiraMonLayer->TopHeader.bIs3d && pZDesc)
    4263             :         {
    4264         102 :             pZDesc[pArcTopHeader->nElemCount].dfBBminz =
    4265             :                 STATISTICAL_UNDEF_VALUE;
    4266         102 :             pZDesc[pArcTopHeader->nElemCount].dfBBmaxz =
    4267             :                 -STATISTICAL_UNDEF_VALUE;
    4268             : 
    4269             :             // Number of arc altitudes. If the number of altitudes is
    4270             :             // positive this indicates the number of altitudes for
    4271             :             // each vertex of the arc, and all the altitudes of the
    4272             :             // vertex 0 are written first, then those of the vertex 1,
    4273             :             // etc. If the number of altitudes is negative this
    4274             :             // indicates the number of arc altitudes, understanding
    4275             :             // that all the vertices have the same altitude (it is
    4276             :             // the case of a contour line, for example).
    4277             : 
    4278         161 :             for (nIVertice = 0; nIVertice < pCurrentArcHeader->nElemCount;
    4279          59 :                  nIVertice++, pZ++)
    4280             :             {
    4281         145 :                 pFlushZL->SizeOfBlockToBeSaved = sizeof(*pZ);
    4282         145 :                 pFlushZL->pBlockToBeSaved = (void *)pZ;
    4283         145 :                 if (MMAppendBlockToBuffer(pFlushZL))
    4284             :                 {
    4285           0 :                     CPLDebugOnly("MiraMon", "Error in MMAppendBlockToBuffer()");
    4286           0 :                     return MM_FATAL_ERROR_WRITING_FEATURES;
    4287             :                 }
    4288             : 
    4289         145 :                 if (pZDesc[pArcTopHeader->nElemCount].dfBBminz > *pZ)
    4290         115 :                     pZDesc[pArcTopHeader->nElemCount].dfBBminz = *pZ;
    4291         145 :                 if (pZDesc[pArcTopHeader->nElemCount].dfBBmaxz < *pZ)
    4292         116 :                     pZDesc[pArcTopHeader->nElemCount].dfBBmaxz = *pZ;
    4293             : 
    4294         145 :                 if (pMMArc->pZSection.ZHeader.dfBBminz > *pZ)
    4295          68 :                     pMMArc->pZSection.ZHeader.dfBBminz = *pZ;
    4296         145 :                 if (pMMArc->pZSection.ZHeader.dfBBmaxz < *pZ)
    4297          67 :                     pMMArc->pZSection.ZHeader.dfBBmaxz = *pZ;
    4298             : 
    4299             :                 // Only one altitude (the same for all vertices) is written
    4300         145 :                 if (hMMFeature->bAllZHaveSameValue)
    4301          86 :                     break;
    4302             :             }
    4303         102 :             if (hMMFeature->bAllZHaveSameValue)
    4304             :             {
    4305             :                 // Same altitude for all vertices
    4306          86 :                 pZDesc[pArcTopHeader->nElemCount].nZCount = -1;
    4307             :             }
    4308             :             else
    4309             :             {
    4310             :                 // One different altitude for each vertice
    4311          16 :                 pZDesc[pArcTopHeader->nElemCount].nZCount = 1;
    4312             :             }
    4313             : 
    4314         102 :             if (pArcTopHeader->nElemCount == 0)
    4315          58 :                 pZDesc[pArcTopHeader->nElemCount].nOffsetZ = 0;
    4316             :             else
    4317             :             {
    4318          44 :                 if (pZDesc[pArcTopHeader->nElemCount - 1].nZCount < 0)
    4319             :                 {
    4320          32 :                     pZDesc[pArcTopHeader->nElemCount].nOffsetZ =
    4321          32 :                         pZDesc[pArcTopHeader->nElemCount - 1].nOffsetZ +
    4322             :                         sizeof(*pZ);
    4323             :                 }
    4324             :                 else
    4325             :                 {
    4326          12 :                     pLastArcHeader =
    4327          12 :                         pMMArc->pArcHeader + pArcTopHeader->nElemCount - 1;
    4328             : 
    4329          12 :                     pZDesc[pArcTopHeader->nElemCount].nOffsetZ =
    4330          12 :                         pZDesc[pArcTopHeader->nElemCount - 1].nOffsetZ +
    4331          12 :                         sizeof(*pZ) * (pLastArcHeader->nElemCount);
    4332             :                 }
    4333             :             }
    4334             :         }
    4335             : 
    4336             :         // Exclusive polygon stuff
    4337         102 :         if (hMiraMonLayer->bIsPolygon && pCurrentPolHeader)
    4338             :         {
    4339             :             // PS SECTION
    4340          53 :             if (MMAppendIntegerDependingOnVersion(hMiraMonLayer, pFlushPS,
    4341             :                                                   &UnsignedLongNumber, 0))
    4342             :             {
    4343           0 :                 CPLDebugOnly("MiraMon",
    4344             :                              "Error in MMAppendIntegerDependingOnVersion()");
    4345           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4346             :             }
    4347             : 
    4348          53 :             if (MMAppendIntegerDependingOnVersion(
    4349             :                     hMiraMonLayer, pFlushPS, &UnsignedLongNumber,
    4350             :                     hMiraMonLayer->TopHeader.nElemCount))
    4351             :             {
    4352           0 :                 CPLDebugOnly("MiraMon",
    4353             :                              "Error in MMAppendIntegerDependingOnVersion()");
    4354           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4355             :             }
    4356             : 
    4357             :             // PAL SECTION
    4358             :             // Vertices of rings defining
    4359             :             // holes in polygons are in a counterclockwise direction.
    4360             :             // Holes are at the end of all external rings that contain the holes!!
    4361          53 :             if (VFG & MM_EXTERIOR_ARC_SIDE)
    4362          45 :                 nExternalRingsCount++;
    4363             : 
    4364          53 :             pCurrentPolHeader->nArcsCount++;
    4365             :             //(MM_POLYGON_ARCS_COUNT)hMMFeature->nNRings;
    4366          53 :             if (VFG & MM_EXTERIOR_ARC_SIDE)
    4367             :                 pCurrentPolHeader
    4368          45 :                     ->nExternalRingsCount++;  //= nExternalRingsCount;
    4369             : 
    4370          53 :             if (VFG & MM_END_ARC_IN_RING)
    4371          53 :                 pCurrentPolHeader->nRingsCount++;  //= hMMFeature->nNRings;
    4372          53 :             if (nIPart == 0)
    4373             :             {
    4374          41 :                 pCurrentPolHeader->nOffset =
    4375          41 :                     pFlushPAL->TotalSavedBytes + pFlushPAL->nNumBytes;
    4376             :             }
    4377             : 
    4378          53 :             if (nIPart == hMMFeature->nNRings - 1)
    4379          41 :                 pCurrentPolHeader->dfArea /= 2;
    4380             : 
    4381          53 :             pFlushPAL->SizeOfBlockToBeSaved = 1;
    4382          53 :             pFlushPAL->pBlockToBeSaved = (void *)&VFG;
    4383          53 :             if (MMAppendBlockToBuffer(pFlushPAL))
    4384             :             {
    4385           0 :                 CPLDebugOnly("MiraMon", "Error in MMAppendBlockToBuffer()");
    4386           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4387             :             }
    4388             : 
    4389          53 :             if (MMAppendIntegerDependingOnVersion(hMiraMonLayer, pFlushPAL,
    4390             :                                                   &UnsignedLongNumber,
    4391             :                                                   pArcTopHeader->nElemCount))
    4392             :             {
    4393           0 :                 CPLDebugOnly("MiraMon",
    4394             :                              "Error in MMAppendIntegerDependingOnVersion()");
    4395           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4396             :             }
    4397             : 
    4398             :             // 8bytes alignment
    4399          53 :             if (nIPart == hMMFeature->nNRings - 1)
    4400             :             {
    4401          41 :                 nOffsetTmp = pFlushPAL->TotalSavedBytes + pFlushPAL->nNumBytes;
    4402          41 :                 MMGetOffsetAlignedTo8(&nOffsetTmp);
    4403             : 
    4404          41 :                 if (nOffsetTmp !=
    4405          41 :                     pFlushPAL->TotalSavedBytes + pFlushPAL->nNumBytes)
    4406             :                 {
    4407          41 :                     pFlushPAL->SizeOfBlockToBeSaved =
    4408          41 :                         (size_t)(nOffsetTmp - (pFlushPAL->TotalSavedBytes +
    4409          41 :                                                pFlushPAL->nNumBytes));
    4410          41 :                     pFlushPAL->pBlockToBeSaved = (void *)nullptr;
    4411          41 :                     if (MMAppendBlockToBuffer(pFlushPAL))
    4412             :                     {
    4413           0 :                         CPLDebugOnly("MiraMon",
    4414             :                                      "Error in MMAppendBlockToBuffer()");
    4415           0 :                         return MM_FATAL_ERROR_WRITING_FEATURES;
    4416             :                     }
    4417             :                 }
    4418             :             }
    4419             : 
    4420          53 :             MMUpdateBoundingBox(&pCurrentPolHeader->dfBB,
    4421             :                                 &pCurrentArcHeader->dfBB);
    4422          53 :             pCurrentPolHeader->dfPerimeter += pCurrentArcHeader->dfLength;
    4423             :         }
    4424             :     }
    4425             : 
    4426             :     // Updating element count and if the polygon is multipart.
    4427             :     // MiraMon does not accept multipoints or multilines, only multipolygons.
    4428          90 :     if (hMiraMonLayer->bIsPolygon)
    4429             :     {
    4430          41 :         if (MMAddPolygonRecordToMMDB(hMiraMonLayer, hMMFeature,
    4431             :                                      hMiraMonLayer->TopHeader.nElemCount,
    4432             :                                      nPolVertices, pCurrentPolHeader))
    4433             :         {
    4434           0 :             CPLDebugOnly("MiraMon", "Error in MMAddPolygonRecordToMMDB()");
    4435           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    4436             :         }
    4437          41 :         hMiraMonLayer->TopHeader.nElemCount++;
    4438             : 
    4439          41 :         if (nExternalRingsCount > 1)
    4440           4 :             hMiraMonLayer->TopHeader.bIsMultipolygon = TRUE;
    4441             :     }
    4442             : 
    4443          90 :     return MM_CONTINUE_WRITING_FEATURES;
    4444             : }  // End of de MMCreateFeaturePolOrArc()
    4445             : 
    4446             : // Creates a MiraMon DBF record when not associated with a geometric feature.
    4447          34 : static int MMCreateRecordDBF(struct MiraMonVectLayerInfo *hMiraMonLayer,
    4448             :                              struct MiraMonFeature *hMMFeature)
    4449             : {
    4450             :     int result;
    4451             : 
    4452          34 :     if (!hMiraMonLayer)
    4453           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    4454             : 
    4455          34 :     if (hMiraMonLayer->TopHeader.nElemCount == 0)
    4456             :     {
    4457          17 :         if (MMCreateMMDB(hMiraMonLayer, nullptr))
    4458             :         {
    4459           0 :             MMDestroyMMDB(hMiraMonLayer);
    4460           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    4461             :         }
    4462             :     }
    4463             : 
    4464          34 :     result = MMAddDBFRecordToMMDB(hMiraMonLayer, hMMFeature);
    4465          34 :     if (result == MM_FATAL_ERROR_WRITING_FEATURES ||
    4466             :         result == MM_STOP_WRITING_FEATURES)
    4467           0 :         return result;
    4468             : 
    4469             :     // Everything OK.
    4470          34 :     return MM_CONTINUE_WRITING_FEATURES;
    4471             : }  // End of de MMCreateRecordDBF()
    4472             : 
    4473             : // Creates a MiraMon point feature.
    4474          89 : static int MMCreateFeaturePoint(struct MiraMonVectLayerInfo *hMiraMonLayer,
    4475             :                                 struct MiraMonFeature *hMMFeature)
    4476             : {
    4477          89 :     double *pZ = nullptr;
    4478             :     struct MM_POINT_2D *pCoord;
    4479             :     MM_POLYGON_RINGS_COUNT nIPart;
    4480             :     MM_N_VERTICES_TYPE nIVertice, nCoord;
    4481          89 :     struct MM_ZD *pZDescription = nullptr;
    4482             :     MM_INTERNAL_FID nElemCount;
    4483             :     int result;
    4484             : 
    4485          89 :     if (!hMiraMonLayer)
    4486           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    4487             : 
    4488          89 :     if (!hMMFeature)
    4489           0 :         return MM_STOP_WRITING_FEATURES;
    4490             : 
    4491          89 :     if (hMiraMonLayer->TopHeader.bIs3d)
    4492          89 :         pZ = hMMFeature->pZCoord;
    4493             : 
    4494          89 :     nElemCount = hMiraMonLayer->TopHeader.nElemCount;
    4495         178 :     for (nIPart = 0, pCoord = hMMFeature->pCoord; nIPart < hMMFeature->nNRings;
    4496          89 :          nIPart++, nElemCount++)
    4497             :     {
    4498          89 :         nCoord = hMMFeature->pNCoordRing[nIPart];
    4499             : 
    4500             :         // Checking if its possible continue writing the file due
    4501             :         // to version limitations.
    4502          89 :         if (MMCheckVersionForFID(hMiraMonLayer,
    4503          89 :                                  hMiraMonLayer->TopHeader.nElemCount + nCoord))
    4504             :         {
    4505           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    4506             :                      "Error in MMCheckVersionForFID() (5)");
    4507           0 :             return MM_STOP_WRITING_FEATURES;
    4508             :         }
    4509             : 
    4510          89 :         if (hMiraMonLayer->TopHeader.bIs3d)
    4511             :         {
    4512          89 :             if (nElemCount == 0)
    4513             :             {
    4514          34 :                 if (MMCheckVersionFor3DOffset(hMiraMonLayer, (nElemCount + 1),
    4515             :                                               0, 0))
    4516           0 :                     return MM_STOP_WRITING_FEATURES;
    4517             :             }
    4518             :             else
    4519             :             {
    4520          55 :                 pZDescription = hMiraMonLayer->MMPoint.pZSection.pZDescription;
    4521          55 :                 if (!pZDescription)
    4522             :                 {
    4523           0 :                     CPLError(CE_Failure, CPLE_ObjectNull,
    4524             :                              "Error: pZDescription should not be nullptr");
    4525           0 :                     return MM_STOP_WRITING_FEATURES;
    4526             :                 }
    4527             : 
    4528          55 :                 if (MMCheckVersionFor3DOffset(
    4529             :                         hMiraMonLayer, nElemCount + 1, 0,
    4530          55 :                         pZDescription[nElemCount - 1].nOffsetZ + sizeof(*pZ)))
    4531           0 :                     return MM_STOP_WRITING_FEATURES;
    4532             :             }
    4533             :         }
    4534             : 
    4535             :         // Doing real job
    4536             :         // Memory issues
    4537          89 :         if (hMiraMonLayer->TopHeader.bIs3d && pZ)
    4538             :         {
    4539          89 :             if (MMResizeZSectionDescrPointer(
    4540             :                     &hMiraMonLayer->MMPoint.pZSection.pZDescription,
    4541             :                     &hMiraMonLayer->MMPoint.pZSection.nMaxZDescription,
    4542             :                     nElemCount, MM_INCR_NUMBER_OF_POINTS, 0))
    4543             :             {
    4544           0 :                 CPLError(CE_Failure, CPLE_OutOfMemory,
    4545             :                          "Memory error in MiraMon "
    4546             :                          "driver (MMCreateFeaturePoint())");
    4547           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4548             :             }
    4549             : 
    4550          89 :             pZDescription = hMiraMonLayer->MMPoint.pZSection.pZDescription;
    4551          89 :             if (!pZDescription)
    4552             :             {
    4553           0 :                 CPLError(CE_Failure, CPLE_ObjectNull,
    4554             :                          "Error: pZDescription should not be nullptr");
    4555           0 :                 return MM_STOP_WRITING_FEATURES;
    4556             :             }
    4557             : 
    4558          89 :             pZDescription[nElemCount].dfBBminz = *pZ;
    4559          89 :             pZDescription[nElemCount].dfBBmaxz = *pZ;
    4560             : 
    4561          89 :             if (hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBminz > *pZ)
    4562          41 :                 hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBminz = *pZ;
    4563          89 :             if (hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBmaxz < *pZ)
    4564          38 :                 hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBmaxz = *pZ;
    4565             : 
    4566             :             // Specification ask for a negative number.
    4567          89 :             pZDescription[nElemCount].nZCount = -1;
    4568          89 :             if (nElemCount == 0)
    4569          34 :                 pZDescription[nElemCount].nOffsetZ = 0;
    4570             :             else
    4571          55 :                 pZDescription[nElemCount].nOffsetZ =
    4572          55 :                     pZDescription[nElemCount - 1].nOffsetZ + sizeof(*pZ);
    4573             :         }
    4574             : 
    4575             :         // Flush settings
    4576          89 :         hMiraMonLayer->MMPoint.FlushTL.pBlockWhereToSaveOrRead =
    4577          89 :             (void *)hMiraMonLayer->MMPoint.pTL;
    4578          89 :         if (hMiraMonLayer->TopHeader.bIs3d)
    4579          89 :             hMiraMonLayer->MMPoint.pZSection.FlushZL.pBlockWhereToSaveOrRead =
    4580          89 :                 (void *)hMiraMonLayer->MMPoint.pZSection.pZL;
    4581             : 
    4582             :         // Dump point or points (MiraMon does not have multiple points)
    4583         178 :         for (nIVertice = 0; nIVertice < nCoord; nIVertice++, pCoord++)
    4584             :         {
    4585             :             // Updating the bounding box of the layer
    4586          89 :             MMUpdateBoundingBoxXY(&hMiraMonLayer->TopHeader.hBB, pCoord);
    4587             : 
    4588             :             // Adding the point at the memory block
    4589          89 :             hMiraMonLayer->MMPoint.FlushTL.SizeOfBlockToBeSaved =
    4590             :                 sizeof(pCoord->dfX);
    4591          89 :             hMiraMonLayer->MMPoint.FlushTL.pBlockToBeSaved =
    4592          89 :                 (void *)&pCoord->dfX;
    4593          89 :             if (MMAppendBlockToBuffer(&hMiraMonLayer->MMPoint.FlushTL))
    4594           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4595          89 :             hMiraMonLayer->MMPoint.FlushTL.pBlockToBeSaved =
    4596          89 :                 (void *)&pCoord->dfY;
    4597          89 :             if (MMAppendBlockToBuffer(&hMiraMonLayer->MMPoint.FlushTL))
    4598           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4599             : 
    4600             :             // Adding the 3D part, if exists, at the memory block
    4601          89 :             if (hMiraMonLayer->TopHeader.bIs3d && pZ)
    4602             :             {
    4603          89 :                 hMiraMonLayer->MMPoint.pZSection.FlushZL.SizeOfBlockToBeSaved =
    4604             :                     sizeof(*pZ);
    4605          89 :                 hMiraMonLayer->MMPoint.pZSection.FlushZL.pBlockToBeSaved =
    4606             :                     (void *)pZ;
    4607          89 :                 if (MMAppendBlockToBuffer(
    4608             :                         &hMiraMonLayer->MMPoint.pZSection.FlushZL))
    4609           0 :                     return MM_FATAL_ERROR_WRITING_FEATURES;
    4610             : 
    4611          89 :                 if (!pZDescription)
    4612             :                 {
    4613           0 :                     CPLError(CE_Failure, CPLE_ObjectNull,
    4614             :                              "Error: pZDescription should not be nullptr");
    4615           0 :                     return MM_STOP_WRITING_FEATURES;
    4616             :                 }
    4617             : 
    4618          89 :                 if (pZDescription[nElemCount].dfBBminz > *pZ)
    4619           0 :                     pZDescription[nElemCount].dfBBminz = *pZ;
    4620          89 :                 if (pZDescription[nElemCount].dfBBmaxz < *pZ)
    4621           0 :                     pZDescription[nElemCount].dfBBmaxz = *pZ;
    4622             : 
    4623          89 :                 if (hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBminz > *pZ)
    4624           0 :                     hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBminz = *pZ;
    4625          89 :                 if (hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBmaxz < *pZ)
    4626           0 :                     hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBmaxz = *pZ;
    4627             : 
    4628          89 :                 pZ++;
    4629             :             }
    4630             :         }
    4631             : 
    4632          89 :         if (hMiraMonLayer->TopHeader.nElemCount == 0)
    4633             :         {
    4634          34 :             if (MMCreateMMDB(hMiraMonLayer, hMMFeature->pCoord))
    4635           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4636             :         }
    4637             : 
    4638          89 :         result = MMAddPointRecordToMMDB(hMiraMonLayer, hMMFeature, nElemCount);
    4639          89 :         if (result == MM_FATAL_ERROR_WRITING_FEATURES ||
    4640             :             result == MM_STOP_WRITING_FEATURES)
    4641           0 :             return result;
    4642             :     }
    4643             :     // Updating nElemCount at the header of the layer
    4644          89 :     hMiraMonLayer->TopHeader.nElemCount = nElemCount;
    4645             : 
    4646             :     // Everything OK.
    4647          89 :     return MM_CONTINUE_WRITING_FEATURES;
    4648             : }  // End of de MMCreateFeaturePoint()
    4649             : 
    4650             : // Checks whether a given Feature ID (FID) exceeds the maximum allowed
    4651             : // index for 2 GB vectors in a specific MiraMon layer.
    4652         804 : int MMCheckVersionForFID(struct MiraMonVectLayerInfo *hMiraMonLayer,
    4653             :                          MM_INTERNAL_FID FID)
    4654             : {
    4655         804 :     if (!hMiraMonLayer)
    4656           0 :         return 1;
    4657             : 
    4658         804 :     if (hMiraMonLayer->LayerVersion != MM_32BITS_VERSION)
    4659          56 :         return 0;
    4660             : 
    4661         748 :     if (FID >= MAXIMUM_OBJECT_INDEX_IN_2GB_VECTORS)
    4662           0 :         return 1;
    4663         748 :     return 0;
    4664             : }
    4665             : 
    4666             : // Checks whether a given offset exceeds the maximum allowed
    4667             : // index for 2 GB vectors in a specific MiraMon layer.
    4668         217 : int MMCheckVersionOffset(struct MiraMonVectLayerInfo *hMiraMonLayer,
    4669             :                          MM_FILE_OFFSET OffsetToCheck)
    4670             : {
    4671         217 :     if (!hMiraMonLayer)
    4672           0 :         return 1;
    4673             : 
    4674             :     // Checking if the final version is 1.1 or 2.0
    4675         217 :     if (hMiraMonLayer->LayerVersion != MM_32BITS_VERSION)
    4676           0 :         return 0;
    4677             : 
    4678             :     // User decided that if necessary, output version can be 2.0
    4679         217 :     if (OffsetToCheck < MAXIMUM_OFFSET_IN_2GB_VECTORS)
    4680         217 :         return 0;
    4681             : 
    4682           0 :     return 1;
    4683             : }
    4684             : 
    4685             : // Checks whether a given offset in 3D section exceeds the maximum allowed
    4686             : // index for 2 GB vectors in a specific MiraMon layer.
    4687         177 : int MMCheckVersionFor3DOffset(struct MiraMonVectLayerInfo *hMiraMonLayer,
    4688             :                               MM_INTERNAL_FID nElemCount,
    4689             :                               MM_FILE_OFFSET nOffsetAL,
    4690             :                               MM_FILE_OFFSET nZLOffset)
    4691             : {
    4692             :     MM_FILE_OFFSET LastOffset;
    4693             : 
    4694         177 :     if (!hMiraMonLayer)
    4695           0 :         return 1;
    4696             : 
    4697             :     // Checking if the final version is 1.1 or 2.0
    4698         177 :     if (hMiraMonLayer->LayerVersion != MM_32BITS_VERSION)
    4699           6 :         return 0;
    4700             : 
    4701             :     // User decided that if necessary, output version can be 2.0
    4702         171 :     if (hMiraMonLayer->bIsPoint)
    4703          83 :         LastOffset = MM_HEADER_SIZE_32_BITS + nElemCount * MM_SIZE_OF_TL;
    4704             :     else  // Arc case
    4705             :     {
    4706          88 :         LastOffset = MM_HEADER_SIZE_32_BITS +
    4707          88 :                      nElemCount * MM_SIZE_OF_AH_32BITS + +nOffsetAL;
    4708             :     }
    4709             : 
    4710         171 :     LastOffset += MM_SIZE_OF_ZH;
    4711         171 :     LastOffset += nElemCount * MM_SIZE_OF_ZD_32_BITS;
    4712         171 :     LastOffset += nZLOffset;
    4713             : 
    4714         171 :     if (LastOffset < MAXIMUM_OFFSET_IN_2GB_VECTORS)
    4715         171 :         return 0;
    4716             : 
    4717           0 :     return 1;
    4718             : }
    4719             : 
    4720             : // Adds a feature in a MiraMon layer.
    4721         213 : int MMAddFeature(struct MiraMonVectLayerInfo *hMiraMonLayer,
    4722             :                  struct MiraMonFeature *hMiraMonFeature)
    4723             : {
    4724             :     int re;
    4725         213 :     MM_INTERNAL_FID previousFID = 0;
    4726             : 
    4727         213 :     if (!hMiraMonLayer)
    4728           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    4729             : 
    4730         213 :     if (!hMiraMonLayer->bIsBeenInit)
    4731             :     {
    4732           0 :         if (MMInitLayerByType(hMiraMonLayer))
    4733             :         {
    4734           0 :             CPLDebugOnly("MiraMon", "Error in MMInitLayerByType()");
    4735           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    4736             :         }
    4737           0 :         hMiraMonLayer->bIsBeenInit = 1;
    4738             :     }
    4739             : 
    4740         213 :     if (hMiraMonFeature)
    4741         213 :         previousFID = hMiraMonLayer->TopHeader.nElemCount;
    4742             : 
    4743         213 :     if (hMiraMonLayer->bIsPoint)
    4744             :     {
    4745          89 :         re = MMCreateFeaturePoint(hMiraMonLayer, hMiraMonFeature);
    4746          89 :         if (hMiraMonFeature)
    4747             :         {
    4748          89 :             hMiraMonFeature->nReadFeatures =
    4749          89 :                 hMiraMonLayer->TopHeader.nElemCount - previousFID;
    4750             :         }
    4751          89 :         return re;
    4752             :     }
    4753         124 :     if (hMiraMonLayer->bIsArc || hMiraMonLayer->bIsPolygon)
    4754             :     {
    4755          90 :         re = MMCreateFeaturePolOrArc(hMiraMonLayer, hMiraMonFeature);
    4756          90 :         if (hMiraMonFeature)
    4757             :         {
    4758          90 :             hMiraMonFeature->nReadFeatures =
    4759          90 :                 hMiraMonLayer->TopHeader.nElemCount - previousFID;
    4760             :         }
    4761          90 :         return re;
    4762             :     }
    4763          34 :     if (hMiraMonLayer->bIsDBF)
    4764             :     {
    4765             :         // Adding a record to DBF file
    4766          34 :         re = MMCreateRecordDBF(hMiraMonLayer, hMiraMonFeature);
    4767          34 :         if (hMiraMonFeature)
    4768             :         {
    4769          34 :             hMiraMonFeature->nReadFeatures =
    4770          34 :                 hMiraMonLayer->TopHeader.nElemCount - previousFID;
    4771             :         }
    4772          34 :         return re;
    4773             :     }
    4774             : 
    4775           0 :     return MM_CONTINUE_WRITING_FEATURES;
    4776             : }
    4777             : 
    4778             : /* -------------------------------------------------------------------- */
    4779             : /*      Tools used by MiraMon.                                          */
    4780             : /* -------------------------------------------------------------------- */
    4781             : 
    4782         320 : void MMInitBoundingBox(struct MMBoundingBox *dfBB)
    4783             : {
    4784         320 :     if (!dfBB)
    4785           0 :         return;
    4786         320 :     dfBB->dfMinX = STATISTICAL_UNDEF_VALUE;
    4787         320 :     dfBB->dfMaxX = -STATISTICAL_UNDEF_VALUE;
    4788         320 :     dfBB->dfMinY = STATISTICAL_UNDEF_VALUE;
    4789         320 :     dfBB->dfMaxY = -STATISTICAL_UNDEF_VALUE;
    4790             : }
    4791             : 
    4792         208 : void MMUpdateBoundingBox(struct MMBoundingBox *dfBBToBeAct,
    4793             :                          struct MMBoundingBox *dfBBWithData)
    4794             : {
    4795         208 :     if (!dfBBToBeAct)
    4796           0 :         return;
    4797             : 
    4798         208 :     if (dfBBToBeAct->dfMinX > dfBBWithData->dfMinX)
    4799         133 :         dfBBToBeAct->dfMinX = dfBBWithData->dfMinX;
    4800             : 
    4801         208 :     if (dfBBToBeAct->dfMinY > dfBBWithData->dfMinY)
    4802         148 :         dfBBToBeAct->dfMinY = dfBBWithData->dfMinY;
    4803             : 
    4804         208 :     if (dfBBToBeAct->dfMaxX < dfBBWithData->dfMaxX)
    4805         147 :         dfBBToBeAct->dfMaxX = dfBBWithData->dfMaxX;
    4806             : 
    4807         208 :     if (dfBBToBeAct->dfMaxY < dfBBWithData->dfMaxY)
    4808         145 :         dfBBToBeAct->dfMaxY = dfBBWithData->dfMaxY;
    4809             : }
    4810             : 
    4811         763 : void MMUpdateBoundingBoxXY(struct MMBoundingBox *dfBB,
    4812             :                            struct MM_POINT_2D *pCoord)
    4813             : {
    4814         763 :     if (!pCoord)
    4815           0 :         return;
    4816             : 
    4817         763 :     if (pCoord->dfX < dfBB->dfMinX)
    4818         269 :         dfBB->dfMinX = pCoord->dfX;
    4819             : 
    4820         763 :     if (pCoord->dfY < dfBB->dfMinY)
    4821         294 :         dfBB->dfMinY = pCoord->dfY;
    4822             : 
    4823         763 :     if (pCoord->dfX > dfBB->dfMaxX)
    4824         398 :         dfBB->dfMaxX = pCoord->dfX;
    4825             : 
    4826         763 :     if (pCoord->dfY > dfBB->dfMaxY)
    4827         358 :         dfBB->dfMaxY = pCoord->dfY;
    4828             : }
    4829             : 
    4830             : /* -------------------------------------------------------------------- */
    4831             : /*      Resize structures for reuse                                     */
    4832             : /* -------------------------------------------------------------------- */
    4833        1398 : int MMResizeMiraMonFieldValue(struct MiraMonFieldValue **pFieldValue,
    4834             :                               MM_EXT_DBF_N_MULTIPLE_RECORDS *nMax,
    4835             :                               MM_EXT_DBF_N_MULTIPLE_RECORDS nNum,
    4836             :                               MM_EXT_DBF_N_MULTIPLE_RECORDS nIncr,
    4837             :                               MM_EXT_DBF_N_MULTIPLE_RECORDS nProposedMax)
    4838             : {
    4839             :     MM_EXT_DBF_N_MULTIPLE_RECORDS nPrevMax;
    4840             :     MM_EXT_DBF_N_MULTIPLE_RECORDS nNewMax;
    4841             :     void *pTmp;
    4842             : 
    4843        1398 :     if (nNum < *nMax)
    4844        1379 :         return 0;
    4845             : 
    4846          19 :     nPrevMax = *nMax;
    4847          19 :     nNewMax = MAX(nNum + nIncr, nProposedMax);
    4848          19 :     if (MMCheckSize_t(nNewMax, sizeof(**pFieldValue)))
    4849             :     {
    4850           0 :         return 1;
    4851             :     }
    4852          19 :     if ((pTmp = VSIRealloc(*pFieldValue,
    4853          19 :                            (size_t)nNewMax * sizeof(**pFieldValue))) == nullptr)
    4854             :     {
    4855           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    4856             :                  "Memory error in MiraMon "
    4857             :                  "driver (MMResizeMiraMonFieldValue())");
    4858           0 :         return 1;
    4859             :     }
    4860          19 :     *nMax = nNewMax;
    4861          19 :     *pFieldValue = pTmp;
    4862             : 
    4863          19 :     memset((*pFieldValue) + nPrevMax, 0,
    4864          19 :            (size_t)(*nMax - nPrevMax) * sizeof(**pFieldValue));
    4865          19 :     return 0;
    4866             : }
    4867             : 
    4868         352 : int MMResizeMiraMonPolygonArcs(struct MM_PAL_MEM **pFID,
    4869             :                                MM_POLYGON_ARCS_COUNT *nMax,
    4870             :                                MM_POLYGON_ARCS_COUNT nNum,
    4871             :                                MM_POLYGON_ARCS_COUNT nIncr,
    4872             :                                MM_POLYGON_ARCS_COUNT nProposedMax)
    4873             : {
    4874             :     MM_POLYGON_ARCS_COUNT nPrevMax;
    4875             :     MM_POLYGON_ARCS_COUNT nNewMax;
    4876             :     void *pTmp;
    4877             : 
    4878         352 :     if (nNum < *nMax)
    4879          32 :         return 0;
    4880             : 
    4881         320 :     nPrevMax = *nMax;
    4882         320 :     nNewMax = MAX(nNum + nIncr, nProposedMax);
    4883         320 :     if (MMCheckSize_t(nNewMax, sizeof(**pFID)))
    4884             :     {
    4885           0 :         return 1;
    4886             :     }
    4887         320 :     if (nNewMax == 0 && *pFID)
    4888           0 :         return 0;
    4889         320 :     if ((pTmp = VSIRealloc(*pFID, (size_t)nNewMax * sizeof(**pFID))) == nullptr)
    4890             :     {
    4891           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    4892             :                  "Memory error in MiraMon "
    4893             :                  "driver (MMResizeMiraMonPolygonArcs())");
    4894           0 :         return 1;
    4895             :     }
    4896         320 :     *nMax = nNewMax;
    4897         320 :     *pFID = pTmp;
    4898             : 
    4899         320 :     memset((*pFID) + nPrevMax, 0, (size_t)(*nMax - nPrevMax) * sizeof(**pFID));
    4900         320 :     return 0;
    4901             : }
    4902             : 
    4903          88 : int MMResizeMiraMonRecord(struct MiraMonRecord **pMiraMonRecord,
    4904             :                           MM_EXT_DBF_N_MULTIPLE_RECORDS *nMax,
    4905             :                           MM_EXT_DBF_N_MULTIPLE_RECORDS nNum,
    4906             :                           MM_EXT_DBF_N_MULTIPLE_RECORDS nIncr,
    4907             :                           MM_EXT_DBF_N_MULTIPLE_RECORDS nProposedMax)
    4908             : {
    4909             :     MM_EXT_DBF_N_MULTIPLE_RECORDS nPrevMax;
    4910             :     MM_EXT_DBF_N_MULTIPLE_RECORDS nNewMax;
    4911             :     void *pTmp;
    4912             : 
    4913          88 :     if (nNum < *nMax)
    4914          72 :         return 0;
    4915             : 
    4916          16 :     nPrevMax = *nMax;
    4917          16 :     nNewMax = MAX(nNum + nIncr, nProposedMax);
    4918          16 :     if (MMCheckSize_t(nNewMax, sizeof(**pMiraMonRecord)))
    4919             :     {
    4920           0 :         return 1;
    4921             :     }
    4922          16 :     if (nNewMax == 0 && *pMiraMonRecord)
    4923           0 :         return 0;
    4924          16 :     if ((pTmp = VSIRealloc(*pMiraMonRecord,
    4925          16 :                            (size_t)nNewMax * sizeof(**pMiraMonRecord))) ==
    4926             :         nullptr)
    4927             :     {
    4928           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    4929             :                  "Memory error in MiraMon "
    4930             :                  "driver (MMResizeMiraMonRecord())");
    4931           0 :         return 1;
    4932             :     }
    4933          16 :     *nMax = nNewMax;
    4934          16 :     *pMiraMonRecord = pTmp;
    4935             : 
    4936          16 :     memset((*pMiraMonRecord) + nPrevMax, 0,
    4937          16 :            (size_t)(*nMax - nPrevMax) * sizeof(**pMiraMonRecord));
    4938          16 :     return 0;
    4939             : }
    4940             : 
    4941         191 : int MMResizeZSectionDescrPointer(struct MM_ZD **pZDescription, GUInt64 *nMax,
    4942             :                                  GUInt64 nNum, GUInt64 nIncr,
    4943             :                                  GUInt64 nProposedMax)
    4944             : {
    4945             :     GUInt64 nNewMax, nPrevMax;
    4946             :     void *pTmp;
    4947             : 
    4948         191 :     if (nNum < *nMax)
    4949         133 :         return 0;
    4950             : 
    4951          58 :     nPrevMax = *nMax;
    4952          58 :     nNewMax = MAX(nNum + nIncr, nProposedMax);
    4953          58 :     if (MMCheckSize_t(nNewMax, sizeof(**pZDescription)))
    4954             :     {
    4955           0 :         return 1;
    4956             :     }
    4957          58 :     if (nNewMax == 0 && *pZDescription)
    4958           0 :         return 0;
    4959          58 :     if ((pTmp = VSIRealloc(*pZDescription,
    4960             :                            (size_t)nNewMax * sizeof(**pZDescription))) ==
    4961             :         nullptr)
    4962             :     {
    4963           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    4964             :                  "Memory error in MiraMon "
    4965             :                  "driver (MMResizeZSectionDescrPointer())");
    4966           0 :         return 1;
    4967             :     }
    4968          58 :     *nMax = nNewMax;
    4969          58 :     *pZDescription = pTmp;
    4970             : 
    4971          58 :     memset((*pZDescription) + nPrevMax, 0,
    4972          58 :            (size_t)(*nMax - nPrevMax) * sizeof(**pZDescription));
    4973          58 :     return 0;
    4974             : }
    4975             : 
    4976         102 : int MMResizeNodeHeaderPointer(struct MM_NH **pNodeHeader, GUInt64 *nMax,
    4977             :                               GUInt64 nNum, GUInt64 nIncr, GUInt64 nProposedMax)
    4978             : {
    4979             :     GUInt64 nNewMax, nPrevMax;
    4980             :     void *pTmp;
    4981             : 
    4982         102 :     if (nNum < *nMax)
    4983         102 :         return 0;
    4984             : 
    4985           0 :     nPrevMax = *nMax;
    4986           0 :     nNewMax = MAX(nNum + nIncr, nProposedMax);
    4987           0 :     if (MMCheckSize_t(nNewMax, sizeof(**pNodeHeader)))
    4988             :     {
    4989           0 :         return 1;
    4990             :     }
    4991           0 :     if (nNewMax == 0 && *pNodeHeader)
    4992           0 :         return 0;
    4993           0 :     if ((pTmp = VSIRealloc(*pNodeHeader,
    4994             :                            (size_t)nNewMax * sizeof(**pNodeHeader))) == nullptr)
    4995             :     {
    4996           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    4997             :                  "Memory error in MiraMon "
    4998             :                  "driver (MMResizeNodeHeaderPointer())");
    4999           0 :         return 1;
    5000             :     }
    5001           0 :     *nMax = nNewMax;
    5002           0 :     *pNodeHeader = pTmp;
    5003             : 
    5004           0 :     memset((*pNodeHeader) + nPrevMax, 0,
    5005           0 :            (size_t)(*nMax - nPrevMax) * sizeof(**pNodeHeader));
    5006           0 :     return 0;
    5007             : }
    5008             : 
    5009         102 : int MMResizeArcHeaderPointer(struct MM_AH **pArcHeader, GUInt64 *nMax,
    5010             :                              GUInt64 nNum, GUInt64 nIncr, GUInt64 nProposedMax)
    5011             : {
    5012             :     GUInt64 nNewMax, nPrevMax;
    5013             :     void *pTmp;
    5014             : 
    5015         102 :     if (nNum < *nMax)
    5016         102 :         return 0;
    5017             : 
    5018           0 :     nPrevMax = *nMax;
    5019           0 :     nNewMax = MAX(nNum + nIncr, nProposedMax);
    5020           0 :     if (MMCheckSize_t(nNewMax, sizeof(**pArcHeader)))
    5021             :     {
    5022           0 :         return 1;
    5023             :     }
    5024           0 :     if (nNewMax == 0 && *pArcHeader)
    5025           0 :         return 0;
    5026           0 :     if ((pTmp = VSIRealloc(*pArcHeader,
    5027             :                            (size_t)nNewMax * sizeof(**pArcHeader))) == nullptr)
    5028             :     {
    5029           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    5030             :                  "Memory error in MiraMon "
    5031             :                  "driver (MMResizeArcHeaderPointer())");
    5032           0 :         return 1;
    5033             :     }
    5034           0 :     *nMax = nNewMax;
    5035           0 :     *pArcHeader = pTmp;
    5036             : 
    5037           0 :     memset((*pArcHeader) + nPrevMax, 0,
    5038           0 :            (size_t)(*nMax - nPrevMax) * sizeof(**pArcHeader));
    5039           0 :     return 0;
    5040             : }
    5041             : 
    5042          41 : int MMResizePolHeaderPointer(struct MM_PH **pPolHeader, GUInt64 *nMax,
    5043             :                              GUInt64 nNum, GUInt64 nIncr, GUInt64 nProposedMax)
    5044             : {
    5045             :     GUInt64 nNewMax, nPrevMax;
    5046             :     void *pTmp;
    5047             : 
    5048          41 :     if (nNum < *nMax)
    5049          41 :         return 0;
    5050             : 
    5051           0 :     nPrevMax = *nMax;
    5052           0 :     nNewMax = MAX(nNum + nIncr, nProposedMax);
    5053           0 :     if (MMCheckSize_t(nNewMax, sizeof(**pPolHeader)))
    5054             :     {
    5055           0 :         return 1;
    5056             :     }
    5057           0 :     if (nNewMax == 0 && *pPolHeader)
    5058           0 :         return 0;
    5059           0 :     if ((pTmp = VSIRealloc(*pPolHeader,
    5060             :                            (size_t)nNewMax * sizeof(**pPolHeader))) == nullptr)
    5061             :     {
    5062           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    5063             :                  "Memory error in MiraMon "
    5064             :                  "driver (MMResizePolHeaderPointer())");
    5065           0 :         return 1;
    5066             :     }
    5067           0 :     *nMax = nNewMax;
    5068           0 :     *pPolHeader = pTmp;
    5069             : 
    5070           0 :     memset((*pPolHeader) + nPrevMax, 0,
    5071           0 :            (size_t)(*nMax - nPrevMax) * sizeof(**pPolHeader));
    5072           0 :     return 0;
    5073             : }
    5074             : 
    5075        2747 : int MMResize_MM_N_VERTICES_TYPE_Pointer(MM_N_VERTICES_TYPE **pVrt,
    5076             :                                         MM_N_VERTICES_TYPE *nMax,
    5077             :                                         MM_N_VERTICES_TYPE nNum,
    5078             :                                         MM_N_VERTICES_TYPE nIncr,
    5079             :                                         MM_N_VERTICES_TYPE nProposedMax)
    5080             : {
    5081             :     MM_N_VERTICES_TYPE nNewMax, nPrevMax;
    5082             :     void *pTmp;
    5083             : 
    5084        2747 :     if (nNum < *nMax)
    5085        1234 :         return 0;
    5086             : 
    5087        1513 :     nPrevMax = *nMax;
    5088        1513 :     nNewMax = MAX(nNum + nIncr, nProposedMax);
    5089        1513 :     if (MMCheckSize_t(nNewMax, sizeof(**pVrt)))
    5090             :     {
    5091           0 :         return 1;
    5092             :     }
    5093        1513 :     if (nNewMax == 0 && *pVrt)
    5094           0 :         return 0;
    5095        1513 :     if ((pTmp = VSIRealloc(*pVrt, (size_t)nNewMax * sizeof(**pVrt))) == nullptr)
    5096             :     {
    5097           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    5098             :                  "Memory error in MiraMon "
    5099             :                  "driver (MMResize_MM_N_VERTICES_TYPE_Pointer())");
    5100           0 :         return 1;
    5101             :     }
    5102        1513 :     *nMax = nNewMax;
    5103        1513 :     *pVrt = pTmp;
    5104             : 
    5105        1513 :     memset((*pVrt) + nPrevMax, 0, (size_t)(*nMax - nPrevMax) * sizeof(**pVrt));
    5106        1513 :     return 0;
    5107             : }
    5108             : 
    5109         399 : int MMResizeVFGPointer(char **pInt, MM_INTERNAL_FID *nMax, MM_INTERNAL_FID nNum,
    5110             :                        MM_INTERNAL_FID nIncr, MM_INTERNAL_FID nProposedMax)
    5111             : {
    5112             :     MM_N_VERTICES_TYPE nNewMax, nPrevMax;
    5113             :     void *pTmp;
    5114             : 
    5115         399 :     if (nNum < *nMax)
    5116          58 :         return 0;
    5117             : 
    5118         341 :     nPrevMax = *nMax;
    5119         341 :     nNewMax = MAX(nNum + nIncr, nProposedMax);
    5120         341 :     if (MMCheckSize_t(nNewMax, sizeof(**pInt)))
    5121             :     {
    5122           0 :         return 1;
    5123             :     }
    5124         341 :     if (nNewMax == 0 && *pInt)
    5125           0 :         return 0;
    5126         341 :     if ((pTmp = VSIRealloc(*pInt, (size_t)nNewMax * sizeof(**pInt))) == nullptr)
    5127             :     {
    5128           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    5129             :                  "Memory error in MiraMon "
    5130             :                  "driver (MMResizeVFGPointer())");
    5131           0 :         return 1;
    5132             :     }
    5133         341 :     *nMax = nNewMax;
    5134         341 :     *pInt = pTmp;
    5135             : 
    5136         341 :     memset((*pInt) + nPrevMax, 0, (size_t)(*nMax - nPrevMax) * sizeof(**pInt));
    5137         341 :     return 0;
    5138             : }
    5139             : 
    5140        2760 : int MMResizeMM_POINT2DPointer(struct MM_POINT_2D **pPoint2D,
    5141             :                               MM_N_VERTICES_TYPE *nMax, MM_N_VERTICES_TYPE nNum,
    5142             :                               MM_N_VERTICES_TYPE nIncr,
    5143             :                               MM_N_VERTICES_TYPE nProposedMax)
    5144             : {
    5145             :     MM_N_VERTICES_TYPE nNewMax, nPrevMax;
    5146             :     void *pTmp;
    5147             : 
    5148        2760 :     if (nNum < *nMax)
    5149        2367 :         return 0;
    5150             : 
    5151         393 :     nPrevMax = *nMax;
    5152         393 :     nNewMax = MAX(nNum + nIncr, nProposedMax);
    5153         393 :     if (MMCheckSize_t(nNewMax, sizeof(**pPoint2D)))
    5154             :     {
    5155           0 :         return 1;
    5156             :     }
    5157         393 :     if (nNewMax == 0 && *pPoint2D)
    5158           0 :         return 0;
    5159         393 :     if ((pTmp = VSIRealloc(*pPoint2D, (size_t)nNewMax * sizeof(**pPoint2D))) ==
    5160             :         nullptr)
    5161             :     {
    5162           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    5163             :                  "Memory error in MiraMon "
    5164             :                  "driver (MMResizeMM_POINT2DPointer())");
    5165           0 :         return 1;
    5166             :     }
    5167         393 :     *nMax = nNewMax;
    5168         393 :     *pPoint2D = pTmp;
    5169             : 
    5170         393 :     memset((*pPoint2D) + nPrevMax, 0,
    5171         393 :            (size_t)(*nMax - nPrevMax) * sizeof(**pPoint2D));
    5172         393 :     return 0;
    5173             : }
    5174             : 
    5175        1787 : int MMResizeDoublePointer(MM_COORD_TYPE **pDouble, MM_N_VERTICES_TYPE *nMax,
    5176             :                           MM_N_VERTICES_TYPE nNum, MM_N_VERTICES_TYPE nIncr,
    5177             :                           MM_N_VERTICES_TYPE nProposedMax)
    5178             : {
    5179             :     MM_N_VERTICES_TYPE nNewMax, nPrevMax;
    5180             :     void *pTmp;
    5181             : 
    5182        1787 :     if (nNum < *nMax)
    5183        1619 :         return 0;
    5184             : 
    5185         168 :     nPrevMax = *nMax;
    5186         168 :     nNewMax = MAX(nNum + nIncr, nProposedMax);
    5187         168 :     if (MMCheckSize_t(nNewMax, sizeof(**pDouble)))
    5188             :     {
    5189           0 :         return 1;
    5190             :     }
    5191         168 :     if (nNewMax == 0 && *pDouble)
    5192           0 :         return 0;
    5193         168 :     if ((pTmp = VSIRealloc(*pDouble, (size_t)nNewMax * sizeof(**pDouble))) ==
    5194             :         nullptr)
    5195             :     {
    5196           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    5197             :                  "Memory error in MiraMon "
    5198             :                  "driver (MMResizeDoublePointer())");
    5199           0 :         return 1;
    5200             :     }
    5201         168 :     *nMax = nNewMax;
    5202         168 :     *pDouble = pTmp;
    5203             : 
    5204         168 :     memset((*pDouble) + nPrevMax, 0,
    5205         168 :            (size_t)(*nMax - nPrevMax) * sizeof(**pDouble));
    5206         168 :     return 0;
    5207             : }
    5208             : 
    5209       23549 : int MMResizeStringToOperateIfNeeded(struct MiraMonVectLayerInfo *hMiraMonLayer,
    5210             :                                     MM_EXT_DBF_N_FIELDS nNewSize)
    5211             : {
    5212       23549 :     if (!hMiraMonLayer)
    5213           0 :         return 1;
    5214             : 
    5215       23549 :     if (nNewSize >= hMiraMonLayer->nNumStringToOperate)
    5216             :     {
    5217             :         char *p;
    5218         449 :         if (MMCheckSize_t(nNewSize, 1))
    5219           0 :             return 1;
    5220         449 :         p = (char *)VSICalloc(1, (size_t)nNewSize);
    5221         449 :         if (!p)
    5222             :         {
    5223           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
    5224             :                      "Memory error in MiraMon "
    5225             :                      "driver (MMResizeStringToOperateIfNeeded())");
    5226           0 :             return 1;
    5227             :         }
    5228         449 :         VSIFree(hMiraMonLayer->szStringToOperate);
    5229         449 :         hMiraMonLayer->szStringToOperate = p;
    5230         449 :         hMiraMonLayer->nNumStringToOperate = nNewSize;
    5231             :     }
    5232       23549 :     return 0;
    5233             : }
    5234             : 
    5235             : /* -------------------------------------------------------------------- */
    5236             : /*      Metadata Functions                                              */
    5237             : /* -------------------------------------------------------------------- */
    5238             : 
    5239             : #define LineReturn "\r\n"
    5240             : 
    5241             : // Generates an identifier that REL 4 MiraMon metadata needs.
    5242         177 : static void MMGenerateFileIdentifierFromMetadataFileName(char *pMMFN,
    5243             :                                                          char *aFileIdentifier)
    5244             : {
    5245             :     char aCharRand[8];
    5246             :     static const char aCharset[] =
    5247             :         "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    5248             :     int i, len_charset;
    5249             : 
    5250         177 :     memset(aFileIdentifier, '\0', MM_MAX_LEN_LAYER_IDENTIFIER);
    5251             : 
    5252         177 :     aCharRand[0] = '_';
    5253         177 :     len_charset = (int)strlen(aCharset);
    5254        1239 :     for (i = 1; i < 7; i++)
    5255             :     {
    5256             : #ifndef __COVERITY__
    5257        1062 :         aCharRand[i] = aCharset[rand() % (len_charset - 1)];
    5258             : #else
    5259             :         aCharRand[i] = aCharset[i % (len_charset - 1)];
    5260             : #endif
    5261             :     }
    5262         177 :     aCharRand[7] = '\0';
    5263         177 :     CPLStrlcpy(aFileIdentifier, pMMFN, MM_MAX_LEN_LAYER_IDENTIFIER - 7);
    5264         177 :     strcat(aFileIdentifier, aCharRand);
    5265         177 :     return;
    5266             : }
    5267             : 
    5268             : // Converts a string from UTF-8 to ANSI to be written in a REL 4 file
    5269         759 : static void MMWrite_ANSI_MetadataKeyDescriptor(
    5270             :     struct MiraMonVectorMetaData *hMMMD, VSILFILE *pF, const char *pszEng,
    5271             :     const char *pszCat, const char *pszEsp, const char *pszCurrentEncoding)
    5272             : {
    5273         759 :     if (!EQUAL(pszCurrentEncoding, CPL_ENC_ISO8859_1))
    5274             :     {
    5275          99 :         char *pszString = nullptr;
    5276             : 
    5277          99 :         switch (hMMMD->nMMLanguage)
    5278             :         {
    5279           2 :             case MM_CAT_LANGUAGE:
    5280             :                 pszString =
    5281           2 :                     CPLRecode(pszCat, pszCurrentEncoding, CPL_ENC_ISO8859_1);
    5282           2 :                 break;
    5283           2 :             case MM_SPA_LANGUAGE:
    5284             :                 pszString =
    5285           2 :                     CPLRecode(pszEsp, pszCurrentEncoding, CPL_ENC_ISO8859_1);
    5286           2 :                 break;
    5287          95 :             default:
    5288             :             case MM_ENG_LANGUAGE:
    5289             :                 pszString =
    5290          95 :                     CPLRecode(pszEng, pszCurrentEncoding, CPL_ENC_ISO8859_1);
    5291          95 :                 break;
    5292             :         }
    5293          99 :         if (pszString)
    5294             :         {
    5295          99 :             VSIFPrintfL(pF, "%s", KEY_descriptor);
    5296          99 :             VSIFPrintfL(pF, "=");
    5297          99 :             VSIFPrintfL(pF, "%s", pszString);
    5298          99 :             VSIFPrintfL(pF, "%s", LineReturn);
    5299          99 :             CPLFree(pszString);
    5300             :         }
    5301             :     }
    5302             :     else
    5303             :     {
    5304             :         const char *pszString;
    5305         660 :         switch (hMMMD->nMMLanguage)
    5306             :         {
    5307           1 :             case MM_CAT_LANGUAGE:
    5308           1 :                 pszString = pszCat;
    5309           1 :                 break;
    5310           1 :             case MM_SPA_LANGUAGE:
    5311           1 :                 pszString = pszEsp;
    5312           1 :                 break;
    5313         658 :             default:
    5314             :             case MM_ENG_LANGUAGE:
    5315         658 :                 pszString = pszEng;
    5316         658 :                 break;
    5317             :         }
    5318         660 :         if (pszString)
    5319             :         {
    5320         660 :             VSIFPrintfL(pF, "%s", KEY_descriptor);
    5321         660 :             VSIFPrintfL(pF, "=");
    5322         660 :             VSIFPrintfL(pF, "%s", pszString);
    5323         660 :             VSIFPrintfL(pF, "%s", LineReturn);
    5324             :         }
    5325             :     }
    5326         759 : }
    5327             : 
    5328             : /*
    5329             :     Writes a MiraMon REL 4 metadata file. Next sections are included:
    5330             :     VERSION, METADADES, IDENTIFICATION, EXTENT, OVERVIEW,
    5331             :     TAULA_PRINCIPAL and GEOMETRIA_I_TOPOLOGIA
    5332             : 
    5333             :     Please, consult the meaning of all them at:
    5334             :     https://www.miramon.cat/help/eng/GeMPlus/ClausREL.htm
    5335             : 
    5336             :     This file must be written in ANSI encoding; therefore, some
    5337             :     conversions are performed for strings that may originally
    5338             :     be in UTF-8.
    5339             : */
    5340         177 : static int MMWriteMetadataFile(struct MiraMonVectorMetaData *hMMMD)
    5341             : {
    5342             :     char aMessage[MM_MESSAGE_LENGTH],
    5343             :         aFileIdentifier[MM_MAX_LEN_LAYER_IDENTIFIER], aMMIDSRS[MM_MAX_ID_SNY];
    5344             :     char *pszChaiCP1252;
    5345             :     MM_EXT_DBF_N_FIELDS nIField;
    5346             :     VSILFILE *pF;
    5347             :     time_t currentTime;
    5348             :     char aTimeString[200];
    5349             : 
    5350         177 :     if (!hMMMD->aLayerName)
    5351           0 :         return 0;
    5352             : 
    5353         177 :     if (nullptr == (pF = VSIFOpenL(hMMMD->aLayerName, "wb")))
    5354             :     {
    5355           0 :         CPLError(CE_Failure, CPLE_OpenFailed, "The file %s must exist.",
    5356             :                  hMMMD->aLayerName);
    5357           0 :         return 1;
    5358             :     }
    5359             : 
    5360             :     // Writing MiraMon version section
    5361         177 :     VSIFPrintfL(pF, "[%s]" LineReturn, SECTION_VERSIO);
    5362             : 
    5363         177 :     VSIFPrintfL(pF, "%s=%u" LineReturn, KEY_Vers, (unsigned)MM_VERS);
    5364         177 :     VSIFPrintfL(pF, "%s=%u" LineReturn, KEY_SubVers, (unsigned)MM_SUBVERS);
    5365             : 
    5366         177 :     VSIFPrintfL(pF, "%s=%u" LineReturn, KEY_VersMetaDades,
    5367             :                 (unsigned)MM_VERS_METADADES);
    5368         177 :     VSIFPrintfL(pF, "%s=%u" LineReturn, KEY_SubVersMetaDades,
    5369             :                 (unsigned)MM_SUBVERS_METADADES);
    5370             : 
    5371             :     // Writing METADADES section
    5372         177 :     VSIFPrintfL(pF, "\r\n[%s]" LineReturn, SECTION_METADADES);
    5373         177 :     CPLStrlcpy(aMessage, hMMMD->aLayerName, sizeof(aMessage));
    5374         177 :     MMGenerateFileIdentifierFromMetadataFileName(aMessage, aFileIdentifier);
    5375             : 
    5376         177 :     pszChaiCP1252 = CPLRecode(aFileIdentifier, CPL_ENC_UTF8, "CP1252");
    5377         177 :     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_FileIdentifier,
    5378             :                 pszChaiCP1252 ? pszChaiCP1252 : aFileIdentifier);
    5379         177 :     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_language, KEY_Value_eng);
    5380         177 :     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_MDIdiom, KEY_Value_eng);
    5381         177 :     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_characterSet,
    5382             :                 KEY_Value_characterSet);
    5383             : 
    5384             :     // Writing IDENTIFICATION section
    5385         177 :     VSIFPrintfL(pF, LineReturn "[%s]" LineReturn, SECTION_IDENTIFICATION);
    5386         177 :     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_code,
    5387             :                 pszChaiCP1252 ? pszChaiCP1252 : aFileIdentifier);
    5388         177 :     VSIFPrintfL(pF, "%s=" LineReturn, KEY_codeSpace);
    5389         177 :     CPLFree(pszChaiCP1252);  // Not needed
    5390         177 :     if (hMMMD->szLayerTitle && !MMIsEmptyString(hMMMD->szLayerTitle))
    5391             :     {
    5392         177 :         pszChaiCP1252 = CPLRecode(hMMMD->szLayerTitle, CPL_ENC_UTF8, "CP1252");
    5393         177 :         if (hMMMD->ePlainLT == MM_LayerType_Point)
    5394          34 :             VSIFPrintfL(pF, "%s=%s (pnt)" LineReturn, KEY_DatasetTitle,
    5395             :                         pszChaiCP1252 ? pszChaiCP1252 : hMMMD->szLayerTitle);
    5396         177 :         if (hMMMD->ePlainLT == MM_LayerType_Arc)
    5397          58 :             VSIFPrintfL(pF, "%s=%s (arc)" LineReturn, KEY_DatasetTitle,
    5398             :                         pszChaiCP1252 ? pszChaiCP1252 : hMMMD->szLayerTitle);
    5399         177 :         if (hMMMD->ePlainLT == MM_LayerType_Pol)
    5400          27 :             VSIFPrintfL(pF, "%s=%s (pol)" LineReturn, KEY_DatasetTitle,
    5401             :                         pszChaiCP1252 ? pszChaiCP1252 : hMMMD->szLayerTitle);
    5402         177 :         CPLFree(pszChaiCP1252);
    5403             :     }
    5404         177 :     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_language, KEY_Value_eng);
    5405             : 
    5406         177 :     if (hMMMD->ePlainLT != MM_LayerType_Node &&
    5407         119 :         hMMMD->ePlainLT != MM_LayerType_Pol)
    5408             :     {
    5409             :         // SPATIAL_REFERENCE_SYSTEM:HORIZONTAL
    5410          92 :         VSIFPrintfL(pF, LineReturn "[%s:%s]" LineReturn,
    5411             :                     SECTION_SPATIAL_REFERENCE_SYSTEM, SECTION_HORIZONTAL);
    5412         113 :         if (!ReturnMMIDSRSFromEPSGCodeSRS(hMMMD->pSRS, aMMIDSRS) &&
    5413          21 :             !MMIsEmptyString(aMMIDSRS))
    5414          21 :             VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_HorizontalSystemIdentifier,
    5415             :                         aMMIDSRS);
    5416             :         else
    5417             :         {
    5418          71 :             CPLError(CE_Warning, CPLE_NotSupported,
    5419             :                      "The MiraMon driver cannot assign any HRS.");
    5420             :             // Horizontal Reference System
    5421          71 :             VSIFPrintfL(pF, "%s=plane" LineReturn,
    5422             :                         KEY_HorizontalSystemIdentifier);
    5423          71 :             VSIFPrintfL(pF, "%s=local" LineReturn,
    5424             :                         KEY_HorizontalSystemDefinition);
    5425          71 :             if (hMMMD->pXUnit)
    5426           0 :                 VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_unitats, hMMMD->pXUnit);
    5427          71 :             if (hMMMD->pYUnit)
    5428             :             {
    5429           0 :                 if (!hMMMD->pXUnit || strcasecmp(hMMMD->pXUnit, hMMMD->pYUnit))
    5430           0 :                     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_unitatsY,
    5431             :                                 hMMMD->pYUnit);
    5432             :             }
    5433             :         }
    5434             : 
    5435             :         // SPATIAL_REFERENCE_SYSTEM:VERTICAL
    5436             :         // Llegim les unitats del Sist. ref. vertical
    5437          92 :         if (hMMMD->pZUnit)
    5438             :         {
    5439           0 :             VSIFPrintfL(pF, LineReturn "[%s:%s]" LineReturn,
    5440             :                         SECTION_SPATIAL_REFERENCE_SYSTEM, SECTION_VERTICAL);
    5441           0 :             VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_unitats, hMMMD->pZUnit);
    5442             :         }
    5443             :     }
    5444             : 
    5445         177 :     if (hMMMD->ePlainLT == MM_LayerType_Pol && hMMMD->aArcFile)
    5446             :     {
    5447             :         // Writing OVERVIEW:ASPECTES_TECNICS in polygon metadata file.
    5448             :         // ArcSource=fitx_pol.arc
    5449          27 :         pszChaiCP1252 = CPLRecode(hMMMD->aArcFile, CPL_ENC_UTF8, "CP1252");
    5450          27 :         VSIFPrintfL(pF, LineReturn "[%s]" LineReturn,
    5451             :                     SECTION_OVVW_ASPECTES_TECNICS);
    5452          27 :         VSIFPrintfL(pF, "%s=\"%s\"" LineReturn, KEY_ArcSource, pszChaiCP1252);
    5453          27 :         CPLFree(pszChaiCP1252);
    5454             :     }
    5455         150 :     else if (hMMMD->ePlainLT == MM_LayerType_Arc && hMMMD->aArcFile)
    5456             :     {
    5457          27 :         pszChaiCP1252 = CPLRecode(hMMMD->aArcFile, CPL_ENC_UTF8, "CP1252");
    5458             :         // Writing OVERVIEW:ASPECTES_TECNICS in arc metadata file.
    5459             :         // Ciclat1=fitx_arc.pol
    5460          27 :         VSIFPrintfL(pF, LineReturn "[%s]" LineReturn,
    5461             :                     SECTION_OVVW_ASPECTES_TECNICS);
    5462          27 :         VSIFPrintfL(pF, "Ciclat1=\"%s\"" LineReturn, pszChaiCP1252);
    5463          27 :         CPLFree(pszChaiCP1252);
    5464             :     }
    5465             : 
    5466             :     // Writing EXTENT section
    5467         177 :     VSIFPrintfL(pF, LineReturn "[%s]" LineReturn, SECTION_EXTENT);
    5468         177 :     VSIFPrintfL(pF, "%s=0" LineReturn, KEY_toler_env);
    5469             : 
    5470         177 :     if (hMMMD->hBB.dfMinX != MM_UNDEFINED_STATISTICAL_VALUE &&
    5471         177 :         hMMMD->hBB.dfMaxX != -MM_UNDEFINED_STATISTICAL_VALUE &&
    5472         177 :         hMMMD->hBB.dfMinY != MM_UNDEFINED_STATISTICAL_VALUE &&
    5473         177 :         hMMMD->hBB.dfMaxY != -MM_UNDEFINED_STATISTICAL_VALUE)
    5474             :     {
    5475         177 :         VSIFPrintfL(pF, "%s=%lf" LineReturn, KEY_MinX, hMMMD->hBB.dfMinX);
    5476         177 :         VSIFPrintfL(pF, "%s=%lf" LineReturn, KEY_MaxX, hMMMD->hBB.dfMaxX);
    5477         177 :         VSIFPrintfL(pF, "%s=%lf" LineReturn, KEY_MinY, hMMMD->hBB.dfMinY);
    5478         177 :         VSIFPrintfL(pF, "%s=%lf" LineReturn, KEY_MaxY, hMMMD->hBB.dfMaxY);
    5479             :     }
    5480             : 
    5481             :     // Writing OVERVIEW section
    5482         177 :     VSIFPrintfL(pF, LineReturn "[%s]" LineReturn, SECTION_OVERVIEW);
    5483             : 
    5484         177 :     currentTime = time(nullptr);
    5485             : 
    5486             :     struct tm ltime;
    5487         177 :     VSILocalTime(&currentTime, &ltime);
    5488         177 :     snprintf(aTimeString, sizeof(aTimeString), "%04d%02d%02d %02d%02d%02d%02d",
    5489         177 :              ltime.tm_year + 1900, ltime.tm_mon + 1, ltime.tm_mday,
    5490             :              ltime.tm_hour, ltime.tm_min, ltime.tm_sec, 0);
    5491         177 :     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_CreationDate, aTimeString);
    5492         177 :     VSIFPrintfL(pF, LineReturn);
    5493             : 
    5494             :     // Writing TAULA_PRINCIPAL section
    5495         177 :     VSIFPrintfL(pF, "[%s]" LineReturn, SECTION_TAULA_PRINCIPAL);
    5496         177 :     VSIFPrintfL(pF, "IdGrafic=%s" LineReturn, szMMNomCampIdGraficDefecte);
    5497         177 :     VSIFPrintfL(pF, "TipusRelacio=RELACIO_1_1_DICC" LineReturn);
    5498             : 
    5499         177 :     VSIFPrintfL(pF, LineReturn);
    5500         177 :     VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5501             :                 szMMNomCampIdGraficDefecte);
    5502         177 :     VSIFPrintfL(pF, "visible=0" LineReturn);
    5503         177 :     VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5504             : 
    5505         177 :     MMWrite_ANSI_MetadataKeyDescriptor(
    5506             :         hMMMD, pF, szInternalGraphicIdentifierEng,
    5507             :         szInternalGraphicIdentifierCat, szInternalGraphicIdentifierSpa,
    5508             :         CPL_ENC_ISO8859_1);
    5509             : 
    5510         177 :     if (hMMMD->ePlainLT == MM_LayerType_Arc)
    5511             :     {
    5512          58 :         VSIFPrintfL(pF, LineReturn);
    5513          58 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5514             :                     szMMNomCampNVertexsDefecte);
    5515          58 :         VSIFPrintfL(pF, "visible=0" LineReturn);
    5516          58 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5517          58 :         MMWrite_ANSI_MetadataKeyDescriptor(
    5518             :             hMMMD, pF, szNumberOfVerticesEng, szNumberOfVerticesCat,
    5519             :             szNumberOfVerticesSpa, CPL_ENC_ISO8859_1);
    5520             : 
    5521          58 :         VSIFPrintfL(pF, LineReturn);
    5522          58 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5523             :                     szMMNomCampLongitudArcDefecte);
    5524          58 :         MMWrite_ANSI_MetadataKeyDescriptor(hMMMD, pF, szLengthOfAarcEng,
    5525             :                                            szLengthOfAarcCat, szLengthOfAarcSpa,
    5526             :                                            CPL_ENC_ISO8859_1);
    5527             : 
    5528          58 :         VSIFPrintfL(pF, LineReturn);
    5529          58 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5530             :                     szMMNomCampNodeIniDefecte);
    5531          58 :         VSIFPrintfL(pF, "visible=0" LineReturn);
    5532          58 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5533          58 :         MMWrite_ANSI_MetadataKeyDescriptor(hMMMD, pF, szInitialNodeEng,
    5534             :                                            szInitialNodeCat, szInitialNodeSpa,
    5535             :                                            CPL_ENC_ISO8859_1);
    5536             : 
    5537          58 :         VSIFPrintfL(pF, LineReturn);
    5538          58 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5539             :                     szMMNomCampNodeFiDefecte);
    5540          58 :         VSIFPrintfL(pF, "visible=0" LineReturn);
    5541          58 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5542          58 :         MMWrite_ANSI_MetadataKeyDescriptor(hMMMD, pF, szFinalNodeEng,
    5543             :                                            szFinalNodeCat, szFinalNodeSpa,
    5544             :                                            CPL_ENC_ISO8859_1);
    5545             : 
    5546          58 :         VSIFPrintfL(pF, LineReturn);
    5547          58 :         VSIFPrintfL(pF, "[GEOMETRIA_I_TOPOLOGIA]" LineReturn);
    5548          58 :         VSIFPrintfL(pF, "NomCampNVertexs=%s" LineReturn,
    5549             :                     szMMNomCampNVertexsDefecte);
    5550          58 :         VSIFPrintfL(pF, "NomCampLongitudArc=%s" LineReturn,
    5551             :                     szMMNomCampLongitudArcDefecte);
    5552          58 :         VSIFPrintfL(pF, "NomCampNodeIni=%s" LineReturn,
    5553             :                     szMMNomCampNodeIniDefecte);
    5554          58 :         VSIFPrintfL(pF, "NomCampNodeFi=%s" LineReturn,
    5555             :                     szMMNomCampNodeFiDefecte);
    5556             :     }
    5557         119 :     else if (hMMMD->ePlainLT == MM_LayerType_Node)
    5558             :     {
    5559          58 :         VSIFPrintfL(pF, LineReturn);
    5560          58 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5561             :                     szMMNomCampArcsANodeDefecte);
    5562          58 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5563          58 :         MMWrite_ANSI_MetadataKeyDescriptor(
    5564             :             hMMMD, pF, szNumberOfArcsToNodeEng, szNumberOfArcsToNodeCat,
    5565             :             szNumberOfArcsToNodeSpa, CPL_ENC_ISO8859_1);
    5566             : 
    5567          58 :         VSIFPrintfL(pF, LineReturn);
    5568          58 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5569             :                     szMMNomCampTipusNodeDefecte);
    5570          58 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5571          58 :         MMWrite_ANSI_MetadataKeyDescriptor(hMMMD, pF, szNodeTypeEng,
    5572             :                                            szNodeTypeCat, szNodeTypeSpa,
    5573             :                                            CPL_ENC_ISO8859_1);
    5574             : 
    5575          58 :         VSIFPrintfL(pF, LineReturn);
    5576          58 :         VSIFPrintfL(pF, "[GEOMETRIA_I_TOPOLOGIA]" LineReturn);
    5577          58 :         VSIFPrintfL(pF, "NomCampArcsANode=%s" LineReturn,
    5578             :                     szMMNomCampArcsANodeDefecte);
    5579          58 :         VSIFPrintfL(pF, "NomCampTipusNode=%s" LineReturn,
    5580             :                     szMMNomCampTipusNodeDefecte);
    5581             :     }
    5582          61 :     else if (hMMMD->ePlainLT == MM_LayerType_Pol)
    5583             :     {
    5584          27 :         VSIFPrintfL(pF, LineReturn);
    5585          27 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5586             :                     szMMNomCampNVertexsDefecte);
    5587          27 :         VSIFPrintfL(pF, "visible=0" LineReturn);
    5588          27 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5589          27 :         MMWrite_ANSI_MetadataKeyDescriptor(
    5590             :             hMMMD, pF, szNumberOfVerticesEng, szNumberOfVerticesCat,
    5591             :             szNumberOfVerticesSpa, CPL_ENC_ISO8859_1);
    5592             : 
    5593          27 :         VSIFPrintfL(pF, LineReturn);
    5594          27 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5595             :                     szMMNomCampPerimetreDefecte);
    5596          27 :         MMWrite_ANSI_MetadataKeyDescriptor(
    5597             :             hMMMD, pF, szPerimeterOfThePolygonEng, szPerimeterOfThePolygonCat,
    5598             :             szPerimeterOfThePolygonSpa, CPL_ENC_ISO8859_1);
    5599             : 
    5600          27 :         VSIFPrintfL(pF, LineReturn);
    5601          27 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5602             :                     szMMNomCampAreaDefecte);
    5603          27 :         MMWrite_ANSI_MetadataKeyDescriptor(
    5604             :             hMMMD, pF, szAreaOfThePolygonEng, szAreaOfThePolygonCat,
    5605             :             szAreaOfThePolygonSpa, CPL_ENC_ISO8859_1);
    5606             : 
    5607          27 :         VSIFPrintfL(pF, LineReturn);
    5608          27 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5609             :                     szMMNomCampNArcsDefecte);
    5610          27 :         VSIFPrintfL(pF, "visible=0" LineReturn);
    5611          27 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5612          27 :         MMWrite_ANSI_MetadataKeyDescriptor(hMMMD, pF, szNumberOfArcsEng,
    5613             :                                            szNumberOfArcsCat, szNumberOfArcsSpa,
    5614             :                                            CPL_ENC_ISO8859_1);
    5615             : 
    5616          27 :         VSIFPrintfL(pF, LineReturn);
    5617          27 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5618             :                     szMMNomCampNPoligonsDefecte);
    5619          27 :         VSIFPrintfL(pF, "visible=0" LineReturn);
    5620          27 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5621          27 :         MMWrite_ANSI_MetadataKeyDescriptor(
    5622             :             hMMMD, pF, szNumberOfElementaryPolygonsEng,
    5623             :             szNumberOfElementaryPolygonsCat, szNumberOfElementaryPolygonsSpa,
    5624             :             CPL_ENC_ISO8859_1);
    5625             : 
    5626          27 :         VSIFPrintfL(pF, LineReturn);
    5627          27 :         VSIFPrintfL(pF, "[GEOMETRIA_I_TOPOLOGIA]" LineReturn);
    5628          27 :         VSIFPrintfL(pF, "NomCampNVertexs=%s" LineReturn,
    5629             :                     szMMNomCampNVertexsDefecte);
    5630          27 :         VSIFPrintfL(pF, "NomCampPerimetre=%s" LineReturn,
    5631             :                     szMMNomCampPerimetreDefecte);
    5632          27 :         VSIFPrintfL(pF, "NomCampArea=%s" LineReturn, szMMNomCampAreaDefecte);
    5633          27 :         VSIFPrintfL(pF, "NomCampNArcs=%s" LineReturn, szMMNomCampNArcsDefecte);
    5634          27 :         VSIFPrintfL(pF, "NomCampNPoligons=%s" LineReturn,
    5635             :                     szMMNomCampNPoligonsDefecte);
    5636             :     }
    5637             : 
    5638         177 :     if (hMMMD->pLayerDB && hMMMD->pLayerDB->nNFields > 0)
    5639             :     {
    5640             :         // For each field of the databes
    5641         586 :         for (nIField = 0; nIField < hMMMD->pLayerDB->nNFields; nIField++)
    5642             :         {
    5643         495 :             VSIFPrintfL(pF, LineReturn "[%s:%s]" LineReturn,
    5644             :                         SECTION_TAULA_PRINCIPAL,
    5645         495 :                         hMMMD->pLayerDB->pFields[nIField].pszFieldName);
    5646             : 
    5647         495 :             if (!MMIsEmptyString(
    5648         594 :                     hMMMD->pLayerDB->pFields[nIField].pszFieldDescription) &&
    5649          99 :                 !MMIsEmptyString(
    5650          99 :                     hMMMD->pLayerDB->pFields[nIField].pszFieldName))
    5651             :             {
    5652          99 :                 MMWrite_ANSI_MetadataKeyDescriptor(
    5653             :                     hMMMD, pF,
    5654          99 :                     hMMMD->pLayerDB->pFields[nIField].pszFieldDescription,
    5655          99 :                     hMMMD->pLayerDB->pFields[nIField].pszFieldDescription,
    5656          99 :                     hMMMD->pLayerDB->pFields[nIField].pszFieldDescription,
    5657             :                     CPL_ENC_UTF8);
    5658             :             }
    5659             : 
    5660             :             // Exception in a particular case: "altura" is a catalan word that means
    5661             :             // "height". Its unit by default will be "m" instead of "unknown".
    5662             :             // The same goes for "z", which easily means height.
    5663         495 :             if (EQUAL("altura",
    5664         495 :                       hMMMD->pLayerDB->pFields[nIField].pszFieldName) ||
    5665         495 :                 EQUAL("z", hMMMD->pLayerDB->pFields[nIField].pszFieldName))
    5666             :             {
    5667           0 :                 VSIFPrintfL(pF, "unitats=m" LineReturn);
    5668             :             }
    5669             :             else
    5670             :             {
    5671             :                 // By default units of field values will not be shown.
    5672         495 :                 VSIFPrintfL(pF, "MostrarUnitats=0" LineReturn);
    5673             :             }
    5674             :         }
    5675             :     }
    5676         177 :     VSIFCloseL(pF);
    5677         177 :     return 0;
    5678             : }
    5679             : 
    5680             : // Writes metadata files for MiraMon vector layers
    5681         194 : static int MMWriteVectorMetadataFile(struct MiraMonVectLayerInfo *hMiraMonLayer,
    5682             :                                      int layerPlainType, int layerMainPlainType)
    5683             : {
    5684             :     struct MiraMonVectorMetaData hMMMD;
    5685             : 
    5686         194 :     if (!hMiraMonLayer)
    5687           0 :         return 1;
    5688             : 
    5689             :     // MiraMon writes a REL file of each .pnt, .arc, .nod or .pol
    5690         194 :     memset(&hMMMD, 0, sizeof(hMMMD));
    5691         194 :     hMMMD.ePlainLT = layerPlainType;
    5692         194 :     hMMMD.pSRS = hMiraMonLayer->pSRS;
    5693         194 :     hMMMD.pZUnit = hMiraMonLayer->pZUnit;
    5694         194 :     hMMMD.nMMLanguage = hMiraMonLayer->nMMLanguage;
    5695             : 
    5696         194 :     hMMMD.szLayerTitle = hMiraMonLayer->szLayerTitle;
    5697         194 :     if (layerPlainType == MM_LayerType_Point)
    5698             :     {
    5699          34 :         hMMMD.aLayerName = hMiraMonLayer->MMPoint.pszREL_LayerName;
    5700          34 :         if (MMIsEmptyString(hMMMD.aLayerName))
    5701           0 :             return 0;  // If no file, no error. Just continue.
    5702          34 :         memcpy(&hMMMD.hBB, &hMiraMonLayer->TopHeader.hBB, sizeof(hMMMD.hBB));
    5703          34 :         hMMMD.pLayerDB = hMiraMonLayer->pLayerDB;
    5704          34 :         return MMWriteMetadataFile(&hMMMD);
    5705             :     }
    5706         160 :     else if (layerPlainType == MM_LayerType_Arc)
    5707             :     {
    5708             :         int nResult;
    5709             : 
    5710             :         // Arcs and not polygons
    5711          58 :         if (layerMainPlainType == MM_LayerType_Arc)
    5712             :         {
    5713          31 :             hMMMD.aLayerName = hMiraMonLayer->MMArc.pszREL_LayerName;
    5714          31 :             if (MMIsEmptyString(hMMMD.aLayerName))
    5715           0 :                 return 0;  // If no file, no error. Just continue.
    5716          31 :             memcpy(&hMMMD.hBB, &hMiraMonLayer->TopHeader.hBB,
    5717             :                    sizeof(hMMMD.hBB));
    5718          31 :             hMMMD.pLayerDB = hMiraMonLayer->pLayerDB;
    5719             :         }
    5720             :         // Arcs and polygons
    5721             :         else
    5722             :         {
    5723             :             // Arc from polygon
    5724          27 :             hMMMD.aLayerName = hMiraMonLayer->MMPolygon.MMArc.pszREL_LayerName;
    5725          27 :             if (MMIsEmptyString(hMMMD.aLayerName))
    5726           0 :                 return 0;  // If no file, no error. Just continue.
    5727             : 
    5728          27 :             memcpy(&hMMMD.hBB, &hMiraMonLayer->MMPolygon.TopArcHeader.hBB,
    5729             :                    sizeof(hMMMD.hBB));
    5730          27 :             hMMMD.pLayerDB = nullptr;
    5731          27 :             hMMMD.aArcFile = CPLStrdup(
    5732          27 :                 CPLGetFilename(hMiraMonLayer->MMPolygon.pszLayerName));
    5733             :         }
    5734          58 :         nResult = MMWriteMetadataFile(&hMMMD);
    5735          58 :         VSIFree(hMMMD.aArcFile);
    5736          58 :         return nResult;
    5737             :     }
    5738         102 :     else if (layerPlainType == MM_LayerType_Pol)
    5739             :     {
    5740             :         int nResult;
    5741             : 
    5742          27 :         hMMMD.aLayerName = hMiraMonLayer->MMPolygon.pszREL_LayerName;
    5743             : 
    5744          27 :         if (MMIsEmptyString(hMMMD.aLayerName))
    5745           0 :             return 0;  // If no file, no error. Just continue.
    5746             : 
    5747          27 :         memcpy(&hMMMD.hBB, &hMiraMonLayer->TopHeader.hBB, sizeof(hMMMD.hBB));
    5748          27 :         hMMMD.pLayerDB = hMiraMonLayer->pLayerDB;
    5749          27 :         hMMMD.aArcFile = CPLStrdup(
    5750          27 :             CPLGetFilename(hMiraMonLayer->MMPolygon.MMArc.pszLayerName));
    5751          27 :         nResult = MMWriteMetadataFile(&hMMMD);
    5752          27 :         VSIFree(hMMMD.aArcFile);
    5753          27 :         return nResult;
    5754             :     }
    5755          75 :     else if (layerPlainType == MM_LayerType_Node)
    5756             :     {
    5757             :         // Node from arc
    5758          58 :         if (layerMainPlainType == MM_LayerType_Arc)
    5759             :         {
    5760          31 :             hMMMD.aLayerName = hMiraMonLayer->MMArc.MMNode.pszREL_LayerName;
    5761          31 :             if (MMIsEmptyString(hMMMD.aLayerName))
    5762           0 :                 return 0;  // If no file, no error. Just continue.
    5763          31 :             memcpy(&hMMMD.hBB, &hMiraMonLayer->MMArc.TopNodeHeader.hBB,
    5764             :                    sizeof(hMMMD.hBB));
    5765             :         }
    5766             :         else  // Node from polygon
    5767             :         {
    5768          27 :             hMMMD.aLayerName =
    5769          27 :                 hMiraMonLayer->MMPolygon.MMArc.MMNode.pszREL_LayerName;
    5770          27 :             if (MMIsEmptyString(hMMMD.aLayerName))
    5771           0 :                 return 0;  // If no file, no error. Just continue.
    5772          27 :             memcpy(&hMMMD.hBB,
    5773          27 :                    &hMiraMonLayer->MMPolygon.MMArc.TopNodeHeader.hBB,
    5774             :                    sizeof(hMMMD.hBB));
    5775             :         }
    5776          58 :         hMMMD.pLayerDB = nullptr;
    5777          58 :         return MMWriteMetadataFile(&hMMMD);
    5778             :     }
    5779          17 :     return 0;
    5780             : }
    5781             : 
    5782         109 : int MMWriteVectorMetadata(struct MiraMonVectLayerInfo *hMiraMonLayer)
    5783             : {
    5784         109 :     if (!hMiraMonLayer)
    5785           0 :         return 1;
    5786             : 
    5787         109 :     if (hMiraMonLayer->bIsPoint)
    5788          34 :         return MMWriteVectorMetadataFile(hMiraMonLayer, MM_LayerType_Point,
    5789             :                                          MM_LayerType_Point);
    5790          75 :     if (hMiraMonLayer->bIsArc && !hMiraMonLayer->bIsPolygon)
    5791             :     {
    5792          31 :         if (MMWriteVectorMetadataFile(hMiraMonLayer, MM_LayerType_Node,
    5793             :                                       MM_LayerType_Arc))
    5794           0 :             return 1;
    5795          31 :         return MMWriteVectorMetadataFile(hMiraMonLayer, MM_LayerType_Arc,
    5796             :                                          MM_LayerType_Arc);
    5797             :     }
    5798          44 :     if (hMiraMonLayer->bIsPolygon)
    5799             :     {
    5800          27 :         if (MMWriteVectorMetadataFile(hMiraMonLayer, MM_LayerType_Node,
    5801             :                                       MM_LayerType_Pol))
    5802           0 :             return 1;
    5803          27 :         if (MMWriteVectorMetadataFile(hMiraMonLayer, MM_LayerType_Arc,
    5804             :                                       MM_LayerType_Pol))
    5805           0 :             return 1;
    5806          27 :         return MMWriteVectorMetadataFile(hMiraMonLayer, MM_LayerType_Pol,
    5807             :                                          MM_LayerType_Pol);
    5808             :     }
    5809          17 :     if (hMiraMonLayer->bIsDBF)
    5810             :     {
    5811          17 :         return MMWriteVectorMetadataFile(hMiraMonLayer, MM_LayerType_Unknown,
    5812             :                                          MM_LayerType_Unknown);
    5813             :     }
    5814           0 :     return 0;
    5815             : }
    5816             : 
    5817             : /* -------------------------------------------------------------------- */
    5818             : /*      MiraMon database functions                                      */
    5819             : /* -------------------------------------------------------------------- */
    5820             : 
    5821             : // Initializes a MiraMon database associated with a vector layer:
    5822             : // Sets the usual fields that MiraMon needs and after them, adds
    5823             : // all fields of the input layer
    5824         194 : static int MMInitMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    5825             :                       struct MMAdmDatabase *pMMAdmDB)
    5826             : {
    5827         194 :     if (!hMiraMonLayer || !pMMAdmDB)
    5828           0 :         return 1;
    5829             : 
    5830         194 :     if (MMIsEmptyString(pMMAdmDB->pszExtDBFLayerName))
    5831           0 :         return 0;  // No file, no error. Just continue
    5832             : 
    5833         194 :     strcpy(pMMAdmDB->pMMBDXP->ReadingMode, "wb+");
    5834         194 :     if (FALSE == MM_CreateAndOpenDBFFile(pMMAdmDB->pMMBDXP,
    5835         194 :                                          pMMAdmDB->pszExtDBFLayerName))
    5836             :     {
    5837           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
    5838             :                  "Error pMMAdmDB: Cannot create or open file %s.",
    5839           0 :                  pMMAdmDB->pszExtDBFLayerName);
    5840           0 :         return 1;
    5841             :     }
    5842             : 
    5843         194 :     VSIFSeekL(pMMAdmDB->pMMBDXP->pfDataBase,
    5844         194 :               pMMAdmDB->pMMBDXP->FirstRecordOffset, SEEK_SET);
    5845             : 
    5846         194 :     if (MMInitFlush(&pMMAdmDB->FlushRecList, pMMAdmDB->pMMBDXP->pfDataBase,
    5847             :                     MM_1MB, &pMMAdmDB->pRecList,
    5848         194 :                     pMMAdmDB->pMMBDXP->FirstRecordOffset, 0))
    5849           0 :         return 1;
    5850             : 
    5851         194 :     pMMAdmDB->nNumRecordOnCourse =
    5852         194 :         (GUInt64)pMMAdmDB->pMMBDXP->BytesPerRecord + 1;
    5853         194 :     if (MMCheckSize_t(pMMAdmDB->nNumRecordOnCourse, 1))
    5854           0 :         return 1;
    5855         194 :     pMMAdmDB->szRecordOnCourse =
    5856         194 :         VSICalloc(1, (size_t)pMMAdmDB->nNumRecordOnCourse);
    5857         194 :     if (!pMMAdmDB->szRecordOnCourse)
    5858             :     {
    5859           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    5860             :                  "Memory error in MiraMon "
    5861             :                  "driver (MMInitMMDB())");
    5862           0 :         return 1;
    5863             :     }
    5864         194 :     return 0;
    5865             : }
    5866             : 
    5867             : // Creates a MiraMon database associated with a vector layer.
    5868             : // It determines the number of fields and initializes the database header
    5869             : // accordingly. Depending on the layer type (point, arc, polygon, or generic),
    5870             : // it defines the fields and initializes the corresponding MiraMon database
    5871             : // structures.
    5872         109 : int MMCreateMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    5873             :                  struct MM_POINT_2D *pFirstCoord)
    5874             : {
    5875         109 :     struct MM_DATA_BASE_XP *pBD_XP = nullptr, *pBD_XP_Aux = nullptr;
    5876             :     struct MM_FIELD MMField;
    5877             :     size_t nIFieldLayer;
    5878         109 :     MM_EXT_DBF_N_FIELDS nIField = 0;
    5879             :     MM_EXT_DBF_N_FIELDS nNFields;
    5880             : 
    5881         109 :     if (!hMiraMonLayer)
    5882           0 :         return 1;
    5883             : 
    5884             :     // If the SRS is unknown, we attempt to deduce the appropriate number
    5885             :     // of decimals to be used in the reserved fields as LONG_ARC, PERIMETRE,
    5886             :     // or AREA using the coordinate values. It's not 100% reliable, but it's a
    5887             :     // good approximation.
    5888         109 :     if (hMiraMonLayer->nSRSType == MM_SRS_LAYER_IS_UNKNOWN_TYPE && pFirstCoord)
    5889             :     {
    5890          71 :         if (pFirstCoord->dfX < -360 || pFirstCoord->dfX > 360)
    5891           8 :             hMiraMonLayer->nSRSType = MM_SRS_LAYER_IS_PROJECTED_TYPE;
    5892             :         else
    5893          63 :             hMiraMonLayer->nSRSType = MM_SRS_LAYER_IS_GEOGRAPHIC_TYPE;
    5894             :     }
    5895             : 
    5896         109 :     if (hMiraMonLayer->bIsPoint)
    5897             :     {
    5898          34 :         if (hMiraMonLayer->pLayerDB)
    5899          34 :             nNFields =
    5900          34 :                 MM_PRIVATE_POINT_DB_FIELDS + hMiraMonLayer->pLayerDB->nNFields;
    5901             :         else
    5902           0 :             nNFields = MM_PRIVATE_POINT_DB_FIELDS;
    5903             : 
    5904             :         // Before allocating new memory, there might be some previously allocated but unused memory.
    5905             :         // Let's free that memory first.
    5906          34 :         if (hMiraMonLayer->MMPoint.MMAdmDB.pMMBDXP)
    5907           0 :             MM_ReleaseDBFHeader(&hMiraMonLayer->MMPoint.MMAdmDB.pMMBDXP);
    5908             : 
    5909          34 :         pBD_XP = hMiraMonLayer->MMPoint.MMAdmDB.pMMBDXP =
    5910          34 :             MM_CreateDBFHeader(nNFields, hMiraMonLayer->nCharSet);
    5911             : 
    5912          34 :         if (!pBD_XP)
    5913           0 :             return 1;
    5914             : 
    5915          34 :         if (0 == (nIField = (MM_EXT_DBF_N_FIELDS)MM_DefineFirstPointFieldsDB_XP(
    5916             :                       pBD_XP)))
    5917           0 :             return 1;
    5918             :     }
    5919          75 :     else if (hMiraMonLayer->bIsArc && !hMiraMonLayer->bIsPolygon)
    5920             :     {
    5921          31 :         if (hMiraMonLayer->pLayerDB)
    5922          30 :             nNFields =
    5923          30 :                 MM_PRIVATE_ARC_DB_FIELDS + hMiraMonLayer->pLayerDB->nNFields;
    5924             :         else
    5925           1 :             nNFields = MM_PRIVATE_ARC_DB_FIELDS;
    5926             : 
    5927             :         // Before allocating new memory, there might be some previously allocated but unused memory.
    5928             :         // Let's free that memory first.
    5929          31 :         if (hMiraMonLayer->MMArc.MMAdmDB.pMMBDXP)
    5930           0 :             MM_ReleaseDBFHeader(&hMiraMonLayer->MMArc.MMAdmDB.pMMBDXP);
    5931             : 
    5932          31 :         pBD_XP = hMiraMonLayer->MMArc.MMAdmDB.pMMBDXP =
    5933          31 :             MM_CreateDBFHeader(nNFields, hMiraMonLayer->nCharSet);
    5934             : 
    5935          31 :         if (!pBD_XP)
    5936           0 :             return 1;
    5937             : 
    5938          31 :         if (0 == (nIField = (MM_EXT_DBF_N_FIELDS)MM_DefineFirstArcFieldsDB_XP(
    5939             :                       pBD_XP,
    5940          31 :                       hMiraMonLayer->nSRSType == MM_SRS_LAYER_IS_PROJECTED_TYPE
    5941             :                           ? 3
    5942             :                           : 9)))
    5943           0 :             return 1;
    5944             : 
    5945             :         // Before allocating new memory, there might be some previously allocated but unused memory.
    5946             :         // Let's free that memory first.
    5947          31 :         if (hMiraMonLayer->MMArc.MMNode.MMAdmDB.pMMBDXP)
    5948           0 :             MM_ReleaseDBFHeader(&hMiraMonLayer->MMArc.MMNode.MMAdmDB.pMMBDXP);
    5949             : 
    5950          31 :         pBD_XP_Aux = hMiraMonLayer->MMArc.MMNode.MMAdmDB.pMMBDXP =
    5951          31 :             MM_CreateDBFHeader(3, hMiraMonLayer->nCharSet);
    5952             : 
    5953          31 :         if (!pBD_XP_Aux)
    5954           0 :             return 1;
    5955             : 
    5956          31 :         if (0 == MM_DefineFirstNodeFieldsDB_XP(pBD_XP_Aux))
    5957           0 :             return 1;
    5958             :     }
    5959          44 :     else if (hMiraMonLayer->bIsPolygon)
    5960             :     {
    5961          27 :         if (hMiraMonLayer->pLayerDB)
    5962          27 :             nNFields = MM_PRIVATE_POLYGON_DB_FIELDS +
    5963          27 :                        hMiraMonLayer->pLayerDB->nNFields;
    5964             :         else
    5965           0 :             nNFields = MM_PRIVATE_POLYGON_DB_FIELDS;
    5966             : 
    5967             :         // Before allocating new memory, there might be some previously allocated but unused memory.
    5968             :         // Let's free that memory first.
    5969          27 :         if (hMiraMonLayer->MMPolygon.MMAdmDB.pMMBDXP)
    5970           0 :             MM_ReleaseDBFHeader(&hMiraMonLayer->MMPolygon.MMAdmDB.pMMBDXP);
    5971             : 
    5972          27 :         pBD_XP = hMiraMonLayer->MMPolygon.MMAdmDB.pMMBDXP =
    5973          27 :             MM_CreateDBFHeader(nNFields, hMiraMonLayer->nCharSet);
    5974             : 
    5975          27 :         if (!pBD_XP)
    5976           0 :             return 1;
    5977             : 
    5978          27 :         if (0 ==
    5979          54 :             (nIField = (MM_EXT_DBF_N_FIELDS)MM_DefineFirstPolygonFieldsDB_XP(
    5980             :                  pBD_XP,
    5981          27 :                  hMiraMonLayer->nSRSType == MM_SRS_LAYER_IS_PROJECTED_TYPE ? 3
    5982             :                                                                            : 9,
    5983          27 :                  hMiraMonLayer->nSRSType == MM_SRS_LAYER_IS_PROJECTED_TYPE
    5984             :                      ? 3
    5985             :                      : 12)))
    5986           0 :             return 1;
    5987             : 
    5988             :         // Before allocating new memory, there might be some previously allocated but unused memory.
    5989             :         // Let's free that memory first.
    5990          27 :         if (hMiraMonLayer->MMPolygon.MMArc.MMAdmDB.pMMBDXP)
    5991           0 :             MM_ReleaseDBFHeader(
    5992             :                 &hMiraMonLayer->MMPolygon.MMArc.MMAdmDB.pMMBDXP);
    5993             : 
    5994          27 :         pBD_XP_Aux = hMiraMonLayer->MMPolygon.MMArc.MMAdmDB.pMMBDXP =
    5995          27 :             MM_CreateDBFHeader(5, hMiraMonLayer->nCharSet);
    5996             : 
    5997          27 :         if (!pBD_XP_Aux)
    5998           0 :             return 1;
    5999             : 
    6000          27 :         if (0 == MM_DefineFirstArcFieldsDB_XP(
    6001             :                      pBD_XP_Aux,
    6002          27 :                      hMiraMonLayer->nSRSType == MM_SRS_LAYER_IS_PROJECTED_TYPE
    6003             :                          ? 3
    6004             :                          : 9))
    6005           0 :             return 1;
    6006             : 
    6007             :         // Before allocating new memory, there might be some previously allocated but unused memory.
    6008             :         // Let's free that memory first.
    6009          27 :         if (hMiraMonLayer->MMPolygon.MMArc.MMNode.MMAdmDB.pMMBDXP)
    6010           0 :             MM_ReleaseDBFHeader(
    6011             :                 &hMiraMonLayer->MMPolygon.MMArc.MMNode.MMAdmDB.pMMBDXP);
    6012             : 
    6013          27 :         pBD_XP_Aux = hMiraMonLayer->MMPolygon.MMArc.MMNode.MMAdmDB.pMMBDXP =
    6014          27 :             MM_CreateDBFHeader(3, hMiraMonLayer->nCharSet);
    6015             : 
    6016          27 :         if (!pBD_XP_Aux)
    6017           0 :             return 1;
    6018             : 
    6019          27 :         if (0 == MM_DefineFirstNodeFieldsDB_XP(pBD_XP_Aux))
    6020           0 :             return 1;
    6021             :     }
    6022          17 :     else if (hMiraMonLayer->bIsDBF)
    6023             :     {
    6024             :         // Creating only a DBF
    6025          17 :         if (hMiraMonLayer->pLayerDB)
    6026          17 :             nNFields = hMiraMonLayer->pLayerDB->nNFields;
    6027             :         else
    6028           0 :             nNFields = 0;
    6029             : 
    6030          17 :         pBD_XP = hMiraMonLayer->MMAdmDBWriting.pMMBDXP =
    6031          17 :             MM_CreateDBFHeader(nNFields, hMiraMonLayer->nCharSet);
    6032             : 
    6033          17 :         if (!pBD_XP)
    6034           0 :             return 1;
    6035             :     }
    6036             :     else
    6037           0 :         return 0;
    6038             : 
    6039             :     // After private MiraMon fields, other fields are added.
    6040             :     // If names are no compatible, some changes are done.
    6041         109 :     if (hMiraMonLayer->pLayerDB)
    6042             :     {
    6043         684 :         for (nIFieldLayer = 0; nIField < nNFields; nIField++, nIFieldLayer++)
    6044             :         {
    6045         576 :             MM_InitializeField(&MMField);
    6046         576 :             CPLStrlcpy(
    6047             :                 MMField.FieldName,
    6048         576 :                 hMiraMonLayer->pLayerDB->pFields[nIFieldLayer].pszFieldName,
    6049             :                 MM_MAX_LON_FIELD_NAME_DBF);
    6050             : 
    6051         576 :             CPLStrlcpy(MMField.FieldDescription[0],
    6052         576 :                        hMiraMonLayer->pLayerDB->pFields[nIFieldLayer]
    6053         576 :                            .pszFieldDescription,
    6054             :                        MM_MAX_BYTES_FIELD_DESC);
    6055             : 
    6056         576 :             MMField.BytesPerField =
    6057         576 :                 hMiraMonLayer->pLayerDB->pFields[nIFieldLayer].nFieldSize;
    6058         576 :             switch (hMiraMonLayer->pLayerDB->pFields[nIFieldLayer].eFieldType)
    6059             :             {
    6060         283 :                 case MM_Numeric:
    6061         283 :                     MMField.FieldType = 'N';
    6062         283 :                     if (hMiraMonLayer->pLayerDB->pFields[nIFieldLayer]
    6063         283 :                             .bIs64BitInteger)
    6064          79 :                         MMField.Is64 = 1;
    6065         283 :                     if (MMField.BytesPerField == 0)
    6066           0 :                         MMField.BytesPerField = MM_MAX_AMPLADA_CAMP_N_DBF;
    6067         283 :                     break;
    6068         192 :                 case MM_Character:
    6069         192 :                     MMField.FieldType = 'C';
    6070         192 :                     if (MMField.BytesPerField == 0)
    6071           0 :                         MMField.BytesPerField = MM_MAX_AMPLADA_CAMP_C_DBF;
    6072         192 :                     break;
    6073          68 :                 case MM_Data:
    6074          68 :                     MMField.FieldType = 'D';
    6075          68 :                     if (MMField.BytesPerField == 0)
    6076           0 :                         MMField.BytesPerField = MM_MAX_AMPLADA_CAMP_D_DBF;
    6077          68 :                     break;
    6078          33 :                 case MM_Logic:
    6079          33 :                     MMField.FieldType = 'L';
    6080          33 :                     if (MMField.BytesPerField == 0)
    6081           0 :                         MMField.BytesPerField = 1;
    6082          33 :                     break;
    6083           0 :                 default:
    6084           0 :                     MMField.FieldType = 'C';
    6085           0 :                     if (MMField.BytesPerField == 0)
    6086           0 :                         MMField.BytesPerField = MM_MAX_AMPLADA_CAMP_C_DBF;
    6087             :             };
    6088             : 
    6089         576 :             MMField.DecimalsIfFloat =
    6090         576 :                 (MM_BYTE)hMiraMonLayer->pLayerDB->pFields[nIFieldLayer]
    6091         576 :                     .nNumberOfDecimals;
    6092             : 
    6093         576 :             MM_DuplicateFieldDBXP(pBD_XP->pField + nIField, &MMField);
    6094         576 :             MM_ModifyFieldNameAndDescriptorIfPresentBD_XP(
    6095         576 :                 pBD_XP->pField + nIField, pBD_XP, FALSE, 0);
    6096         576 :             if (pBD_XP->pField[nIField].FieldType == 'F')
    6097           0 :                 pBD_XP->pField[nIField].FieldType = 'N';
    6098             :         }
    6099             :     }
    6100             : 
    6101         109 :     if (hMiraMonLayer->bIsPoint)
    6102             :     {
    6103          34 :         if (MMInitMMDB(hMiraMonLayer, &hMiraMonLayer->MMPoint.MMAdmDB))
    6104           0 :             return 1;
    6105             :     }
    6106          75 :     else if (hMiraMonLayer->bIsArc && !hMiraMonLayer->bIsPolygon)
    6107             :     {
    6108          31 :         if (MMInitMMDB(hMiraMonLayer, &hMiraMonLayer->MMArc.MMAdmDB))
    6109           0 :             return 1;
    6110             : 
    6111          31 :         if (MMInitMMDB(hMiraMonLayer, &hMiraMonLayer->MMArc.MMNode.MMAdmDB))
    6112           0 :             return 1;
    6113             :     }
    6114          44 :     else if (hMiraMonLayer->bIsPolygon)
    6115             :     {
    6116          27 :         if (MMInitMMDB(hMiraMonLayer, &hMiraMonLayer->MMPolygon.MMAdmDB))
    6117           0 :             return 1;
    6118             : 
    6119          27 :         if (MMInitMMDB(hMiraMonLayer, &hMiraMonLayer->MMPolygon.MMArc.MMAdmDB))
    6120           0 :             return 1;
    6121             : 
    6122          27 :         if (MMInitMMDB(hMiraMonLayer,
    6123             :                        &hMiraMonLayer->MMPolygon.MMArc.MMNode.MMAdmDB))
    6124           0 :             return 1;
    6125             :     }
    6126          17 :     else if (hMiraMonLayer->bIsDBF)
    6127             :     {
    6128          17 :         if (MMInitMMDB(hMiraMonLayer, &hMiraMonLayer->MMAdmDBWriting))
    6129           0 :             return 1;
    6130             :     }
    6131         109 :     return 0;
    6132             : }
    6133             : 
    6134             : // Checks and fits the width of a specific field in a MiraMon database
    6135             : // associated with a vector layer. It examines the length of the provided
    6136             : // value and resizes the field width, if necessary, to accommodate the new
    6137             : // value. If the new width exceeds the current width of the field,
    6138             : // it updates the database structure, including the field width and
    6139             : // the size of the record. Additionally, it reallocates memory if needed
    6140             : // for the record handling buffer.
    6141             : 
    6142             : static int
    6143        2977 : MMTestAndFixValueToRecordDBXP(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6144             :                               struct MMAdmDatabase *pMMAdmDB,
    6145             :                               MM_EXT_DBF_N_FIELDS nIField, char *szValue)
    6146             : {
    6147             :     struct MM_FIELD *camp;
    6148             :     MM_BYTES_PER_FIELD_TYPE_DBF nNewWidth;
    6149             : 
    6150        2977 :     if (!hMiraMonLayer || !pMMAdmDB || !pMMAdmDB->pMMBDXP ||
    6151        2977 :         !pMMAdmDB->pMMBDXP->pField || !pMMAdmDB->pMMBDXP->pfDataBase)
    6152           0 :         return 1;
    6153             : 
    6154        2977 :     camp = pMMAdmDB->pMMBDXP->pField + nIField;
    6155             : 
    6156        2977 :     if (!szValue)
    6157         282 :         return 0;
    6158             : 
    6159        2695 :     nNewWidth = (MM_BYTES_PER_FIELD_TYPE_DBF)strlen(szValue);
    6160        2695 :     if (MMResizeStringToOperateIfNeeded(hMiraMonLayer, nNewWidth + 1))
    6161           0 :         return 1;
    6162             : 
    6163        2695 :     if (nNewWidth > camp->BytesPerField)
    6164             :     {
    6165         117 :         if (MM_WriteNRecordsMMBD_XPFile(pMMAdmDB))
    6166           0 :             return 1;
    6167             : 
    6168             :         // Flushing all to be flushed
    6169         117 :         pMMAdmDB->FlushRecList.SizeOfBlockToBeSaved = 0;
    6170         117 :         if (MMAppendBlockToBuffer(&pMMAdmDB->FlushRecList))
    6171           0 :             return 1;
    6172             : 
    6173         117 :         if (MM_ChangeDBFWidthField(
    6174             :                 pMMAdmDB->pMMBDXP, nIField, nNewWidth,
    6175         117 :                 pMMAdmDB->pMMBDXP->pField[nIField].DecimalsIfFloat))
    6176           0 :             return 1;
    6177             : 
    6178             :         // The record on course also has to change its size.
    6179         117 :         if ((GUInt64)pMMAdmDB->pMMBDXP->BytesPerRecord + 1 >=
    6180         117 :             pMMAdmDB->nNumRecordOnCourse)
    6181             :         {
    6182             :             void *pTmp;
    6183         117 :             if (nullptr == (pTmp = VSIRealloc(
    6184         117 :                                 pMMAdmDB->szRecordOnCourse,
    6185         117 :                                 (size_t)pMMAdmDB->pMMBDXP->BytesPerRecord + 1)))
    6186             :             {
    6187           0 :                 CPLError(CE_Failure, CPLE_OutOfMemory,
    6188             :                          "Memory error in MiraMon "
    6189             :                          "driver (MMTestAndFixValueToRecordDBXP())");
    6190           0 :                 return 1;
    6191             :             }
    6192         117 :             pMMAdmDB->szRecordOnCourse = pTmp;
    6193             :         }
    6194             : 
    6195             :         // File has changed its size, so it has to be updated
    6196             :         // at the Flush tool
    6197         117 :         VSIFSeekL(pMMAdmDB->pMMBDXP->pfDataBase, 0, SEEK_END);
    6198         117 :         pMMAdmDB->FlushRecList.OffsetWhereToFlush =
    6199         117 :             VSIFTellL(pMMAdmDB->pMMBDXP->pfDataBase);
    6200             :     }
    6201        2695 :     return 0;
    6202             : }
    6203             : 
    6204             : static int
    6205        3460 : MMWriteValueToszStringToOperate(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6206             :                                 const struct MM_FIELD *camp, const void *valor,
    6207             :                                 MM_BOOLEAN is_64)
    6208             : {
    6209        3460 :     if (!hMiraMonLayer)
    6210           0 :         return 1;
    6211             : 
    6212        3460 :     if (!camp)
    6213           0 :         return 0;
    6214             : 
    6215        3460 :     if (MMResizeStringToOperateIfNeeded(hMiraMonLayer,
    6216        3460 :                                         camp->BytesPerField + 10))
    6217           0 :         return 1;
    6218             : 
    6219        3460 :     if (!valor)
    6220           0 :         *hMiraMonLayer->szStringToOperate = '\0';
    6221             :     else
    6222             :     {
    6223        3460 :         if (camp->FieldType == 'N')
    6224             :         {
    6225        2862 :             if (!is_64)
    6226             :             {
    6227         972 :                 snprintf(hMiraMonLayer->szStringToOperate,
    6228         972 :                          (size_t)hMiraMonLayer->nNumStringToOperate, "%*.*f",
    6229         972 :                          camp->BytesPerField, camp->DecimalsIfFloat,
    6230             :                          *(const double *)valor);
    6231             :             }
    6232             :             else
    6233             :             {
    6234        1890 :                 snprintf(hMiraMonLayer->szStringToOperate,
    6235        1890 :                          (size_t)hMiraMonLayer->nNumStringToOperate, "%*lld",
    6236             :                          camp->BytesPerField, *(const GInt64 *)valor);
    6237             :             }
    6238             :         }
    6239             :         else
    6240             :         {
    6241         598 :             snprintf(hMiraMonLayer->szStringToOperate,
    6242         598 :                      (size_t)hMiraMonLayer->nNumStringToOperate, "%-*s",
    6243             :                      camp->BytesPerField, (const char *)valor);
    6244             :         }
    6245             :     }
    6246             : 
    6247        3460 :     return 0;
    6248             : }
    6249             : 
    6250         559 : int MMWritePreformatedNumberValueToRecordDBXP(
    6251             :     struct MiraMonVectLayerInfo *hMiraMonLayer, char *registre,
    6252             :     const struct MM_FIELD *camp, const char *valor)
    6253             : {
    6254         559 :     if (!hMiraMonLayer)
    6255           0 :         return 1;
    6256             : 
    6257         559 :     if (!camp)
    6258           0 :         return 0;
    6259             : 
    6260         559 :     if (MMResizeStringToOperateIfNeeded(hMiraMonLayer,
    6261         559 :                                         camp->BytesPerField + 10))
    6262           0 :         return 1;
    6263             : 
    6264         559 :     if (!valor)
    6265           0 :         memset(hMiraMonLayer->szStringToOperate, 0, camp->BytesPerField);
    6266             :     else
    6267             :     {
    6268         559 :         snprintf(hMiraMonLayer->szStringToOperate,
    6269         559 :                  (size_t)hMiraMonLayer->nNumStringToOperate, "%*s",
    6270             :                  camp->BytesPerField, valor);
    6271             :     }
    6272             : 
    6273         559 :     memcpy(registre + camp->AccumulatedBytes, hMiraMonLayer->szStringToOperate,
    6274         559 :            camp->BytesPerField);
    6275         559 :     return 0;
    6276             : }
    6277             : 
    6278        2135 : int MMWriteValueToRecordDBXP(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6279             :                              char *registre, const struct MM_FIELD *camp,
    6280             :                              const void *valor, MM_BOOLEAN is_64)
    6281             : {
    6282        2135 :     if (!hMiraMonLayer)
    6283           0 :         return 1;
    6284             : 
    6285        2135 :     if (!camp)
    6286           0 :         return 0;
    6287             : 
    6288        2135 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, camp, valor, is_64))
    6289           0 :         return 1;
    6290             : 
    6291        2135 :     memcpy(registre + camp->AccumulatedBytes, hMiraMonLayer->szStringToOperate,
    6292        2135 :            camp->BytesPerField);
    6293        2135 :     return 0;
    6294             : }
    6295             : 
    6296         213 : static int MMAddFeatureRecordToMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6297             :                                     struct MiraMonFeature *hMMFeature,
    6298             :                                     struct MMAdmDatabase *pMMAdmDB,
    6299             :                                     char *pszRecordOnCourse,
    6300             :                                     struct MM_FLUSH_INFO *pFlushRecList,
    6301             :                                     MM_EXT_DBF_N_RECORDS *nNumRecords,
    6302             :                                     MM_EXT_DBF_N_FIELDS nNumPrivateMMField)
    6303             : {
    6304             :     MM_EXT_DBF_N_MULTIPLE_RECORDS nIRecord;
    6305             :     MM_EXT_DBF_N_FIELDS nIField;
    6306         213 :     struct MM_DATA_BASE_XP *pBD_XP = nullptr;
    6307             : 
    6308         213 :     if (!hMiraMonLayer)
    6309           0 :         return 1;
    6310             : 
    6311         213 :     if (!hMMFeature)
    6312           0 :         return 1;
    6313             : 
    6314         213 :     pBD_XP = pMMAdmDB->pMMBDXP;
    6315         453 :     for (nIRecord = 0; nIRecord < hMMFeature->nNumMRecords; nIRecord++)
    6316             :     {
    6317        1892 :         for (nIField = 0; nIField < hMMFeature->pRecords[nIRecord].nNumField;
    6318        1652 :              nIField++)
    6319             :         {
    6320             :             // A field with no valid value is written as blank
    6321        1652 :             if (!hMMFeature->pRecords[nIRecord].pField[nIField].bIsValid)
    6322             :             {
    6323         283 :                 memset(
    6324         283 :                     pszRecordOnCourse +
    6325         283 :                         pBD_XP->pField[nIField + nNumPrivateMMField]
    6326         283 :                             .AccumulatedBytes,
    6327             :                     ' ',
    6328         283 :                     pBD_XP->pField[nIField + nNumPrivateMMField].BytesPerField);
    6329             : 
    6330         283 :                 continue;
    6331             :             }
    6332        1369 :             if (pBD_XP->pField[nIField + nNumPrivateMMField].FieldType == 'C' ||
    6333         983 :                 pBD_XP->pField[nIField + nNumPrivateMMField].FieldType == 'L' ||
    6334         880 :                 pBD_XP->pField[nIField + nNumPrivateMMField].FieldType == 'D')
    6335             :             {
    6336         598 :                 if (MMWriteValueToRecordDBXP(hMiraMonLayer, pszRecordOnCourse,
    6337         598 :                                              pBD_XP->pField + nIField +
    6338             :                                                  nNumPrivateMMField,
    6339         598 :                                              hMMFeature->pRecords[nIRecord]
    6340         598 :                                                  .pField[nIField]
    6341         598 :                                                  .pDinValue,
    6342             :                                              FALSE))
    6343           0 :                     return 1;
    6344             :             }
    6345         771 :             else if (pBD_XP->pField[nIField + nNumPrivateMMField].FieldType ==
    6346         771 :                          'N' &&
    6347         771 :                      !pBD_XP->pField[nIField + nNumPrivateMMField].Is64)
    6348             :             {
    6349         559 :                 if (MMWritePreformatedNumberValueToRecordDBXP(
    6350             :                         hMiraMonLayer, pszRecordOnCourse,
    6351         559 :                         pBD_XP->pField + nIField + nNumPrivateMMField,
    6352         559 :                         hMMFeature->pRecords[nIRecord]
    6353         559 :                             .pField[nIField]
    6354         559 :                             .pDinValue))
    6355           0 :                     return 1;
    6356             :             }
    6357         212 :             else if (pBD_XP->pField[nIField + nNumPrivateMMField].FieldType ==
    6358             :                      'N')
    6359             :             {
    6360         212 :                 if (pBD_XP->pField[nIField + nNumPrivateMMField].Is64)
    6361             :                 {
    6362         212 :                     if (MMWriteValueToRecordDBXP(
    6363             :                             hMiraMonLayer, pszRecordOnCourse,
    6364         212 :                             pBD_XP->pField + nIField + nNumPrivateMMField,
    6365         212 :                             &hMMFeature->pRecords[nIRecord]
    6366         212 :                                  .pField[nIField]
    6367             :                                  .iValue,
    6368             :                             TRUE))
    6369           0 :                         return 1;
    6370             :                 }
    6371             :             }
    6372             :         }
    6373             : 
    6374         240 :         if (MMAppendBlockToBuffer(pFlushRecList))
    6375           0 :             return 1;
    6376             : 
    6377         240 :         (*nNumRecords)++;
    6378             :     }
    6379         213 :     return 0;
    6380             : }
    6381             : 
    6382             : // Adds feature records to a MiraMon database associated with a vector layer.
    6383        1652 : static int MMDetectAndFixDBFWidthChange(
    6384             :     struct MiraMonVectLayerInfo *hMiraMonLayer,
    6385             :     struct MiraMonFeature *hMMFeature, struct MMAdmDatabase *pMMAdmDB,
    6386             :     MM_EXT_DBF_N_FIELDS nNumPrivateMMField,
    6387             :     MM_EXT_DBF_N_MULTIPLE_RECORDS nIRecord, MM_EXT_DBF_N_FIELDS nIField)
    6388             : {
    6389        1652 :     if (!hMiraMonLayer)
    6390           0 :         return 1;
    6391             : 
    6392        1652 :     if (!hMMFeature)
    6393           0 :         return 1;
    6394             : 
    6395        1652 :     if (nIRecord >= hMMFeature->nNumMRecords)
    6396           0 :         return 1;
    6397             : 
    6398        1652 :     if (nIField >= hMMFeature->pRecords[nIRecord].nNumField)
    6399           0 :         return 1;
    6400             : 
    6401        1652 :     if (MMTestAndFixValueToRecordDBXP(
    6402             :             hMiraMonLayer, pMMAdmDB, nIField + nNumPrivateMMField,
    6403        1652 :             hMMFeature->pRecords[nIRecord].pField[nIField].pDinValue))
    6404           0 :         return 1;
    6405             : 
    6406             :     // We analyze next fields
    6407        1652 :     if (nIField == hMMFeature->pRecords[nIRecord].nNumField - 1)
    6408             :     {
    6409         239 :         if (nIRecord + 1 < hMMFeature->nNumMRecords)
    6410             :         {
    6411          27 :             if (MMDetectAndFixDBFWidthChange(hMiraMonLayer, hMMFeature,
    6412             :                                              pMMAdmDB, nNumPrivateMMField,
    6413             :                                              nIRecord + 1, 0))
    6414           0 :                 return 1;
    6415             :         }
    6416             :         else
    6417         212 :             return 0;
    6418             :     }
    6419             :     else
    6420             :     {
    6421        1413 :         if (nIField + 1 < hMMFeature->pRecords[nIRecord].nNumField)
    6422             :         {
    6423        1413 :             if (MMDetectAndFixDBFWidthChange(hMiraMonLayer, hMMFeature,
    6424             :                                              pMMAdmDB, nNumPrivateMMField,
    6425             :                                              nIRecord, nIField + 1))
    6426           0 :                 return 1;
    6427             :         }
    6428             :         else
    6429           0 :             return 0;
    6430             :     }
    6431        1440 :     return 0;
    6432             : }  // End of MMDetectAndFixDBFWidthChange()
    6433             : 
    6434             : // Adds a DBF record to a MiraMon table associated with a vector layer.
    6435             : // It sets up flush settings for writing to the table and initializes
    6436             : // variables needed for the process. Then, it checks and fixes the width
    6437             : // change if necessary.
    6438          34 : int MMAddDBFRecordToMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6439             :                          struct MiraMonFeature *hMMFeature)
    6440             : {
    6441          34 :     struct MM_DATA_BASE_XP *pBD_XP = nullptr;
    6442          34 :     MM_EXT_DBF_N_FIELDS nNumPrivateMMField = 0;
    6443             :     struct MM_FLUSH_INFO *pFlushRecList;
    6444             : 
    6445          34 :     if (!hMiraMonLayer)
    6446           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6447             : 
    6448          34 :     pBD_XP = hMiraMonLayer->MMAdmDBWriting.pMMBDXP;
    6449             : 
    6450             :     // Test length
    6451          34 :     if (hMMFeature && hMMFeature->nNumMRecords &&
    6452          34 :         hMMFeature->pRecords[0].nNumField)
    6453             :     {
    6454          34 :         if (MMDetectAndFixDBFWidthChange(hMiraMonLayer, hMMFeature,
    6455             :                                          &hMiraMonLayer->MMAdmDBWriting,
    6456             :                                          nNumPrivateMMField, 0, 0))
    6457           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6458             :     }
    6459             : 
    6460             :     // Adding record to the MiraMon table (extended DBF)
    6461             :     // Flush settings
    6462          34 :     pFlushRecList = &hMiraMonLayer->MMAdmDBWriting.FlushRecList;
    6463          34 :     pFlushRecList->pBlockWhereToSaveOrRead =
    6464          34 :         (void *)hMiraMonLayer->MMAdmDBWriting.pRecList;
    6465             : 
    6466          34 :     pFlushRecList->pBlockToBeSaved =
    6467          34 :         (void *)hMiraMonLayer->MMAdmDBWriting.szRecordOnCourse;
    6468          34 :     pFlushRecList->SizeOfBlockToBeSaved = pBD_XP->BytesPerRecord;
    6469             : 
    6470          34 :     if (MMAddFeatureRecordToMMDB(
    6471             :             hMiraMonLayer, hMMFeature, &hMiraMonLayer->MMAdmDBWriting,
    6472             :             hMiraMonLayer->MMAdmDBWriting.szRecordOnCourse, pFlushRecList,
    6473          34 :             &hMiraMonLayer->MMAdmDBWriting.pMMBDXP->nRecords,
    6474             :             nNumPrivateMMField))
    6475           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6476             : 
    6477             :     // In this case, the number of features is also updated
    6478          34 :     hMiraMonLayer->TopHeader.nElemCount =
    6479          34 :         hMiraMonLayer->MMAdmDBWriting.pMMBDXP->nRecords;
    6480             : 
    6481          34 :     return MM_CONTINUE_WRITING_FEATURES;
    6482             : }
    6483             : 
    6484             : // Adds a point record to a MiraMon table associated with a vector layer.
    6485          89 : int MMAddPointRecordToMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6486             :                            struct MiraMonFeature *hMMFeature,
    6487             :                            MM_INTERNAL_FID nElemCount)
    6488             : {
    6489          89 :     struct MM_DATA_BASE_XP *pBD_XP = nullptr;
    6490          89 :     MM_EXT_DBF_N_FIELDS nNumPrivateMMField = MM_PRIVATE_POINT_DB_FIELDS;
    6491             :     struct MM_FLUSH_INFO *pFlushRecList;
    6492             : 
    6493          89 :     if (!hMiraMonLayer)
    6494           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6495             : 
    6496          89 :     if (!hMMFeature)
    6497           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6498             : 
    6499             :     // In V1.1 only _UI32_MAX records number is allowed
    6500          89 :     if (MMCheckVersionForFID(hMiraMonLayer,
    6501          89 :                              hMiraMonLayer->MMPoint.MMAdmDB.pMMBDXP->nRecords +
    6502          89 :                                  hMMFeature->nNumMRecords))
    6503             :     {
    6504           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    6505             :                  "Error in MMCheckVersionForFID() (6)");
    6506           0 :         return MM_STOP_WRITING_FEATURES;
    6507             :     }
    6508             : 
    6509          89 :     pBD_XP = hMiraMonLayer->MMPoint.MMAdmDB.pMMBDXP;
    6510             : 
    6511             :     // Test length
    6512             :     // Private fields
    6513             :     // ID_GRAFIC
    6514          89 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField,
    6515             :                                         &nElemCount, TRUE))
    6516           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6517          89 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer,
    6518             :                                       &hMiraMonLayer->MMPoint.MMAdmDB, 0,
    6519             :                                       hMiraMonLayer->szStringToOperate))
    6520           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6521             : 
    6522             :     // GDAL fields
    6523          89 :     if (hMMFeature->nNumMRecords && hMMFeature->pRecords[0].nNumField)
    6524             :     {
    6525          89 :         if (MMDetectAndFixDBFWidthChange(hMiraMonLayer, hMMFeature,
    6526             :                                          &hMiraMonLayer->MMPoint.MMAdmDB,
    6527             :                                          nNumPrivateMMField, 0, 0))
    6528           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6529             :     }
    6530             : 
    6531             :     // Now length is sure, write
    6532          89 :     memset(hMiraMonLayer->MMPoint.MMAdmDB.szRecordOnCourse, 0,
    6533          89 :            pBD_XP->BytesPerRecord);
    6534          89 :     MMWriteValueToRecordDBXP(hMiraMonLayer,
    6535             :                              hMiraMonLayer->MMPoint.MMAdmDB.szRecordOnCourse,
    6536          89 :                              pBD_XP->pField, &nElemCount, TRUE);
    6537             : 
    6538             :     // Adding record to the MiraMon table (extended DBF)
    6539             :     // Flush settings
    6540          89 :     pFlushRecList = &hMiraMonLayer->MMPoint.MMAdmDB.FlushRecList;
    6541          89 :     pFlushRecList->pBlockWhereToSaveOrRead =
    6542          89 :         (void *)hMiraMonLayer->MMPoint.MMAdmDB.pRecList;
    6543             : 
    6544          89 :     pFlushRecList->pBlockToBeSaved =
    6545          89 :         (void *)hMiraMonLayer->MMPoint.MMAdmDB.szRecordOnCourse;
    6546          89 :     pFlushRecList->SizeOfBlockToBeSaved = pBD_XP->BytesPerRecord;
    6547             : 
    6548          89 :     if (MMAddFeatureRecordToMMDB(
    6549             :             hMiraMonLayer, hMMFeature, &hMiraMonLayer->MMPoint.MMAdmDB,
    6550             :             hMiraMonLayer->MMPoint.MMAdmDB.szRecordOnCourse, pFlushRecList,
    6551          89 :             &hMiraMonLayer->MMPoint.MMAdmDB.pMMBDXP->nRecords,
    6552             :             nNumPrivateMMField))
    6553           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6554          89 :     return MM_CONTINUE_WRITING_FEATURES;
    6555             : }
    6556             : 
    6557             : // Adds a stringline record to a MiraMon table associated with a vector layer.
    6558         102 : int MMAddArcRecordToMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6559             :                          struct MiraMonFeature *hMMFeature,
    6560             :                          MM_INTERNAL_FID nElemCount, struct MM_AH *pArcHeader)
    6561             : {
    6562         102 :     struct MM_DATA_BASE_XP *pBD_XP = nullptr;
    6563             :     struct MiraMonArcLayer *pMMArcLayer;
    6564         102 :     MM_EXT_DBF_N_FIELDS nNumPrivateMMField = MM_PRIVATE_ARC_DB_FIELDS;
    6565             :     struct MM_FLUSH_INFO *pFlushRecList;
    6566             : 
    6567         102 :     if (!hMiraMonLayer)
    6568           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6569             : 
    6570         102 :     if (hMiraMonLayer->bIsPolygon)
    6571          53 :         pMMArcLayer = &hMiraMonLayer->MMPolygon.MMArc;
    6572             :     else
    6573          49 :         pMMArcLayer = &hMiraMonLayer->MMArc;
    6574             : 
    6575             :     // In V1.1 only _UI32_MAX records number is allowed
    6576         102 :     if (hMiraMonLayer->bIsPolygon)
    6577             :     {
    6578          53 :         if (MMCheckVersionForFID(hMiraMonLayer,
    6579          53 :                                  pMMArcLayer->MMAdmDB.pMMBDXP->nRecords + 1))
    6580             :         {
    6581           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    6582             :                      "Error in MMCheckVersionForFID() (7)");
    6583           0 :             return MM_STOP_WRITING_FEATURES;
    6584             :         }
    6585             :     }
    6586             :     else
    6587             :     {
    6588          49 :         if (MMCheckVersionForFID(hMiraMonLayer,
    6589          49 :                                  pMMArcLayer->MMAdmDB.pMMBDXP->nRecords +
    6590          49 :                                      hMMFeature->nNumMRecords))
    6591             :         {
    6592           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    6593             :                      "Error in MMCheckVersionForFID() (8)");
    6594           0 :             return MM_STOP_WRITING_FEATURES;
    6595             :         }
    6596             :     }
    6597             : 
    6598         102 :     pBD_XP = pMMArcLayer->MMAdmDB.pMMBDXP;
    6599             : 
    6600             :     // Test length
    6601             :     // Private fields
    6602             :     // ID_GRAFIC
    6603         102 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField,
    6604             :                                         &nElemCount, TRUE))
    6605           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6606         102 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMArcLayer->MMAdmDB, 0,
    6607             :                                       hMiraMonLayer->szStringToOperate))
    6608           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6609             : 
    6610             :     // N_VERTEXS
    6611         102 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 1,
    6612         102 :                                         &pArcHeader->nElemCount, TRUE))
    6613           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6614         102 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMArcLayer->MMAdmDB, 1,
    6615             :                                       hMiraMonLayer->szStringToOperate))
    6616           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6617             : 
    6618             :     // LENGTH
    6619         102 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 2,
    6620         102 :                                         &pArcHeader->dfLength, FALSE))
    6621           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6622         102 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMArcLayer->MMAdmDB, 2,
    6623             :                                       hMiraMonLayer->szStringToOperate))
    6624           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6625             : 
    6626             :     // NODE_INI
    6627         102 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 3,
    6628         102 :                                         &pArcHeader->nFirstIdNode, TRUE))
    6629           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6630         102 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMArcLayer->MMAdmDB, 3,
    6631             :                                       hMiraMonLayer->szStringToOperate))
    6632           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6633             : 
    6634             :     // NODE_FI
    6635         102 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 4,
    6636         102 :                                         &pArcHeader->nLastIdNode, TRUE))
    6637           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6638         102 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMArcLayer->MMAdmDB, 4,
    6639             :                                       hMiraMonLayer->szStringToOperate))
    6640           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6641             : 
    6642             :     // GDAL fields
    6643         102 :     if (!hMiraMonLayer->bIsPolygon)
    6644             :     {
    6645          49 :         if (hMMFeature->nNumMRecords && hMMFeature->pRecords[0].nNumField)
    6646             :         {
    6647          48 :             if (MMDetectAndFixDBFWidthChange(hMiraMonLayer, hMMFeature,
    6648             :                                              &pMMArcLayer->MMAdmDB,
    6649             :                                              nNumPrivateMMField, 0, 0))
    6650           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    6651             :         }
    6652             :     }
    6653             : 
    6654             :     // Now length is sure, write
    6655         102 :     memset(pMMArcLayer->MMAdmDB.szRecordOnCourse, 0, pBD_XP->BytesPerRecord);
    6656         102 :     MMWriteValueToRecordDBXP(hMiraMonLayer,
    6657             :                              pMMArcLayer->MMAdmDB.szRecordOnCourse,
    6658         102 :                              pBD_XP->pField, &nElemCount, TRUE);
    6659             : 
    6660         102 :     MMWriteValueToRecordDBXP(hMiraMonLayer,
    6661             :                              pMMArcLayer->MMAdmDB.szRecordOnCourse,
    6662         102 :                              pBD_XP->pField + 1, &pArcHeader->nElemCount, TRUE);
    6663             : 
    6664         102 :     MMWriteValueToRecordDBXP(hMiraMonLayer,
    6665             :                              pMMArcLayer->MMAdmDB.szRecordOnCourse,
    6666         102 :                              pBD_XP->pField + 2, &pArcHeader->dfLength, FALSE);
    6667             : 
    6668         102 :     MMWriteValueToRecordDBXP(
    6669             :         hMiraMonLayer, pMMArcLayer->MMAdmDB.szRecordOnCourse,
    6670         102 :         pBD_XP->pField + 3, &pArcHeader->nFirstIdNode, TRUE);
    6671             : 
    6672         102 :     MMWriteValueToRecordDBXP(
    6673             :         hMiraMonLayer, pMMArcLayer->MMAdmDB.szRecordOnCourse,
    6674         102 :         pBD_XP->pField + 4, &pArcHeader->nLastIdNode, TRUE);
    6675             : 
    6676             :     // Adding record to the MiraMon table (extended DBF)
    6677             :     // Flush settings
    6678         102 :     pFlushRecList = &pMMArcLayer->MMAdmDB.FlushRecList;
    6679         102 :     pFlushRecList->pBlockWhereToSaveOrRead =
    6680         102 :         (void *)pMMArcLayer->MMAdmDB.pRecList;
    6681             : 
    6682         102 :     pFlushRecList->SizeOfBlockToBeSaved = pBD_XP->BytesPerRecord;
    6683         102 :     pFlushRecList->pBlockToBeSaved =
    6684         102 :         (void *)pMMArcLayer->MMAdmDB.szRecordOnCourse;
    6685             : 
    6686         102 :     if (hMiraMonLayer->bIsPolygon)
    6687             :     {
    6688          53 :         if (MMAppendBlockToBuffer(pFlushRecList))
    6689           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6690          53 :         pMMArcLayer->MMAdmDB.pMMBDXP->nRecords++;
    6691          53 :         return MM_CONTINUE_WRITING_FEATURES;
    6692             :     }
    6693             : 
    6694          49 :     pFlushRecList->SizeOfBlockToBeSaved = pBD_XP->BytesPerRecord;
    6695          49 :     if (MMAddFeatureRecordToMMDB(
    6696             :             hMiraMonLayer, hMMFeature, &pMMArcLayer->MMAdmDB,
    6697             :             pMMArcLayer->MMAdmDB.szRecordOnCourse, pFlushRecList,
    6698          49 :             &pMMArcLayer->MMAdmDB.pMMBDXP->nRecords, nNumPrivateMMField))
    6699           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6700          49 :     return MM_CONTINUE_WRITING_FEATURES;
    6701             : }
    6702             : 
    6703             : // Adds a node record to a MiraMon table associated with a vector layer.
    6704         151 : int MMAddNodeRecordToMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6705             :                           MM_INTERNAL_FID nElemCount, struct MM_NH *pNodeHeader)
    6706             : {
    6707         151 :     struct MM_DATA_BASE_XP *pBD_XP = nullptr;
    6708             :     struct MiraMonNodeLayer *pMMNodeLayer;
    6709             :     double nDoubleValue;
    6710             : 
    6711         151 :     if (!hMiraMonLayer)
    6712           0 :         return 1;
    6713             : 
    6714         151 :     if (hMiraMonLayer->bIsPolygon)
    6715          53 :         pMMNodeLayer = &hMiraMonLayer->MMPolygon.MMArc.MMNode;
    6716             :     else
    6717          98 :         pMMNodeLayer = &hMiraMonLayer->MMArc.MMNode;
    6718             : 
    6719         151 :     if (!pMMNodeLayer)
    6720             :     {
    6721           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Error in pMMNodeLayer() (1)");
    6722           0 :         return MM_STOP_WRITING_FEATURES;
    6723             :     }
    6724             : 
    6725             :     // In V1.1 only _UI32_MAX records number is allowed
    6726         151 :     if (MMCheckVersionForFID(hMiraMonLayer,
    6727         151 :                              pMMNodeLayer->MMAdmDB.pMMBDXP->nRecords + 1))
    6728             :     {
    6729           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    6730             :                  "Error in MMCheckVersionForFID() (9)");
    6731           0 :         return MM_STOP_WRITING_FEATURES;
    6732             :     }
    6733             : 
    6734             :     // Test length
    6735             :     // Private fields
    6736             :     // ID_GRAFIC
    6737         151 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer,
    6738         151 :                                         pMMNodeLayer->MMAdmDB.pMMBDXP->pField,
    6739             :                                         &nElemCount, TRUE))
    6740           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6741         151 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMNodeLayer->MMAdmDB, 0,
    6742             :                                       hMiraMonLayer->szStringToOperate))
    6743           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6744             : 
    6745             :     // ARCS_A_NOD
    6746         151 :     nDoubleValue = pNodeHeader->nArcsCount;
    6747         151 :     if (MMWriteValueToszStringToOperate(
    6748         151 :             hMiraMonLayer, pMMNodeLayer->MMAdmDB.pMMBDXP->pField + 1,
    6749             :             &nDoubleValue, FALSE))
    6750           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6751         151 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMNodeLayer->MMAdmDB, 1,
    6752             :                                       hMiraMonLayer->szStringToOperate))
    6753           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6754             : 
    6755             :     // TIPUS_NODE
    6756         151 :     nDoubleValue = pNodeHeader->cNodeType;
    6757         151 :     if (MMWriteValueToszStringToOperate(
    6758         151 :             hMiraMonLayer, pMMNodeLayer->MMAdmDB.pMMBDXP->pField + 2,
    6759             :             &nDoubleValue, FALSE))
    6760           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6761         151 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMNodeLayer->MMAdmDB, 2,
    6762             :                                       hMiraMonLayer->szStringToOperate))
    6763           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6764             : 
    6765             :     // Adding record to the MiraMon table (extended DBF)
    6766             :     // Flush settings
    6767         151 :     pMMNodeLayer->MMAdmDB.FlushRecList.pBlockWhereToSaveOrRead =
    6768         151 :         (void *)pMMNodeLayer->MMAdmDB.pRecList;
    6769             : 
    6770         151 :     pBD_XP = pMMNodeLayer->MMAdmDB.pMMBDXP;
    6771             : 
    6772         151 :     pMMNodeLayer->MMAdmDB.FlushRecList.SizeOfBlockToBeSaved =
    6773         151 :         pBD_XP->BytesPerRecord;
    6774         151 :     pMMNodeLayer->MMAdmDB.FlushRecList.pBlockToBeSaved =
    6775         151 :         (void *)pMMNodeLayer->MMAdmDB.szRecordOnCourse;
    6776             : 
    6777         151 :     memset(pMMNodeLayer->MMAdmDB.szRecordOnCourse, 0, pBD_XP->BytesPerRecord);
    6778         151 :     MMWriteValueToRecordDBXP(hMiraMonLayer,
    6779             :                              pMMNodeLayer->MMAdmDB.szRecordOnCourse,
    6780         151 :                              pBD_XP->pField, &nElemCount, TRUE);
    6781             : 
    6782         151 :     nDoubleValue = pNodeHeader->nArcsCount;
    6783         151 :     MMWriteValueToRecordDBXP(hMiraMonLayer,
    6784             :                              pMMNodeLayer->MMAdmDB.szRecordOnCourse,
    6785         151 :                              pBD_XP->pField + 1, &nDoubleValue, FALSE);
    6786             : 
    6787         151 :     nDoubleValue = pNodeHeader->cNodeType;
    6788         151 :     MMWriteValueToRecordDBXP(hMiraMonLayer,
    6789             :                              pMMNodeLayer->MMAdmDB.szRecordOnCourse,
    6790         151 :                              pBD_XP->pField + 2, &nDoubleValue, FALSE);
    6791             : 
    6792         151 :     if (MMAppendBlockToBuffer(&pMMNodeLayer->MMAdmDB.FlushRecList))
    6793           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6794         151 :     pMMNodeLayer->MMAdmDB.pMMBDXP->nRecords++;
    6795         151 :     return MM_CONTINUE_WRITING_FEATURES;
    6796             : }
    6797             : 
    6798             : // Adds a polygon or multipolygon record to a MiraMon table
    6799             : // associated with a vector layer.
    6800          68 : int MMAddPolygonRecordToMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6801             :                              struct MiraMonFeature *hMMFeature,
    6802             :                              MM_INTERNAL_FID nElemCount,
    6803             :                              MM_N_VERTICES_TYPE nVerticesCount,
    6804             :                              struct MM_PH *pPolHeader)
    6805             : {
    6806          68 :     struct MM_DATA_BASE_XP *pBD_XP = nullptr;
    6807          68 :     MM_EXT_DBF_N_FIELDS nNumPrivateMMField = MM_PRIVATE_POLYGON_DB_FIELDS;
    6808             :     struct MM_FLUSH_INFO *pFlushRecList;
    6809             : 
    6810          68 :     if (!hMiraMonLayer)
    6811           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6812             : 
    6813             :     // In V1.1 only _UI32_MAX records number is allowed
    6814          68 :     if (MMCheckVersionForFID(
    6815          68 :             hMiraMonLayer, hMiraMonLayer->MMPolygon.MMAdmDB.pMMBDXP->nRecords +
    6816          68 :                                (hMMFeature ? hMMFeature->nNumMRecords : 0)))
    6817           0 :         return MM_STOP_WRITING_FEATURES;
    6818             : 
    6819          68 :     pBD_XP = hMiraMonLayer->MMPolygon.MMAdmDB.pMMBDXP;
    6820             : 
    6821             :     // Test length
    6822             :     // Private fields
    6823             :     // ID_GRAFIC
    6824          68 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField,
    6825             :                                         &nElemCount, TRUE))
    6826           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6827          68 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer,
    6828             :                                       &hMiraMonLayer->MMPolygon.MMAdmDB, 0,
    6829             :                                       hMiraMonLayer->szStringToOperate))
    6830           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6831             : 
    6832             :     // The other fields are valid if pPolHeader exists (it is not
    6833             :     // the universal polygon)
    6834          68 :     if (pPolHeader)
    6835             :     {
    6836             :         // N_VERTEXS
    6837          41 :         if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 1,
    6838             :                                             &nVerticesCount, TRUE))
    6839           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6840          41 :         if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer,
    6841             :                                           &hMiraMonLayer->MMPolygon.MMAdmDB, 1,
    6842             :                                           hMiraMonLayer->szStringToOperate))
    6843           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6844             : 
    6845             :         // PERIMETER
    6846          41 :         if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 2,
    6847          41 :                                             &pPolHeader->dfPerimeter, FALSE))
    6848           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6849          41 :         if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer,
    6850             :                                           &hMiraMonLayer->MMPolygon.MMAdmDB, 2,
    6851             :                                           hMiraMonLayer->szStringToOperate))
    6852           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6853             : 
    6854             :         // AREA
    6855          41 :         if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 3,
    6856          41 :                                             &pPolHeader->dfArea, FALSE))
    6857           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6858          41 :         if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer,
    6859             :                                           &hMiraMonLayer->MMPolygon.MMAdmDB, 3,
    6860             :                                           hMiraMonLayer->szStringToOperate))
    6861           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6862             : 
    6863             :         // N_ARCS
    6864          41 :         if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 4,
    6865          41 :                                             &pPolHeader->nArcsCount, TRUE))
    6866           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6867          41 :         if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer,
    6868             :                                           &hMiraMonLayer->MMPolygon.MMAdmDB, 4,
    6869             :                                           hMiraMonLayer->szStringToOperate))
    6870           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6871             : 
    6872             :         // N_POLIG
    6873          41 :         if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 5,
    6874          41 :                                             &pPolHeader->nRingsCount, TRUE))
    6875           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6876          41 :         if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer,
    6877             :                                           &hMiraMonLayer->MMPolygon.MMAdmDB, 5,
    6878             :                                           hMiraMonLayer->szStringToOperate))
    6879           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6880             :     }
    6881             : 
    6882             :     // GDAL fields
    6883          68 :     if (hMMFeature && hMMFeature->nNumMRecords &&
    6884          41 :         hMMFeature->pRecords[0].nNumField)
    6885             :     {
    6886          41 :         if (MMDetectAndFixDBFWidthChange(hMiraMonLayer, hMMFeature,
    6887             :                                          &hMiraMonLayer->MMPolygon.MMAdmDB,
    6888             :                                          nNumPrivateMMField, 0, 0))
    6889           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6890             :     }
    6891             : 
    6892             :     // Adding record to the MiraMon table (extended DBF)
    6893             :     // Flush settings
    6894          68 :     pFlushRecList = &hMiraMonLayer->MMPolygon.MMAdmDB.FlushRecList;
    6895          68 :     pFlushRecList->pBlockWhereToSaveOrRead =
    6896          68 :         (void *)hMiraMonLayer->MMPolygon.MMAdmDB.pRecList;
    6897             : 
    6898          68 :     pFlushRecList->SizeOfBlockToBeSaved = pBD_XP->BytesPerRecord;
    6899          68 :     pFlushRecList->pBlockToBeSaved =
    6900          68 :         (void *)hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse;
    6901             : 
    6902             :     // Now length is sure, write
    6903          68 :     memset(hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse, ' ',
    6904          68 :            pBD_XP->BytesPerRecord);
    6905          68 :     if (MMWriteValueToRecordDBXP(
    6906             :             hMiraMonLayer, hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse,
    6907          68 :             pBD_XP->pField, &nElemCount, TRUE))
    6908           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6909             : 
    6910          68 :     if (!hMMFeature)
    6911             :     {
    6912          27 :         if (MMAppendBlockToBuffer(pFlushRecList))
    6913           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6914          27 :         hMiraMonLayer->MMPolygon.MMAdmDB.pMMBDXP->nRecords++;
    6915          27 :         return MM_CONTINUE_WRITING_FEATURES;
    6916             :     }
    6917             : 
    6918          41 :     if (pPolHeader)
    6919             :     {
    6920          41 :         MMWriteValueToRecordDBXP(
    6921             :             hMiraMonLayer, hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse,
    6922          41 :             pBD_XP->pField + 1, &nVerticesCount, TRUE);
    6923             : 
    6924          41 :         MMWriteValueToRecordDBXP(
    6925             :             hMiraMonLayer, hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse,
    6926          41 :             pBD_XP->pField + 2, &pPolHeader->dfPerimeter, FALSE);
    6927             : 
    6928          41 :         MMWriteValueToRecordDBXP(
    6929             :             hMiraMonLayer, hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse,
    6930          41 :             pBD_XP->pField + 3, &pPolHeader->dfArea, FALSE);
    6931             : 
    6932          41 :         MMWriteValueToRecordDBXP(
    6933             :             hMiraMonLayer, hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse,
    6934          41 :             pBD_XP->pField + 4, &pPolHeader->nArcsCount, TRUE);
    6935             : 
    6936          41 :         MMWriteValueToRecordDBXP(
    6937             :             hMiraMonLayer, hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse,
    6938          41 :             pBD_XP->pField + 5, &pPolHeader->nRingsCount, TRUE);
    6939             :     }
    6940             : 
    6941          41 :     pFlushRecList->SizeOfBlockToBeSaved = pBD_XP->BytesPerRecord;
    6942          41 :     if (MMAddFeatureRecordToMMDB(
    6943             :             hMiraMonLayer, hMMFeature, &hMiraMonLayer->MMPolygon.MMAdmDB,
    6944             :             hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse, pFlushRecList,
    6945          41 :             &hMiraMonLayer->MMPolygon.MMAdmDB.pMMBDXP->nRecords,
    6946             :             nNumPrivateMMField))
    6947           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6948          41 :     return MM_CONTINUE_WRITING_FEATURES;
    6949             : }
    6950             : 
    6951             : // Close the MiraMon database associated with a vector layer.
    6952         442 : static int MMCloseMMBD_XPFile(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6953             :                               struct MMAdmDatabase *MMAdmDB)
    6954             : {
    6955         442 :     int ret_code = 1;
    6956         442 :     if (!hMiraMonLayer)
    6957           0 :         return 1;
    6958             : 
    6959         442 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    6960             :     {
    6961         194 :         if (!MMAdmDB->pMMBDXP ||
    6962         194 :             (MMAdmDB->pMMBDXP && !MMAdmDB->pMMBDXP->pfDataBase))
    6963             :         {
    6964             :             // In case of 0 elements created we have to
    6965             :             // create an empty DBF
    6966           0 :             if (hMiraMonLayer->bIsPolygon)
    6967             :             {
    6968           0 :                 if (hMiraMonLayer->TopHeader.nElemCount <= 1)
    6969             :                 {
    6970           0 :                     if (MMCreateMMDB(hMiraMonLayer, nullptr))
    6971             :                     {
    6972           0 :                         CPLError(CE_Failure, CPLE_OutOfMemory,
    6973             :                                  "Memory error in MiraMon "
    6974             :                                  "driver (MMCreateMMDB())");
    6975           0 :                         goto end_label;
    6976             :                     }
    6977             :                 }
    6978             :             }
    6979           0 :             else if (hMiraMonLayer->bIsPoint || hMiraMonLayer->bIsArc)
    6980             :             {
    6981           0 :                 if (hMiraMonLayer->TopHeader.nElemCount == 0)
    6982             :                 {
    6983           0 :                     if (MMCreateMMDB(hMiraMonLayer, nullptr))
    6984             :                     {
    6985           0 :                         CPLError(CE_Failure, CPLE_OutOfMemory,
    6986             :                                  "Memory error in MiraMon "
    6987             :                                  "driver (MMCreateMMDB())");
    6988           0 :                         goto end_label;
    6989             :                     }
    6990             :                 }
    6991             :             }
    6992             :         }
    6993             : 
    6994         194 :         if (MM_WriteNRecordsMMBD_XPFile(MMAdmDB))
    6995           0 :             goto end_label;
    6996             : 
    6997             :         // Flushing all to be flushed
    6998         194 :         MMAdmDB->FlushRecList.SizeOfBlockToBeSaved = 0;
    6999         194 :         if (MMAppendBlockToBuffer(&MMAdmDB->FlushRecList))
    7000           0 :             goto end_label;
    7001             :     }
    7002             : 
    7003         442 :     ret_code = 0;
    7004         442 : end_label:
    7005             :     // Closing database files
    7006         442 :     if (MMAdmDB && MMAdmDB->pMMBDXP && MMAdmDB->pMMBDXP->pfDataBase)
    7007         194 :         fclose_and_nullify(&MMAdmDB->pMMBDXP->pfDataBase);
    7008             : 
    7009         442 :     return ret_code;
    7010             : }
    7011             : 
    7012         230 : int MMCloseMMBD_XP(struct MiraMonVectLayerInfo *hMiraMonLayer)
    7013             : {
    7014         230 :     int ret_code = 0;
    7015         230 :     if (!hMiraMonLayer)
    7016           0 :         return 1;
    7017             : 
    7018         230 :     if (hMiraMonLayer->pMMBDXP && hMiraMonLayer->pMMBDXP->pfDataBase)
    7019             :     {
    7020         113 :         fclose_and_nullify(&hMiraMonLayer->pMMBDXP->pfDataBase);
    7021             :     }
    7022             : 
    7023         230 :     if (hMiraMonLayer->bIsPoint)
    7024             :         ret_code =
    7025          76 :             MMCloseMMBD_XPFile(hMiraMonLayer, &hMiraMonLayer->MMPoint.MMAdmDB);
    7026         154 :     else if (hMiraMonLayer->bIsArc && !hMiraMonLayer->bIsPolygon)
    7027             :     {
    7028          62 :         if (MMCloseMMBD_XPFile(hMiraMonLayer, &hMiraMonLayer->MMArc.MMAdmDB))
    7029           0 :             ret_code = 1;
    7030          62 :         if (MMCloseMMBD_XPFile(hMiraMonLayer,
    7031             :                                &hMiraMonLayer->MMArc.MMNode.MMAdmDB))
    7032           0 :             ret_code = 1;
    7033             :     }
    7034          92 :     else if (hMiraMonLayer->bIsPolygon)
    7035             :     {
    7036          75 :         if (MMCloseMMBD_XPFile(hMiraMonLayer,
    7037             :                                &hMiraMonLayer->MMPolygon.MMAdmDB))
    7038           0 :             ret_code = 1;
    7039          75 :         if (MMCloseMMBD_XPFile(hMiraMonLayer,
    7040             :                                &hMiraMonLayer->MMPolygon.MMArc.MMAdmDB))
    7041           0 :             ret_code = 1;
    7042          75 :         if (MMCloseMMBD_XPFile(hMiraMonLayer,
    7043             :                                &hMiraMonLayer->MMPolygon.MMArc.MMNode.MMAdmDB))
    7044           0 :             ret_code = 1;
    7045             :     }
    7046          17 :     else if (hMiraMonLayer->bIsDBF)
    7047             :         ret_code =
    7048          17 :             MMCloseMMBD_XPFile(hMiraMonLayer, &hMiraMonLayer->MMAdmDBWriting);
    7049             : 
    7050         230 :     return ret_code;
    7051             : }
    7052             : 
    7053             : // Destroys the memory used to create a MiraMon table associated
    7054             : // with a vector layer.
    7055         442 : static void MMDestroyMMDBFile(struct MiraMonVectLayerInfo *hMiraMonLayer,
    7056             :                               struct MMAdmDatabase *pMMAdmDB)
    7057             : {
    7058         442 :     if (!hMiraMonLayer)
    7059           0 :         return;
    7060             : 
    7061         442 :     if (pMMAdmDB && pMMAdmDB->szRecordOnCourse)
    7062             :     {
    7063          44 :         VSIFree(pMMAdmDB->szRecordOnCourse);
    7064          44 :         pMMAdmDB->szRecordOnCourse = nullptr;
    7065             :     }
    7066         442 :     if (hMiraMonLayer->szStringToOperate)
    7067             :     {
    7068           0 :         VSIFree(hMiraMonLayer->szStringToOperate);
    7069           0 :         hMiraMonLayer->szStringToOperate = nullptr;
    7070           0 :         hMiraMonLayer->nNumStringToOperate = 0;
    7071             :     }
    7072             : 
    7073         442 :     if (pMMAdmDB && pMMAdmDB->pMMBDXP)
    7074             :     {
    7075         312 :         MM_ReleaseDBFHeader(&pMMAdmDB->pMMBDXP);
    7076         312 :         hMiraMonLayer->pMMBDXP = nullptr;
    7077             :     }
    7078         442 :     if (pMMAdmDB && pMMAdmDB->pRecList)
    7079             :     {
    7080          44 :         VSIFree(pMMAdmDB->pRecList);
    7081          44 :         pMMAdmDB->pRecList = nullptr;
    7082             :     }
    7083             : }
    7084             : 
    7085         820 : void MMDestroyMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer)
    7086             : {
    7087         820 :     if (!hMiraMonLayer)
    7088           0 :         return;
    7089             : 
    7090         820 :     if (hMiraMonLayer->bIsPoint)
    7091             :     {
    7092          76 :         MMDestroyMMDBFile(hMiraMonLayer, &hMiraMonLayer->MMPoint.MMAdmDB);
    7093          76 :         return;
    7094             :     }
    7095         744 :     if (hMiraMonLayer->bIsArc && !hMiraMonLayer->bIsPolygon)
    7096             :     {
    7097          62 :         MMDestroyMMDBFile(hMiraMonLayer, &hMiraMonLayer->MMArc.MMAdmDB);
    7098          62 :         MMDestroyMMDBFile(hMiraMonLayer, &hMiraMonLayer->MMArc.MMNode.MMAdmDB);
    7099          62 :         return;
    7100             :     }
    7101         682 :     if (hMiraMonLayer->bIsPolygon)
    7102             :     {
    7103          75 :         MMDestroyMMDBFile(hMiraMonLayer, &hMiraMonLayer->MMPolygon.MMAdmDB);
    7104          75 :         MMDestroyMMDBFile(hMiraMonLayer,
    7105             :                           &hMiraMonLayer->MMPolygon.MMArc.MMAdmDB);
    7106          75 :         MMDestroyMMDBFile(hMiraMonLayer,
    7107             :                           &hMiraMonLayer->MMPolygon.MMArc.MMNode.MMAdmDB);
    7108             :     }
    7109         682 :     if (hMiraMonLayer->bIsDBF)
    7110          17 :         MMDestroyMMDBFile(hMiraMonLayer, &hMiraMonLayer->MMAdmDBWriting);
    7111             : }
    7112             : 
    7113             : // COMING FROM mm_gdal_functions.c/h but only used here
    7114         336 : void MM_FillFieldDescriptorByLanguage(void)
    7115             : {
    7116         336 :     CPLStrlcpy(szInternalGraphicIdentifierEng, "Internal Graphic identifier",
    7117             :                MM_MAX_IDENTIFIER_SIZE);
    7118         336 :     CPLStrlcpy(szInternalGraphicIdentifierCat, "Identificador Grafic intern",
    7119             :                MM_MAX_IDENTIFIER_SIZE);
    7120         336 :     *(unsigned char *)&szInternalGraphicIdentifierCat[16] = MM_a_WITH_GRAVE;
    7121         336 :     CPLStrlcpy(szInternalGraphicIdentifierSpa, "Identificador Grafico interno",
    7122             :                MM_MAX_IDENTIFIER_SIZE);
    7123         336 :     *(unsigned char *)&szInternalGraphicIdentifierSpa[16] = MM_a_WITH_ACUTE;
    7124             : 
    7125         336 :     CPLStrlcpy(szNumberOfVerticesEng, "Number of vertices",
    7126             :                MM_MAX_IDENTIFIER_SIZE);
    7127         336 :     CPLStrlcpy(szNumberOfVerticesCat, "Nombre de vertexs",
    7128             :                MM_MAX_IDENTIFIER_SIZE);
    7129         336 :     CPLStrlcpy(szNumberOfVerticesSpa, "Numero de vertices",
    7130             :                MM_MAX_IDENTIFIER_SIZE);
    7131         336 :     *(unsigned char *)&szNumberOfVerticesCat[11] = MM_e_WITH_GRAVE;
    7132         336 :     *(unsigned char *)&szNumberOfVerticesSpa[1] = MM_u_WITH_ACUTE;
    7133         336 :     *(unsigned char *)&szNumberOfVerticesSpa[11] = MM_e_WITH_ACUTE;
    7134             : 
    7135         336 :     CPLStrlcpy(szLengthOfAarcEng, "Length of arc", MM_MAX_IDENTIFIER_SIZE);
    7136         336 :     CPLStrlcpy(szLengthOfAarcCat, "Longitud de l'arc", MM_MAX_IDENTIFIER_SIZE);
    7137         336 :     CPLStrlcpy(szLengthOfAarcSpa, "Longitud del arco", MM_MAX_IDENTIFIER_SIZE);
    7138             : 
    7139         336 :     CPLStrlcpy(szInitialNodeEng, "Initial node", MM_MAX_IDENTIFIER_SIZE);
    7140         336 :     CPLStrlcpy(szInitialNodeCat, "Node inicial", MM_MAX_IDENTIFIER_SIZE);
    7141         336 :     CPLStrlcpy(szInitialNodeSpa, "Nodo inicial", MM_MAX_IDENTIFIER_SIZE);
    7142             : 
    7143         336 :     CPLStrlcpy(szFinalNodeEng, "Final node", MM_MAX_IDENTIFIER_SIZE);
    7144         336 :     CPLStrlcpy(szFinalNodeCat, "Node final", MM_MAX_IDENTIFIER_SIZE);
    7145         336 :     CPLStrlcpy(szFinalNodeSpa, "Nodo final", MM_MAX_IDENTIFIER_SIZE);
    7146             : 
    7147         336 :     CPLStrlcpy(szNumberOfArcsToNodeEng, "Number of arcs to node",
    7148             :                MM_MAX_IDENTIFIER_SIZE);
    7149         336 :     CPLStrlcpy(szNumberOfArcsToNodeCat, "Nombre d'arcs al node",
    7150             :                MM_MAX_IDENTIFIER_SIZE);
    7151         336 :     CPLStrlcpy(szNumberOfArcsToNodeSpa, "Numero de arcos al nodo",
    7152             :                MM_MAX_IDENTIFIER_SIZE);
    7153         336 :     *(unsigned char *)&szNumberOfArcsToNodeSpa[1] = MM_u_WITH_ACUTE;
    7154             : 
    7155         336 :     CPLStrlcpy(szNodeTypeEng, "Node type", MM_MAX_IDENTIFIER_SIZE);
    7156         336 :     CPLStrlcpy(szNodeTypeCat, "Tipus de node", MM_MAX_IDENTIFIER_SIZE);
    7157         336 :     CPLStrlcpy(szNodeTypeSpa, "Tipo de nodo", MM_MAX_IDENTIFIER_SIZE);
    7158             : 
    7159         336 :     CPLStrlcpy(szPerimeterOfThePolygonEng, "Perimeter of the polygon",
    7160             :                MM_MAX_IDENTIFIER_SIZE);
    7161         336 :     CPLStrlcpy(szPerimeterOfThePolygonCat, "Perimetre del poligon",
    7162             :                MM_MAX_IDENTIFIER_SIZE);
    7163         336 :     CPLStrlcpy(szPerimeterOfThePolygonSpa, "Perimetro del poligono",
    7164             :                MM_MAX_IDENTIFIER_SIZE);
    7165             : 
    7166         336 :     *(unsigned char *)&szPerimeterOfThePolygonCat[3] = MM_i_WITH_ACUTE;
    7167         336 :     *(unsigned char *)&szPerimeterOfThePolygonSpa[3] = MM_i_WITH_ACUTE;
    7168         336 :     *(unsigned char *)&szPerimeterOfThePolygonCat[17] = MM_i_WITH_ACUTE;
    7169         336 :     *(unsigned char *)&szPerimeterOfThePolygonSpa[17] = MM_i_WITH_ACUTE;
    7170             : 
    7171         336 :     CPLStrlcpy(szAreaOfThePolygonEng, "Area of the polygon",
    7172             :                MM_MAX_IDENTIFIER_SIZE);
    7173         336 :     CPLStrlcpy(szAreaOfThePolygonCat, "Area del poligon",
    7174             :                MM_MAX_IDENTIFIER_SIZE);
    7175         336 :     CPLStrlcpy(szAreaOfThePolygonSpa, "Area del poligono",
    7176             :                MM_MAX_IDENTIFIER_SIZE);
    7177             : 
    7178         336 :     *(unsigned char *)&szAreaOfThePolygonCat[0] = MM_A_WITH_GRAVE;
    7179         336 :     *(unsigned char *)&szAreaOfThePolygonSpa[0] = MM_A_WITH_ACUTE;
    7180         336 :     *(unsigned char *)&szAreaOfThePolygonCat[12] = MM_i_WITH_ACUTE;
    7181         336 :     *(unsigned char *)&szAreaOfThePolygonSpa[12] = MM_i_WITH_ACUTE;
    7182             : 
    7183         336 :     CPLStrlcpy(szNumberOfArcsEng, "Number of arcs", MM_MAX_IDENTIFIER_SIZE);
    7184         336 :     CPLStrlcpy(szNumberOfArcsCat, "Nombre d'arcs", MM_MAX_IDENTIFIER_SIZE);
    7185         336 :     CPLStrlcpy(szNumberOfArcsSpa, "Numero de arcos", MM_MAX_IDENTIFIER_SIZE);
    7186             : 
    7187         336 :     *(unsigned char *)&szNumberOfArcsSpa[1] = MM_u_WITH_ACUTE;
    7188             : 
    7189         336 :     CPLStrlcpy(szNumberOfElementaryPolygonsEng, "Number of elementary polygons",
    7190             :                MM_MAX_IDENTIFIER_SIZE);
    7191         336 :     CPLStrlcpy(szNumberOfElementaryPolygonsCat, "Nombre de poligons elementals",
    7192             :                MM_MAX_IDENTIFIER_SIZE);
    7193         336 :     CPLStrlcpy(szNumberOfElementaryPolygonsSpa,
    7194             :                "Numero de poligonos elementales", MM_MAX_IDENTIFIER_SIZE);
    7195             : 
    7196         336 :     *(unsigned char *)&szNumberOfElementaryPolygonsSpa[1] = MM_u_WITH_ACUTE;
    7197         336 :     *(unsigned char *)&szNumberOfElementaryPolygonsCat[13] = MM_i_WITH_ACUTE;
    7198         336 :     *(unsigned char *)&szNumberOfElementaryPolygonsSpa[13] = MM_i_WITH_ACUTE;
    7199         336 : }
    7200             : 
    7201         660 : static MM_BOOLEAN MM_FillFieldDB_XP(
    7202             :     struct MM_FIELD *camp, const char *FieldName,
    7203             :     const char *FieldDescriptionEng, const char *FieldDescriptionCat,
    7204             :     const char *FieldDescriptionSpa, char FieldType,
    7205             :     MM_BYTES_PER_FIELD_TYPE_DBF BytesPerField, MM_BYTE DecimalsIfFloat)
    7206             : {
    7207             :     char nom_temp[MM_MAX_LON_FIELD_NAME_DBF];
    7208             :     int retorn_valida_nom_camp;
    7209             : 
    7210         660 :     if (FieldName)
    7211             :     {
    7212         660 :         retorn_valida_nom_camp = MM_ISExtendedNameBD_XP(FieldName);
    7213         660 :         if (retorn_valida_nom_camp == MM_DBF_NAME_NO_VALID)
    7214           0 :             return FALSE;
    7215         660 :         CPLStrlcpy(camp->FieldName, FieldName, MM_MAX_LON_FIELD_NAME_DBF);
    7216             : 
    7217         660 :         if (retorn_valida_nom_camp == MM_VALID_EXTENDED_DBF_NAME)
    7218             :         {
    7219           0 :             MM_CalculateBytesExtendedFieldName(camp);
    7220           0 :             CPLStrlcpy(nom_temp, FieldName, MM_MAX_LON_FIELD_NAME_DBF);
    7221           0 :             MM_ReturnValidClassicDBFFieldName(nom_temp);
    7222           0 :             nom_temp[MM_MAX_LON_CLASSICAL_FIELD_NAME_DBF] = '\0';
    7223           0 :             CPLStrlcpy(camp->ClassicalDBFFieldName, nom_temp,
    7224             :                        MM_MAX_LON_CLASSICAL_FIELD_NAME_DBF);
    7225             :         }
    7226             :     }
    7227             : 
    7228         660 :     if (FieldDescriptionEng)
    7229         660 :         CPLStrlcpy(camp->FieldDescription[MM_DEF_LANGUAGE], FieldDescriptionEng,
    7230             :                    sizeof(camp->FieldDescription[MM_DEF_LANGUAGE]));
    7231             :     else
    7232           0 :         strcpy(camp->FieldDescription[MM_DEF_LANGUAGE], "\0");
    7233             : 
    7234         660 :     if (FieldDescriptionEng)
    7235         660 :         CPLStrlcpy(camp->FieldDescription[MM_ENG_LANGUAGE], FieldDescriptionEng,
    7236             :                    sizeof(camp->FieldDescription[MM_ENG_LANGUAGE]));
    7237             :     else
    7238           0 :         strcpy(camp->FieldDescription[MM_ENG_LANGUAGE], "\0");
    7239             : 
    7240         660 :     if (FieldDescriptionCat)
    7241         660 :         CPLStrlcpy(camp->FieldDescription[MM_CAT_LANGUAGE], FieldDescriptionCat,
    7242             :                    sizeof(camp->FieldDescription[MM_CAT_LANGUAGE]));
    7243             :     else
    7244           0 :         strcpy(camp->FieldDescription[MM_CAT_LANGUAGE], "\0");
    7245             : 
    7246         660 :     if (FieldDescriptionSpa)
    7247         660 :         CPLStrlcpy(camp->FieldDescription[MM_SPA_LANGUAGE], FieldDescriptionSpa,
    7248             :                    sizeof(camp->FieldDescription[MM_SPA_LANGUAGE]));
    7249             :     else
    7250           0 :         strcpy(camp->FieldDescription[MM_SPA_LANGUAGE], "\0");
    7251             : 
    7252         660 :     camp->FieldType = FieldType;
    7253         660 :     camp->DecimalsIfFloat = DecimalsIfFloat;
    7254         660 :     camp->BytesPerField = BytesPerField;
    7255         660 :     return TRUE;
    7256             : }
    7257             : 
    7258          27 : size_t MM_DefineFirstPolygonFieldsDB_XP(struct MM_DATA_BASE_XP *bd_xp,
    7259             :                                         MM_BYTE n_perimeter_decimals,
    7260             :                                         MM_BYTE n_area_decimals_decimals)
    7261             : {
    7262          27 :     MM_EXT_DBF_N_FIELDS i_camp = 0;
    7263             : 
    7264          27 :     MM_FillFieldDB_XP(
    7265          27 :         bd_xp->pField + i_camp, szMMNomCampIdGraficDefecte,
    7266             :         szInternalGraphicIdentifierEng, szInternalGraphicIdentifierCat,
    7267             :         szInternalGraphicIdentifierSpa, 'N', MM_MIN_WIDTH_ID_GRAFIC, 0);
    7268          27 :     bd_xp->IdGraficField = 0;
    7269          27 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_ID_GRAFIC;
    7270          27 :     i_camp++;
    7271             : 
    7272          27 :     MM_FillFieldDB_XP(bd_xp->pField + i_camp, szMMNomCampNVertexsDefecte,
    7273             :                       szNumberOfVerticesEng, szNumberOfVerticesCat,
    7274             :                       szNumberOfVerticesSpa, 'N', MM_MIN_WIDTH_N_VERTEXS, 0);
    7275          27 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_N_VERTEXS;
    7276          27 :     i_camp++;
    7277             : 
    7278          27 :     MM_FillFieldDB_XP(bd_xp->pField + i_camp, szMMNomCampPerimetreDefecte,
    7279             :                       szPerimeterOfThePolygonEng, szPerimeterOfThePolygonCat,
    7280             :                       szPerimeterOfThePolygonSpa, 'N', MM_MIN_WIDTH_LONG,
    7281             :                       n_perimeter_decimals);
    7282          27 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_PERIMETRE;
    7283          27 :     i_camp++;
    7284             : 
    7285          27 :     MM_FillFieldDB_XP(bd_xp->pField + i_camp, szMMNomCampAreaDefecte,
    7286             :                       szAreaOfThePolygonEng, szAreaOfThePolygonCat,
    7287             :                       szAreaOfThePolygonSpa, 'N', MM_MIN_WIDTH_AREA,
    7288             :                       n_area_decimals_decimals);
    7289          27 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_AREA;
    7290          27 :     i_camp++;
    7291             : 
    7292          27 :     MM_FillFieldDB_XP(bd_xp->pField + i_camp, szMMNomCampNArcsDefecte,
    7293             :                       szNumberOfArcsEng, szNumberOfArcsCat, szNumberOfArcsSpa,
    7294             :                       'N', MM_MIN_WIDTH_N_ARCS, 0);
    7295          27 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_N_ARCS;
    7296          27 :     i_camp++;
    7297             : 
    7298          27 :     MM_FillFieldDB_XP(
    7299          27 :         bd_xp->pField + i_camp, szMMNomCampNPoligonsDefecte,
    7300             :         szNumberOfElementaryPolygonsEng, szNumberOfElementaryPolygonsCat,
    7301             :         szNumberOfElementaryPolygonsSpa, 'N', MM_MIN_WIDTH_N_POLIG, 0);
    7302          27 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_N_POLIG;
    7303          27 :     i_camp++;
    7304             : 
    7305          27 :     return i_camp;
    7306             : }
    7307             : 
    7308          58 : size_t MM_DefineFirstArcFieldsDB_XP(struct MM_DATA_BASE_XP *bd_xp,
    7309             :                                     MM_BYTE n_decimals)
    7310             : {
    7311             :     MM_EXT_DBF_N_FIELDS i_camp;
    7312             : 
    7313          58 :     i_camp = 0;
    7314          58 :     MM_FillFieldDB_XP(
    7315          58 :         bd_xp->pField + i_camp, szMMNomCampIdGraficDefecte,
    7316             :         szInternalGraphicIdentifierEng, szInternalGraphicIdentifierCat,
    7317             :         szInternalGraphicIdentifierSpa, 'N', MM_MIN_WIDTH_ID_GRAFIC, 0);
    7318          58 :     bd_xp->IdGraficField = 0;
    7319          58 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_ID_GRAFIC;
    7320          58 :     i_camp++;
    7321             : 
    7322          58 :     MM_FillFieldDB_XP(bd_xp->pField + i_camp, szMMNomCampNVertexsDefecte,
    7323             :                       szNumberOfVerticesEng, szNumberOfVerticesCat,
    7324             :                       szNumberOfVerticesSpa, 'N', MM_MIN_WIDTH_N_VERTEXS, 0);
    7325          58 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_N_VERTEXS;
    7326          58 :     i_camp++;
    7327             : 
    7328          58 :     MM_FillFieldDB_XP(bd_xp->pField + i_camp, szMMNomCampLongitudArcDefecte,
    7329             :                       szLengthOfAarcEng, szLengthOfAarcCat, szLengthOfAarcSpa,
    7330             :                       'N', MM_MIN_WIDTH_LONG, n_decimals);
    7331          58 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_LONG_ARC;
    7332          58 :     i_camp++;
    7333             : 
    7334          58 :     MM_FillFieldDB_XP(bd_xp->pField + i_camp, szMMNomCampNodeIniDefecte,
    7335             :                       szInitialNodeEng, szInitialNodeCat, szInitialNodeSpa, 'N',
    7336             :                       MM_MIN_WIDTH_INITIAL_NODE, 0);
    7337          58 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_NODE_INI;
    7338          58 :     i_camp++;
    7339             : 
    7340          58 :     MM_FillFieldDB_XP(bd_xp->pField + i_camp, szMMNomCampNodeFiDefecte,
    7341             :                       szFinalNodeEng, szFinalNodeCat, szFinalNodeSpa, 'N',
    7342             :                       MM_MIN_WIDTH_FINAL_NODE, 0);
    7343          58 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_NODE_FI;
    7344          58 :     i_camp++;
    7345             : 
    7346          58 :     return i_camp;
    7347             : }
    7348             : 
    7349          58 : size_t MM_DefineFirstNodeFieldsDB_XP(struct MM_DATA_BASE_XP *bd_xp)
    7350             : {
    7351             :     MM_EXT_DBF_N_FIELDS i_camp;
    7352             : 
    7353          58 :     i_camp = 0;
    7354             : 
    7355          58 :     MM_FillFieldDB_XP(
    7356          58 :         bd_xp->pField + i_camp, szMMNomCampIdGraficDefecte,
    7357             :         szInternalGraphicIdentifierEng, szInternalGraphicIdentifierCat,
    7358             :         szInternalGraphicIdentifierSpa, 'N', MM_MIN_WIDTH_ID_GRAFIC, 0);
    7359          58 :     bd_xp->IdGraficField = 0;
    7360          58 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_ID_GRAFIC;
    7361          58 :     i_camp++;
    7362             : 
    7363          58 :     MM_FillFieldDB_XP(bd_xp->pField + i_camp, szMMNomCampArcsANodeDefecte,
    7364             :                       szNumberOfArcsToNodeEng, szNumberOfArcsToNodeCat,
    7365             :                       szNumberOfArcsToNodeSpa, 'N', MM_MIN_WIDTH_ARCS_TO_NODE,
    7366             :                       0);
    7367          58 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_ARCS_A_NOD;
    7368          58 :     i_camp++;
    7369             : 
    7370          58 :     MM_FillFieldDB_XP(bd_xp->pField + i_camp, szMMNomCampTipusNodeDefecte,
    7371             :                       szNodeTypeEng, szNodeTypeCat, szNodeTypeSpa, 'N', 1, 0);
    7372          58 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_TIPUS_NODE;
    7373          58 :     i_camp++;
    7374             : 
    7375          58 :     return i_camp;
    7376             : }
    7377             : 
    7378          34 : size_t MM_DefineFirstPointFieldsDB_XP(struct MM_DATA_BASE_XP *bd_xp)
    7379             : {
    7380          34 :     size_t i_camp = 0;
    7381             : 
    7382          34 :     MM_FillFieldDB_XP(
    7383          34 :         bd_xp->pField + i_camp, szMMNomCampIdGraficDefecte,
    7384             :         szInternalGraphicIdentifierEng, szInternalGraphicIdentifierCat,
    7385             :         szInternalGraphicIdentifierSpa, 'N', MM_MIN_WIDTH_ID_GRAFIC, 0);
    7386          34 :     bd_xp->IdGraficField = 0;
    7387          34 :     (bd_xp->pField + i_camp)->GeoTopoTypeField = (MM_BYTE)MM_CAMP_ES_ID_GRAFIC;
    7388          34 :     i_camp++;
    7389             : 
    7390          34 :     return i_camp;
    7391             : }
    7392             : 
    7393             : CPL_C_END  // Necessary for compiling in GDAL project

Generated by: LCOV version 1.14