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: 2574 3460 74.4 %
Date: 2025-05-31 00:00:17 Functions: 96 96 100.0 %

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

Generated by: LCOV version 1.14