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: 2672 3611 74.0 %
Date: 2025-02-20 10:14:44 Functions: 99 99 100.0 %

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

Generated by: LCOV version 1.14