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

Generated by: LCOV version 1.14