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: 2671 3605 74.1 %
Date: 2024-11-21 22:18:42 Functions: 99 99 100.0 %

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

Generated by: LCOV version 1.14