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

Generated by: LCOV version 1.14