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-07-11 10:11:13 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        5359 : 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        5359 :     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        5359 :     return 0;
     115             : }
     116             : 
     117             : /* -------------------------------------------------------------------- */
     118             : /*      Layer Functions: Version                                         */
     119             : /* -------------------------------------------------------------------- */
     120         232 : int MMGetVectorVersion(struct MM_TH *pTopHeader)
     121             : {
     122         232 :     if ((pTopHeader->aLayerVersion[0] == ' ' ||
     123           0 :          pTopHeader->aLayerVersion[0] == '0') &&
     124         232 :         pTopHeader->aLayerVersion[1] == '1' &&
     125         220 :         pTopHeader->aLayerSubVersion == '1')
     126         220 :         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         496 : static void MMSet1_1Version(struct MM_TH *pTopHeader)
     138             : {
     139         496 :     pTopHeader->aLayerVersion[0] = ' ';
     140         496 :     pTopHeader->aLayerVersion[1] = '1';
     141         496 :     pTopHeader->aLayerSubVersion = '1';
     142         496 : }
     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         208 : int MMReadHeader(VSILFILE *pF, struct MM_TH *pMMHeader)
     155             : {
     156             :     char dot;
     157             :     uint32_t NCount;
     158         208 :     int32_t reservat4 = 0L;
     159             : 
     160         208 :     pMMHeader->Flag = 0x0;
     161         208 :     if (VSIFSeekL(pF, 0, SEEK_SET))
     162           0 :         return 1;
     163         208 :     if (VSIFReadL(pMMHeader->aFileType, 1, 3, pF) != 3)
     164           0 :         return 1;
     165         208 :     if (VSIFReadL(pMMHeader->aLayerVersion, 1, 2, pF) != 2)
     166           0 :         return 1;
     167         208 :     if (VSIFReadL(&dot, 1, 1, pF) != 1)
     168           0 :         return 1;
     169         208 :     if (VSIFReadL(&pMMHeader->aLayerSubVersion, 1, 1, pF) != 1)
     170           0 :         return 1;
     171         208 :     if (VSIFReadL(&pMMHeader->Flag, sizeof(pMMHeader->Flag), 1, pF) != 1)
     172           0 :         return 1;
     173         208 :     if (VSIFReadL(&pMMHeader->hBB.dfMinX, sizeof(pMMHeader->hBB.dfMinX), 1,
     174             :                   pF) != 1)
     175           0 :         return 1;
     176         208 :     if (VSIFReadL(&pMMHeader->hBB.dfMaxX, sizeof(pMMHeader->hBB.dfMaxX), 1,
     177             :                   pF) != 1)
     178           0 :         return 1;
     179         208 :     if (VSIFReadL(&pMMHeader->hBB.dfMinY, sizeof(pMMHeader->hBB.dfMinY), 1,
     180             :                   pF) != 1)
     181           0 :         return 1;
     182         208 :     if (VSIFReadL(&pMMHeader->hBB.dfMaxY, sizeof(pMMHeader->hBB.dfMaxY), 1,
     183             :                   pF) != 1)
     184           0 :         return 1;
     185         208 :     if (pMMHeader->aLayerVersion[0] == ' ' &&
     186         208 :         pMMHeader->aLayerVersion[1] == '1')
     187             :     {
     188         198 :         if (VSIFReadL(&NCount, sizeof(NCount), 1, pF) != 1)
     189           0 :             return 1;
     190             : 
     191         198 :         pMMHeader->nElemCount = (MM_INTERNAL_FID)NCount;
     192             : 
     193         198 :         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         208 :     if (pMMHeader->Flag & MM_LAYER_3D_INFO)
     210          33 :         pMMHeader->bIs3d = 1;
     211             : 
     212         208 :     if (pMMHeader->Flag & MM_LAYER_MULTIPOLYGON)
     213          21 :         pMMHeader->bIsMultipolygon = 1;
     214             : 
     215         208 :     return 0;
     216             : }
     217             : 
     218         175 : static int MMWriteHeader(VSILFILE *pF, struct MM_TH *pMMHeader)
     219             : {
     220         175 :     char dot = '.';
     221             :     uint32_t NCount;
     222         175 :     int32_t reservat4 = 0L;
     223         175 :     MM_INTERNAL_FID nNumber1 = 1, nNumber0 = 0;
     224             : 
     225         175 :     if (!pF)
     226           0 :         return 0;
     227             : 
     228         175 :     pMMHeader->Flag = MM_CREATED_USING_MIRAMON;  // Created from MiraMon
     229         175 :     if (pMMHeader->bIs3d)
     230          99 :         pMMHeader->Flag |= MM_LAYER_3D_INFO;  // 3D
     231             : 
     232         175 :     if (pMMHeader->bIsMultipolygon)
     233           4 :         pMMHeader->Flag |= MM_LAYER_MULTIPOLYGON;  // Multipolygon.
     234             : 
     235         175 :     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         175 :     if (VSIFSeekL(pF, 0, SEEK_SET))
     240           0 :         return 1;
     241         175 :     if (VSIFWriteL(pMMHeader->aFileType, 1, 3, pF) != 3)
     242           0 :         return 1;
     243         175 :     if (VSIFWriteL(pMMHeader->aLayerVersion, 1, 2, pF) != 2)
     244           0 :         return 1;
     245         175 :     if (VSIFWriteL(&dot, 1, 1, pF) != 1)
     246           0 :         return 1;
     247         175 :     if (VSIFWriteL(&pMMHeader->aLayerSubVersion, 1, 1, pF) != 1)
     248           0 :         return 1;
     249         175 :     if (VSIFWriteL(&pMMHeader->Flag, sizeof(pMMHeader->Flag), 1, pF) != 1)
     250           0 :         return 1;
     251         175 :     if (VSIFWriteL(&pMMHeader->hBB.dfMinX, sizeof(pMMHeader->hBB.dfMinX), 1,
     252             :                    pF) != 1)
     253           0 :         return 1;
     254         175 :     if (VSIFWriteL(&pMMHeader->hBB.dfMaxX, sizeof(pMMHeader->hBB.dfMaxX), 1,
     255             :                    pF) != 1)
     256           0 :         return 1;
     257         175 :     if (VSIFWriteL(&pMMHeader->hBB.dfMinY, sizeof(pMMHeader->hBB.dfMinY), 1,
     258             :                    pF) != 1)
     259           0 :         return 1;
     260         175 :     if (VSIFWriteL(&pMMHeader->hBB.dfMaxY, sizeof(pMMHeader->hBB.dfMaxY), 1,
     261             :                    pF) != 1)
     262           0 :         return 1;
     263         175 :     if (pMMHeader->aLayerVersion[0] == ' ' &&
     264         175 :         pMMHeader->aLayerVersion[1] == '1')
     265             :     {
     266         163 :         NCount = (uint32_t)pMMHeader->nElemCount;
     267         163 :         if (VSIFWriteL(&NCount, sizeof(NCount), 1, pF) != 1)
     268           0 :             return 1;
     269             : 
     270         163 :         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         175 :     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         211 : static void MMDestroyZSectionDescription(struct MM_ZSection *pZSection)
     623             : {
     624         211 :     if (pZSection->pZL)
     625             :     {
     626          91 :         VSIFree(pZSection->pZL);
     627          91 :         pZSection->pZL = nullptr;
     628             :     }
     629             : 
     630         211 :     if (pZSection->pZDescription)
     631             :     {
     632         113 :         VSIFree(pZSection->pZDescription);
     633         113 :         pZSection->pZDescription = nullptr;
     634             :     }
     635         211 : }
     636             : 
     637         116 : static int MMInitZSectionDescription(struct MM_ZSection *pZSection)
     638             : {
     639         116 :     if (MMCheckSize_t(pZSection->nMaxZDescription,
     640             :                       sizeof(*pZSection->pZDescription)))
     641           0 :         return 1;
     642             : 
     643         116 :     if (!pZSection->nMaxZDescription)
     644             :     {
     645           3 :         pZSection->pZDescription = nullptr;
     646           3 :         return 0;  // No elements to read (or write)
     647             :     }
     648             : 
     649         226 :     pZSection->pZDescription = (struct MM_ZD *)VSICalloc(
     650         113 :         (size_t)pZSection->nMaxZDescription, sizeof(*pZSection->pZDescription));
     651         113 :     if (!pZSection->pZDescription)
     652           0 :         return 1;
     653         113 :     return 0;
     654             : }
     655             : 
     656         116 : static int MMInitZSectionLayer(struct MiraMonVectLayerInfo *hMiraMonLayer,
     657             :                                VSILFILE *pF3d, struct MM_ZSection *pZSection)
     658             : {
     659         116 :     if (!hMiraMonLayer)
     660           0 :         return 1;
     661             : 
     662             :     // Zsection
     663         116 :     if (!hMiraMonLayer->TopHeader.bIs3d)
     664             :     {
     665           0 :         pZSection->pZDescription = nullptr;
     666           0 :         return 0;
     667             :     }
     668             : 
     669         116 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
     670             :     {
     671          91 :         pZSection->ZHeader.dfBBminz = STATISTICAL_UNDEF_VALUE;
     672          91 :         pZSection->ZHeader.dfBBmaxz = -STATISTICAL_UNDEF_VALUE;
     673             :     }
     674             : 
     675             :     // ZH
     676         116 :     pZSection->ZHeader.nMyDiskSize = 32;
     677         116 :     pZSection->ZSectionOffset = 0;
     678             : 
     679             :     // ZD
     680         116 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
     681             :     {
     682          91 :         pZSection->nMaxZDescription =
     683             :             MM_FIRST_NUMBER_OF_VERTICES * sizeof(double);
     684          91 :         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         116 :     if (hMiraMonLayer->LayerVersion == MM_32BITS_VERSION)
     713         110 :         pZSection->nZDDiskSize = MM_SIZE_OF_ZD_32_BITS;
     714             :     else
     715           6 :         pZSection->nZDDiskSize = MM_SIZE_OF_ZD_64_BITS;
     716             : 
     717         116 :     pZSection->ZDOffset = 0;
     718             : 
     719             :     // ZL
     720         116 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
     721             :     {
     722          91 :         if (MMInitFlush(&pZSection->FlushZL, pF3d, MM_1MB, &pZSection->pZL, 0,
     723             :                         sizeof(double)))
     724           0 :             return 1;
     725             :     }
     726         116 :     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         496 : static int MMChangeFinalPartOfTheName(char *pszName, size_t nMaxSizeOfName,
     744             :                                       const char *pszFinalPart,
     745             :                                       const char *pszNewPart)
     746             : {
     747         496 :     char *pAux, *pszWhereToFind, *pszLastFound = nullptr;
     748             :     ;
     749             : 
     750         496 :     if (!pszName || !pszFinalPart || !pszNewPart)
     751           0 :         return 0;
     752         992 :     if (MMIsEmptyString(pszName) || MMIsEmptyString(pszFinalPart) ||
     753         496 :         MMIsEmptyString(pszNewPart))
     754           0 :         return 0;
     755             : 
     756         496 :     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         496 :     pszWhereToFind = pszName;
     763         992 :     while (nullptr != (pAux = MM_stristr(pszWhereToFind, pszFinalPart)))
     764             :     {
     765         496 :         pszLastFound = pAux;
     766         496 :         pszWhereToFind = pAux + strlen(pAux);
     767             :     }
     768             : 
     769         496 :     if (!pszLastFound)
     770           0 :         return 1;  // Not found not changed
     771             : 
     772         496 :     memcpy(pszLastFound, pszNewPart, strlen(pszNewPart));
     773             : 
     774         496 :     return 0;
     775             : }
     776             : 
     777             : /* -------------------------------------------------------------------- */
     778             : /*      Layer Functions: initializing MiraMon layers                    */
     779             : /* -------------------------------------------------------------------- */
     780          76 : static int MMInitPointLayer(struct MiraMonVectLayerInfo *hMiraMonLayer)
     781             : {
     782          76 :     if (!hMiraMonLayer)
     783           0 :         return 1;
     784             : 
     785          76 :     hMiraMonLayer->bIsPoint = 1;
     786             : 
     787          76 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
     788             :     {
     789             :         // Geometrical part
     790             :         // Init header structure
     791          34 :         hMiraMonLayer->TopHeader.nElemCount = 0;
     792          34 :         MMInitBoundingBox(&hMiraMonLayer->TopHeader.hBB);
     793             : 
     794          34 :         hMiraMonLayer->TopHeader.bIs3d = 1;  // Read description of bRealIs3d
     795          34 :         hMiraMonLayer->TopHeader.aFileType[0] = 'P';
     796          34 :         hMiraMonLayer->TopHeader.aFileType[1] = 'N';
     797          34 :         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          34 :         snprintf(hMiraMonLayer->MMPoint.pszLayerName,
     803             :                  sizeof(hMiraMonLayer->MMPoint.pszLayerName), "%s.pnt",
     804             :                  hMiraMonLayer->pszSrcLayerName);
     805             :     }
     806          76 :     if (nullptr == (hMiraMonLayer->MMPoint.pF =
     807          76 :                         VSIFOpenL(hMiraMonLayer->MMPoint.pszLayerName,
     808          76 :                                   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          76 :     VSIFSeekL(hMiraMonLayer->MMPoint.pF, 0, SEEK_SET);
     816             : 
     817          76 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
     818             :     {
     819             :         // TL
     820          34 :         snprintf(hMiraMonLayer->MMPoint.pszTLName,
     821             :                  sizeof(hMiraMonLayer->MMPoint.pszTLName), "%sT.~xy",
     822             :                  hMiraMonLayer->pszSrcLayerName);
     823             : 
     824          34 :         if (nullptr == (hMiraMonLayer->MMPoint.pFTL =
     825          34 :                             VSIFOpenL(hMiraMonLayer->MMPoint.pszTLName,
     826          34 :                                       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          34 :         VSIFSeekL(hMiraMonLayer->MMPoint.pFTL, 0, SEEK_SET);
     834             : 
     835          34 :         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          34 :         if (hMiraMonLayer->TopHeader.bIs3d)
     842             :         {
     843          34 :             snprintf(hMiraMonLayer->MMPoint.psz3DLayerName,
     844             :                      sizeof(hMiraMonLayer->MMPoint.psz3DLayerName), "%sT.~z",
     845             :                      hMiraMonLayer->pszSrcLayerName);
     846             : 
     847          34 :             if (nullptr == (hMiraMonLayer->MMPoint.pF3d =
     848          34 :                                 VSIFOpenL(hMiraMonLayer->MMPoint.psz3DLayerName,
     849          34 :                                           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          34 :             VSIFSeekL(hMiraMonLayer->MMPoint.pF3d, 0, SEEK_SET);
     857             :         }
     858             :     }
     859             :     // Zsection
     860          76 :     if (hMiraMonLayer->TopHeader.bIs3d)
     861             :     {
     862          46 :         if (MMInitZSectionLayer(hMiraMonLayer, hMiraMonLayer->MMPoint.pF3d,
     863             :                                 &hMiraMonLayer->MMPoint.pZSection))
     864           0 :             return 1;
     865             : 
     866          46 :         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          76 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
     882             :     {
     883          34 :         snprintf(hMiraMonLayer->MMPoint.pszREL_LayerName,
     884             :                  sizeof(hMiraMonLayer->MMPoint.pszREL_LayerName), "%sT.rel",
     885             :                  hMiraMonLayer->pszSrcLayerName);
     886             :     }
     887             :     else
     888             :     {
     889          42 :         CPLStrlcpy(hMiraMonLayer->MMPoint.pszREL_LayerName,
     890          42 :                    hMiraMonLayer->pszSrcLayerName,
     891             :                    sizeof(hMiraMonLayer->MMPoint.pszREL_LayerName));
     892          42 :         if (MMChangeFinalPartOfTheName(hMiraMonLayer->MMPoint.pszREL_LayerName,
     893             :                                        MM_CPL_PATH_BUF_SIZE, ".pnt", "T.rel"))
     894           0 :             return 1;
     895             :     }
     896             : 
     897          76 :     hMiraMonLayer->pszMainREL_LayerName =
     898          76 :         hMiraMonLayer->MMPoint.pszREL_LayerName;
     899             : 
     900          76 :     if (hMiraMonLayer->ReadOrWrite == MM_READING_MODE)
     901             :     {
     902             :         // This file has to exist and be the appropriate version.
     903          42 :         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          75 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
     910             :     {
     911          34 :         snprintf(hMiraMonLayer->MMPoint.MMAdmDB.pszExtDBFLayerName,
     912             :                  sizeof(hMiraMonLayer->MMPoint.MMAdmDB.pszExtDBFLayerName),
     913             :                  "%sT.dbf", hMiraMonLayer->pszSrcLayerName);
     914             :     }
     915             :     else
     916             :     {
     917          41 :         CPLStrlcpy(hMiraMonLayer->MMPoint.MMAdmDB.pszExtDBFLayerName,
     918          41 :                    hMiraMonLayer->pszSrcLayerName,
     919             :                    sizeof(hMiraMonLayer->MMPoint.MMAdmDB.pszExtDBFLayerName));
     920             : 
     921          41 :         if (MMChangeFinalPartOfTheName(
     922          41 :                 hMiraMonLayer->MMPoint.MMAdmDB.pszExtDBFLayerName,
     923             :                 MM_CPL_PATH_BUF_SIZE, ".pnt", "T.dbf"))
     924           0 :             return 1;
     925             :     }
     926             : 
     927          75 :     if (hMiraMonLayer->ReadOrWrite == MM_READING_MODE)
     928             :     {
     929          41 :         if (MM_ReadExtendedDBFHeader(hMiraMonLayer))
     930           1 :             return 1;
     931             :     }
     932             : 
     933          74 :     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         228 : int MMInitLayerByType(struct MiraMonVectLayerInfo *hMiraMonLayer)
    1542             : {
    1543         228 :     if (!hMiraMonLayer)
    1544           0 :         return 1;
    1545             : 
    1546         228 :     if (hMiraMonLayer->eLT == MM_LayerType_Point ||
    1547         174 :         hMiraMonLayer->eLT == MM_LayerType_Point3d)
    1548             :     {
    1549          76 :         if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    1550             :         {
    1551          34 :             snprintf(hMiraMonLayer->MMPoint.pszLayerName,
    1552             :                      sizeof(hMiraMonLayer->MMPoint.pszLayerName), "%s.pnt",
    1553             :                      hMiraMonLayer->pszSrcLayerName);
    1554             :         }
    1555             :         else
    1556             :         {
    1557          42 :             CPLStrlcpy(hMiraMonLayer->MMPoint.pszLayerName,
    1558          42 :                        hMiraMonLayer->pszSrcLayerName,
    1559             :                        sizeof(hMiraMonLayer->MMPoint.pszLayerName));
    1560             :         }
    1561          76 :         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          76 :         if (MMInitPointLayer(hMiraMonLayer))
    1571             :         {
    1572             :             // Error specified inside the function
    1573           2 :             return 1;
    1574             :         }
    1575          74 :         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         332 : 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         332 :     if (!hMiraMonLayer)
    1763           0 :         return 1;
    1764             : 
    1765             :     // Some variables must be initialized
    1766         332 :     MM_FillFieldDescriptorByLanguage();
    1767             : 
    1768         332 :     memset(hMiraMonLayer, 0, sizeof(*hMiraMonLayer));
    1769             : 
    1770             :     //hMiraMonLayer->Version = MM_VECTOR_LAYER_LAST_VERSION;
    1771             : 
    1772         332 :     hMiraMonLayer->ReadOrWrite = ReadOrWrite;
    1773         332 :     hMiraMonLayer->MMMap = MMMap;
    1774             : 
    1775             :     // Don't free in destructor
    1776         332 :     hMiraMonLayer->pLayerDB = pLayerDB;
    1777             : 
    1778             :     // Opening mode
    1779         332 :     strcpy(hMiraMonLayer->pszFlags, "wb+");
    1780             : 
    1781         332 :     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         332 :     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         332 :     else if (LayerVersion == MM_32BITS_VERSION)
    1794             :     {
    1795         308 :         MMSet1_1Version(&hMiraMonLayer->TopHeader);
    1796         308 :         hMiraMonLayer->nHeaderDiskSize = MM_HEADER_SIZE_32_BITS;
    1797         308 :         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         332 :     hMiraMonLayer->pszSrcLayerName = CPLStrdup(pzFileName);
    1807         332 :     hMiraMonLayer->szLayerTitle = CPLStrdup(CPLGetFilename(pzFileName));
    1808             : 
    1809         332 :     if (!hMiraMonLayer->bIsBeenInit &&
    1810         332 :         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         332 :     hMiraMonLayer->nNumStringToOperate = 0;
    1822         332 :     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         332 :     hMiraMonLayer->nMMLanguage = nMMLanguage;
    1831             : 
    1832         332 :     if (nMMRecode == MM_RECODE_UTF8)
    1833           4 :         hMiraMonLayer->nCharSet = MM_JOC_CARAC_UTF8_DBF;
    1834             :     else  //if(nMMRecode==MM_RECODE_ANSI)
    1835         328 :         hMiraMonLayer->nCharSet = MM_JOC_CARAC_ANSI_DBASE;
    1836         332 :     return 0;
    1837             : }
    1838             : 
    1839             : /* -------------------------------------------------------------------- */
    1840             : /*      Layer Functions: Closing MiraMon layers                         */
    1841             : /* -------------------------------------------------------------------- */
    1842          91 : 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          91 :     int ret_code = 1;
    1849          91 :     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          91 :     if (!pF || !pF3d || !pszF3d || !pZSection)
    1855           0 :         return 0;
    1856             : 
    1857          91 :     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          91 :     ret_code = 0;
    1877          91 : end_label:
    1878          91 :     fclose_and_nullify(&pF3d);
    1879          91 :     if (pszF3d && *pszF3d != '\0')
    1880          91 :         VSIUnlink(pszF3d);
    1881             : 
    1882          91 :     return ret_code;
    1883             : }
    1884             : 
    1885          76 : static int MMClosePointLayer(struct MiraMonVectLayerInfo *hMiraMonLayer)
    1886             : {
    1887          76 :     int ret_code = 1;
    1888          76 :     if (!hMiraMonLayer)
    1889           0 :         return 1;
    1890             : 
    1891          76 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    1892             :     {
    1893          34 :         hMiraMonLayer->nFinalElemCount = hMiraMonLayer->TopHeader.nElemCount;
    1894          34 :         hMiraMonLayer->TopHeader.bIs3d = hMiraMonLayer->bIsReal3d;
    1895             : 
    1896          34 :         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          34 :         hMiraMonLayer->OffsetCheck = hMiraMonLayer->nHeaderDiskSize;
    1903             : 
    1904             :         // TL Section
    1905          34 :         hMiraMonLayer->MMPoint.FlushTL.SizeOfBlockToBeSaved = 0;
    1906          34 :         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          34 :         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          34 :         fclose_and_nullify(&hMiraMonLayer->MMPoint.pFTL);
    1922             : 
    1923          34 :         if (*hMiraMonLayer->MMPoint.pszTLName != '\0')
    1924          34 :             VSIUnlink(hMiraMonLayer->MMPoint.pszTLName);
    1925             : 
    1926          34 :         if (MMClose3DSectionLayer(
    1927             :                 hMiraMonLayer, hMiraMonLayer->TopHeader.nElemCount,
    1928             :                 hMiraMonLayer->MMPoint.pF, hMiraMonLayer->MMPoint.pF3d,
    1929          34 :                 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          76 :     ret_code = 0;
    1939          76 : end_label:
    1940          76 :     fclose_and_nullify(&hMiraMonLayer->MMPoint.pF);
    1941          76 :     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         228 : int MMCloseLayer(struct MiraMonVectLayerInfo *hMiraMonLayer)
    2162             : {
    2163         228 :     int ret_code = 0;
    2164             :     //CheckMMVectorLayerVersion(hMiraMonLayer, 1)
    2165             : 
    2166         228 :     if (!hMiraMonLayer)
    2167           0 :         return 0;
    2168             : 
    2169         228 :     if (hMiraMonLayer->bIsPoint)
    2170             :     {
    2171          76 :         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         228 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    2192             :     {
    2193         108 :         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         228 :     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         228 :     return ret_code;
    2209             : }
    2210             : 
    2211             : /* -------------------------------------------------------------------- */
    2212             : /*      Layer Functions: Destroying (allocated memory)                  */
    2213             : /* -------------------------------------------------------------------- */
    2214         421 : static void MMDestroyMMAdmDB(struct MMAdmDatabase *pMMAdmDB)
    2215             : {
    2216         421 :     if (pMMAdmDB->pRecList)
    2217             :     {
    2218         148 :         VSIFree(pMMAdmDB->pRecList);
    2219         148 :         pMMAdmDB->pRecList = nullptr;
    2220             :     }
    2221             : 
    2222         421 :     if (pMMAdmDB->szRecordOnCourse)
    2223             :     {
    2224         148 :         VSIFree(pMMAdmDB->szRecordOnCourse);
    2225         148 :         pMMAdmDB->szRecordOnCourse = nullptr;
    2226         148 :         pMMAdmDB->nNumRecordOnCourse = 0;
    2227             :     }
    2228         421 : }
    2229             : 
    2230          76 : static int MMDestroyPointLayer(struct MiraMonVectLayerInfo *hMiraMonLayer)
    2231             : {
    2232          76 :     if (!hMiraMonLayer)
    2233           0 :         return 1;
    2234             : 
    2235          76 :     if (hMiraMonLayer->MMPoint.pTL)
    2236             :     {
    2237          34 :         VSIFree(hMiraMonLayer->MMPoint.pTL);
    2238          34 :         hMiraMonLayer->MMPoint.pTL = nullptr;
    2239             :     }
    2240             : 
    2241          76 :     MMDestroyZSectionDescription(&hMiraMonLayer->MMPoint.pZSection);
    2242          76 :     MMDestroyMMAdmDB(&hMiraMonLayer->MMPoint.MMAdmDB);
    2243             : 
    2244          76 :     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         812 : int MMDestroyLayer(struct MiraMonVectLayerInfo *hMiraMonLayer)
    2340             : {
    2341             :     //CheckMMVectorLayerVersion(hMiraMonLayer, 1)
    2342             : 
    2343         812 :     if (!hMiraMonLayer)
    2344           0 :         return 1;
    2345             : 
    2346         812 :     if (hMiraMonLayer->bIsPoint)
    2347          76 :         MMDestroyPointLayer(hMiraMonLayer);
    2348         736 :     else if (hMiraMonLayer->bIsArc && !hMiraMonLayer->bIsPolygon)
    2349          60 :         MMDestroyArcLayer(hMiraMonLayer);
    2350         676 :     else if (hMiraMonLayer->bIsPolygon)
    2351          75 :         MMDestroyPolygonLayer(hMiraMonLayer);
    2352             : 
    2353         812 :     if (hMiraMonLayer->pszSrcLayerName)
    2354             :     {
    2355         452 :         VSIFree(hMiraMonLayer->pszSrcLayerName);
    2356         452 :         hMiraMonLayer->pszSrcLayerName = nullptr;
    2357             :     }
    2358         812 :     if (hMiraMonLayer->szLayerTitle)
    2359             :     {
    2360         332 :         VSIFree(hMiraMonLayer->szLayerTitle);
    2361         332 :         hMiraMonLayer->szLayerTitle = nullptr;
    2362             :     }
    2363         812 :     if (hMiraMonLayer->pSRS)
    2364             :     {
    2365         169 :         VSIFree(hMiraMonLayer->pSRS);
    2366         169 :         hMiraMonLayer->pSRS = nullptr;
    2367             :     }
    2368             : 
    2369         812 :     if (hMiraMonLayer->pZUnit)
    2370             :     {
    2371           0 :         VSIFree(hMiraMonLayer->pZUnit);
    2372           0 :         hMiraMonLayer->pZUnit = nullptr;
    2373             :     }
    2374             : 
    2375         812 :     if (hMiraMonLayer->pMultRecordIndex)
    2376             :     {
    2377         103 :         VSIFree(hMiraMonLayer->pMultRecordIndex);
    2378         103 :         hMiraMonLayer->pMultRecordIndex = nullptr;
    2379             :     }
    2380             : 
    2381         812 :     if (hMiraMonLayer->ReadFeature.pNCoordRing)
    2382             :     {
    2383          85 :         free(hMiraMonLayer->ReadFeature.pNCoordRing);
    2384          85 :         hMiraMonLayer->ReadFeature.pNCoordRing = nullptr;
    2385             :     }
    2386         812 :     if (hMiraMonLayer->ReadFeature.pCoord)
    2387             :     {
    2388          97 :         free(hMiraMonLayer->ReadFeature.pCoord);
    2389          97 :         hMiraMonLayer->ReadFeature.pCoord = nullptr;
    2390             :     }
    2391         812 :     if (hMiraMonLayer->ReadFeature.pZCoord)
    2392             :     {
    2393          19 :         free(hMiraMonLayer->ReadFeature.pZCoord);
    2394          19 :         hMiraMonLayer->ReadFeature.pZCoord = nullptr;
    2395             :     }
    2396         812 :     if (hMiraMonLayer->ReadFeature.pRecords)
    2397             :     {
    2398           0 :         free(hMiraMonLayer->ReadFeature.pRecords);
    2399           0 :         hMiraMonLayer->ReadFeature.pRecords = nullptr;
    2400             :     }
    2401         812 :     if (hMiraMonLayer->ReadFeature.flag_VFG)
    2402             :     {
    2403          38 :         free(hMiraMonLayer->ReadFeature.flag_VFG);
    2404          38 :         hMiraMonLayer->ReadFeature.flag_VFG = nullptr;
    2405             :     }
    2406             : 
    2407         812 :     if (hMiraMonLayer->pArcs)
    2408             :     {
    2409          44 :         VSIFree(hMiraMonLayer->pArcs);
    2410          44 :         hMiraMonLayer->pArcs = nullptr;
    2411             :     }
    2412             : 
    2413         812 :     if (hMiraMonLayer->szStringToOperate)
    2414             :     {
    2415         444 :         VSIFree(hMiraMonLayer->szStringToOperate);
    2416         444 :         hMiraMonLayer->szStringToOperate = nullptr;
    2417         444 :         hMiraMonLayer->nNumStringToOperate = 0;
    2418             :     }
    2419             : 
    2420         812 :     if (hMiraMonLayer->pLayerDB)
    2421             :     {
    2422         108 :         if (hMiraMonLayer->pLayerDB->pFields)
    2423             :         {
    2424         108 :             VSIFree(hMiraMonLayer->pLayerDB->pFields);
    2425         108 :             hMiraMonLayer->pLayerDB->pFields = nullptr;
    2426             :         }
    2427         108 :         VSIFree(hMiraMonLayer->pLayerDB);
    2428         108 :         hMiraMonLayer->pLayerDB = nullptr;
    2429             :     }
    2430             : 
    2431             :     // Destroys all database objects
    2432         812 :     MMDestroyMMDB(hMiraMonLayer);
    2433             : 
    2434         812 :     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        1132 : int MMInitFlush(struct MM_FLUSH_INFO *pFlush, VSILFILE *pF, GUInt64 nBlockSize,
    2444             :                 char **pBuffer, MM_FILE_OFFSET DiskOffsetWhereToFlush,
    2445             :                 GInt32 nMyDiskSize)
    2446             : {
    2447        1132 :     memset(pFlush, 0, sizeof(*pFlush));
    2448        1132 :     *pBuffer = nullptr;
    2449             : 
    2450        1132 :     pFlush->nMyDiskSize = nMyDiskSize;
    2451        1132 :     pFlush->pF = pF;
    2452        1132 :     pFlush->nBlockSize = nBlockSize;
    2453        1132 :     pFlush->nNumBytes = 0;
    2454        1132 :     if (MMCheckSize_t(nBlockSize, 1))
    2455           0 :         return 1;
    2456             : 
    2457        1132 :     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        1132 :     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        1132 :     pFlush->OffsetWhereToFlush = DiskOffsetWhereToFlush;
    2473        1132 :     pFlush->CurrentOffset = 0;
    2474        1132 :     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         716 : static int MMFlushToDisk(struct MM_FLUSH_INFO *FlushInfo)
    2490             : {
    2491         716 :     if (!FlushInfo->nNumBytes)
    2492          86 :         return 0;
    2493             :     // Just flush to the disk at the correct place.
    2494         630 :     VSIFSeekL(FlushInfo->pF, FlushInfo->OffsetWhereToFlush, SEEK_SET);
    2495             : 
    2496         630 :     if (FlushInfo->nNumBytes !=
    2497         630 :         (GUInt64)VSIFWriteL(FlushInfo->pBlockWhereToSaveOrRead, 1,
    2498         630 :                             (size_t)FlushInfo->nNumBytes, FlushInfo->pF))
    2499           0 :         return 1;
    2500         630 :     FlushInfo->OffsetWhereToFlush += FlushInfo->nNumBytes;
    2501         630 :     FlushInfo->NTimesFlushed++;
    2502         630 :     FlushInfo->TotalSavedBytes += FlushInfo->nNumBytes;
    2503         630 :     FlushInfo->nNumBytes = 0;
    2504             : 
    2505         630 :     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        5557 : int MMAppendBlockToBuffer(struct MM_FLUSH_INFO *FlushInfo)
    2529             : {
    2530        5557 :     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        4841 :         if (FlushInfo->nNumBytes == 0 &&
    2535         689 :             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        4841 :         if (FlushInfo->nNumBytes + FlushInfo->SizeOfBlockToBeSaved <=
    2544        4841 :             FlushInfo->nBlockSize)
    2545             :         {
    2546        4841 :             if (FlushInfo->pBlockToBeSaved)
    2547             :             {
    2548        4524 :                 memcpy((void *)((char *)FlushInfo->pBlockWhereToSaveOrRead +
    2549        4524 :                                 FlushInfo->nNumBytes),
    2550        4524 :                        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        4841 :             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        4841 :         return 0;
    2573             :     }
    2574             :     // Just flush to the disc.
    2575         716 :     return MMFlushToDisk(FlushInfo);
    2576             : }
    2577             : 
    2578             : // Copy the contents of a temporary file to a final file.
    2579             : // Used everywhere when closing layers.
    2580         234 : int MMMoveFromFileToFile(VSILFILE *pSrcFile, VSILFILE *pDestFile,
    2581             :                          MM_FILE_OFFSET *pnOffset)
    2582             : {
    2583         234 :     size_t bufferSize = 1024 * 1024;  // 1 MB buffer;
    2584             :     unsigned char *buffer;
    2585             :     size_t bytesRead, bytesWritten;
    2586             : 
    2587         234 :     if (!pSrcFile || !pDestFile || !pnOffset)
    2588           0 :         return 0;
    2589             : 
    2590         234 :     buffer = (unsigned char *)VSICalloc(1, bufferSize);
    2591             : 
    2592         234 :     if (!buffer)
    2593           0 :         return 1;
    2594             : 
    2595         234 :     VSIFSeekL(pSrcFile, 0, SEEK_SET);
    2596         234 :     VSIFSeekL(pDestFile, *pnOffset, SEEK_SET);
    2597         468 :     while ((bytesRead = VSIFReadL(buffer, sizeof(unsigned char), bufferSize,
    2598             :                                   pSrcFile)) > 0)
    2599             :     {
    2600             :         bytesWritten =
    2601         234 :             VSIFWriteL(buffer, sizeof(unsigned char), bytesRead, pDestFile);
    2602         234 :         if (bytesWritten != bytesRead)
    2603             :         {
    2604           0 :             VSIFree(buffer);
    2605           0 :             return 1;
    2606             :         }
    2607         234 :         (*pnOffset) += bytesWritten;
    2608             :     }
    2609         234 :     VSIFree(buffer);
    2610         234 :     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          83 : int MMInitFeature(struct MiraMonFeature *hMMFeature)
    3501             : {
    3502          83 :     memset(hMMFeature, 0, sizeof(*hMMFeature));
    3503             : 
    3504          83 :     hMMFeature->nMaxMRecords = MM_INIT_NUMBER_OF_RECORDS;
    3505          83 :     if (MMCheckSize_t(hMMFeature->nMaxMRecords,
    3506             :                       sizeof(*(hMMFeature->pRecords))))
    3507           0 :         return 1;
    3508             : 
    3509          83 :     if (!hMMFeature->nMaxMRecords)
    3510           0 :         return 0;  // No elements nothing to do.
    3511             : 
    3512          83 :     if ((hMMFeature->pRecords = VSICalloc((size_t)hMMFeature->nMaxMRecords,
    3513             :                                           sizeof(*(hMMFeature->pRecords)))) ==
    3514             :         nullptr)
    3515           0 :         return 1;
    3516             : 
    3517          83 :     hMMFeature->pRecords[0].nMaxField = MM_INIT_NUMBER_OF_FIELDS;
    3518          83 :     hMMFeature->pRecords[0].nNumField = 0;
    3519          83 :     if (MMCheckSize_t(hMMFeature->pRecords[0].nMaxField,
    3520             :                       sizeof(*(hMMFeature->pRecords[0].pField))))
    3521           0 :         return 1;
    3522          83 :     if (nullptr == (hMMFeature->pRecords[0].pField =
    3523          83 :                         VSICalloc((size_t)hMMFeature->pRecords[0].nMaxField,
    3524             :                                   sizeof(*(hMMFeature->pRecords[0].pField)))))
    3525           0 :         return 1;
    3526             : 
    3527          83 :     return 0;
    3528             : }
    3529             : 
    3530             : // Conserves all allocated memory but resets the information
    3531         552 : void MMResetFeatureGeometry(struct MiraMonFeature *hMMFeature)
    3532             : {
    3533         552 :     if (hMMFeature->pNCoordRing)
    3534             :     {
    3535         408 :         memset(hMMFeature->pNCoordRing, 0,
    3536         408 :                (size_t)hMMFeature->nMaxpNCoordRing *
    3537             :                    sizeof(*(hMMFeature->pNCoordRing)));
    3538             :     }
    3539         552 :     if (hMMFeature->pCoord)
    3540             :     {
    3541         408 :         memset(hMMFeature->pCoord, 0,
    3542         408 :                (size_t)hMMFeature->nMaxpCoord * sizeof(*(hMMFeature->pCoord)));
    3543             :     }
    3544         552 :     hMMFeature->nICoord = 0;
    3545         552 :     if (hMMFeature->pZCoord)
    3546             :     {
    3547         275 :         memset(hMMFeature->pZCoord, 0,
    3548         275 :                (size_t)hMMFeature->nMaxpZCoord *
    3549             :                    sizeof(*(hMMFeature->pZCoord)));
    3550             :     }
    3551         552 :     hMMFeature->nNRings = 0;
    3552         552 :     hMMFeature->nIRing = 0;
    3553             : 
    3554         552 :     if (hMMFeature->flag_VFG)
    3555             :     {
    3556         318 :         memset(hMMFeature->flag_VFG, 0,
    3557         318 :                (size_t)hMMFeature->nMaxVFG * sizeof(*(hMMFeature->flag_VFG)));
    3558             :     }
    3559         552 : }
    3560             : 
    3561             : // Preserves all allocated memory but initializes it to zero.
    3562         549 : void MMResetFeatureRecord(struct MiraMonFeature *hMMFeature)
    3563             : {
    3564             :     MM_EXT_DBF_N_MULTIPLE_RECORDS nIRecord;
    3565             :     MM_EXT_DBF_N_FIELDS nIField;
    3566             : 
    3567         549 :     if (!hMMFeature->pRecords)
    3568         340 :         return;
    3569             : 
    3570         448 :     for (nIRecord = 0; nIRecord < hMMFeature->nMaxMRecords; nIRecord++)
    3571             :     {
    3572         239 :         if (!hMMFeature->pRecords[nIRecord].pField)
    3573          25 :             continue;
    3574        4544 :         for (nIField = 0; nIField < hMMFeature->pRecords[nIRecord].nMaxField;
    3575        4330 :              nIField++)
    3576             :         {
    3577        4330 :             if (hMMFeature->pRecords[nIRecord].pField[nIField].pDinValue)
    3578         912 :                 *(hMMFeature->pRecords[nIRecord].pField[nIField].pDinValue) =
    3579             :                     '\0';
    3580        4330 :             hMMFeature->pRecords[nIRecord].pField[nIField].bIsValid = 0;
    3581             :         }
    3582         214 :         hMMFeature->pRecords[nIRecord].nNumField = 0;
    3583             :     }
    3584         209 :     hMMFeature->nNumMRecords = 0;
    3585             : }
    3586             : 
    3587             : // Destroys all allocated memory
    3588         203 : void MMDestroyFeature(struct MiraMonFeature *hMMFeature)
    3589             : {
    3590         203 :     if (hMMFeature->pCoord)
    3591             :     {
    3592          66 :         VSIFree(hMMFeature->pCoord);
    3593          66 :         hMMFeature->pCoord = nullptr;
    3594             :     }
    3595         203 :     if (hMMFeature->pZCoord)
    3596             :     {
    3597          66 :         VSIFree(hMMFeature->pZCoord);
    3598          66 :         hMMFeature->pZCoord = nullptr;
    3599             :     }
    3600         203 :     if (hMMFeature->pNCoordRing)
    3601             :     {
    3602          66 :         VSIFree(hMMFeature->pNCoordRing);
    3603          66 :         hMMFeature->pNCoordRing = nullptr;
    3604             :     }
    3605             : 
    3606         203 :     if (hMMFeature->flag_VFG)
    3607             :     {
    3608          27 :         VSIFree(hMMFeature->flag_VFG);
    3609          27 :         hMMFeature->flag_VFG = nullptr;
    3610             :     }
    3611             : 
    3612         203 :     if (hMMFeature->pRecords)
    3613             :     {
    3614             :         MM_EXT_DBF_N_MULTIPLE_RECORDS nIRecord;
    3615             :         MM_EXT_DBF_N_FIELDS nIField;
    3616             : 
    3617         260 :         for (nIRecord = 0; nIRecord < hMMFeature->nMaxMRecords; nIRecord++)
    3618             :         {
    3619         177 :             if (!hMMFeature->pRecords[nIRecord].pField)
    3620          75 :                 continue;
    3621         102 :             for (nIField = 0;
    3622        2272 :                  nIField < hMMFeature->pRecords[nIRecord].nMaxField; nIField++)
    3623             :             {
    3624        2170 :                 if (hMMFeature->pRecords[nIRecord].pField[nIField].pDinValue)
    3625         422 :                     VSIFree(hMMFeature->pRecords[nIRecord]
    3626         422 :                                 .pField[nIField]
    3627         422 :                                 .pDinValue);
    3628             :             }
    3629         102 :             VSIFree(hMMFeature->pRecords[nIRecord].pField);
    3630             :         }
    3631          83 :         VSIFree(hMMFeature->pRecords);
    3632          83 :         hMMFeature->pRecords = nullptr;
    3633             :     }
    3634             : 
    3635         203 :     hMMFeature->nNRings = 0;
    3636         203 :     hMMFeature->nNumMRecords = 0;
    3637         203 :     hMMFeature->nMaxMRecords = 0;
    3638         203 : }
    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          89 : static int MMCreateFeaturePoint(struct MiraMonVectLayerInfo *hMiraMonLayer,
    4378             :                                 struct MiraMonFeature *hMMFeature)
    4379             : {
    4380          89 :     double *pZ = nullptr;
    4381             :     struct MM_POINT_2D *pCoord;
    4382             :     MM_POLYGON_RINGS_COUNT nIPart;
    4383             :     MM_N_VERTICES_TYPE nIVertice, nCoord;
    4384          89 :     struct MM_ZD *pZDescription = nullptr;
    4385             :     MM_INTERNAL_FID nElemCount;
    4386             :     int result;
    4387             : 
    4388          89 :     if (!hMiraMonLayer)
    4389           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    4390             : 
    4391          89 :     if (!hMMFeature)
    4392           0 :         return MM_STOP_WRITING_FEATURES;
    4393             : 
    4394          89 :     if (hMiraMonLayer->TopHeader.bIs3d)
    4395          89 :         pZ = hMMFeature->pZCoord;
    4396             : 
    4397          89 :     nElemCount = hMiraMonLayer->TopHeader.nElemCount;
    4398         178 :     for (nIPart = 0, pCoord = hMMFeature->pCoord; nIPart < hMMFeature->nNRings;
    4399          89 :          nIPart++, nElemCount++)
    4400             :     {
    4401          89 :         nCoord = hMMFeature->pNCoordRing[nIPart];
    4402             : 
    4403             :         // Checking if its possible continue writing the file due
    4404             :         // to version limitations.
    4405          89 :         if (MMCheckVersionForFID(hMiraMonLayer,
    4406          89 :                                  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          89 :         if (hMiraMonLayer->TopHeader.bIs3d)
    4414             :         {
    4415          89 :             if (nElemCount == 0)
    4416             :             {
    4417          34 :                 if (MMCheckVersionFor3DOffset(hMiraMonLayer, (nElemCount + 1),
    4418             :                                               0, 0))
    4419           0 :                     return MM_STOP_WRITING_FEATURES;
    4420             :             }
    4421             :             else
    4422             :             {
    4423          55 :                 pZDescription = hMiraMonLayer->MMPoint.pZSection.pZDescription;
    4424          55 :                 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          55 :                 if (MMCheckVersionFor3DOffset(
    4432             :                         hMiraMonLayer, nElemCount + 1, 0,
    4433          55 :                         pZDescription[nElemCount - 1].nOffsetZ + sizeof(*pZ)))
    4434           0 :                     return MM_STOP_WRITING_FEATURES;
    4435             :             }
    4436             :         }
    4437             : 
    4438             :         // Doing real job
    4439             :         // Memory issues
    4440          89 :         if (hMiraMonLayer->TopHeader.bIs3d && pZ)
    4441             :         {
    4442          89 :             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          89 :             pZDescription = hMiraMonLayer->MMPoint.pZSection.pZDescription;
    4454          89 :             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          89 :             pZDescription[nElemCount].dfBBminz = *pZ;
    4462          89 :             pZDescription[nElemCount].dfBBmaxz = *pZ;
    4463             : 
    4464          89 :             if (hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBminz > *pZ)
    4465          41 :                 hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBminz = *pZ;
    4466          89 :             if (hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBmaxz < *pZ)
    4467          38 :                 hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBmaxz = *pZ;
    4468             : 
    4469             :             // Specification ask for a negative number.
    4470          89 :             pZDescription[nElemCount].nZCount = -1;
    4471          89 :             if (nElemCount == 0)
    4472          34 :                 pZDescription[nElemCount].nOffsetZ = 0;
    4473             :             else
    4474          55 :                 pZDescription[nElemCount].nOffsetZ =
    4475          55 :                     pZDescription[nElemCount - 1].nOffsetZ + sizeof(*pZ);
    4476             :         }
    4477             : 
    4478             :         // Flush settings
    4479          89 :         hMiraMonLayer->MMPoint.FlushTL.pBlockWhereToSaveOrRead =
    4480          89 :             (void *)hMiraMonLayer->MMPoint.pTL;
    4481          89 :         if (hMiraMonLayer->TopHeader.bIs3d)
    4482          89 :             hMiraMonLayer->MMPoint.pZSection.FlushZL.pBlockWhereToSaveOrRead =
    4483          89 :                 (void *)hMiraMonLayer->MMPoint.pZSection.pZL;
    4484             : 
    4485             :         // Dump point or points (MiraMon does not have multiple points)
    4486         178 :         for (nIVertice = 0; nIVertice < nCoord; nIVertice++, pCoord++)
    4487             :         {
    4488             :             // Updating the bounding box of the layer
    4489          89 :             MMUpdateBoundingBoxXY(&hMiraMonLayer->TopHeader.hBB, pCoord);
    4490             : 
    4491             :             // Adding the point at the memory block
    4492          89 :             hMiraMonLayer->MMPoint.FlushTL.SizeOfBlockToBeSaved =
    4493             :                 sizeof(pCoord->dfX);
    4494          89 :             hMiraMonLayer->MMPoint.FlushTL.pBlockToBeSaved =
    4495          89 :                 (void *)&pCoord->dfX;
    4496          89 :             if (MMAppendBlockToBuffer(&hMiraMonLayer->MMPoint.FlushTL))
    4497           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4498          89 :             hMiraMonLayer->MMPoint.FlushTL.pBlockToBeSaved =
    4499          89 :                 (void *)&pCoord->dfY;
    4500          89 :             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          89 :             if (hMiraMonLayer->TopHeader.bIs3d && pZ)
    4505             :             {
    4506          89 :                 hMiraMonLayer->MMPoint.pZSection.FlushZL.SizeOfBlockToBeSaved =
    4507             :                     sizeof(*pZ);
    4508          89 :                 hMiraMonLayer->MMPoint.pZSection.FlushZL.pBlockToBeSaved =
    4509             :                     (void *)pZ;
    4510          89 :                 if (MMAppendBlockToBuffer(
    4511             :                         &hMiraMonLayer->MMPoint.pZSection.FlushZL))
    4512           0 :                     return MM_FATAL_ERROR_WRITING_FEATURES;
    4513             : 
    4514          89 :                 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          89 :                 if (pZDescription[nElemCount].dfBBminz > *pZ)
    4522           0 :                     pZDescription[nElemCount].dfBBminz = *pZ;
    4523          89 :                 if (pZDescription[nElemCount].dfBBmaxz < *pZ)
    4524           0 :                     pZDescription[nElemCount].dfBBmaxz = *pZ;
    4525             : 
    4526          89 :                 if (hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBminz > *pZ)
    4527           0 :                     hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBminz = *pZ;
    4528          89 :                 if (hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBmaxz < *pZ)
    4529           0 :                     hMiraMonLayer->MMPoint.pZSection.ZHeader.dfBBmaxz = *pZ;
    4530             : 
    4531          89 :                 pZ++;
    4532             :             }
    4533             :         }
    4534             : 
    4535          89 :         if (hMiraMonLayer->TopHeader.nElemCount == 0)
    4536             :         {
    4537          34 :             if (MMCreateMMDB(hMiraMonLayer, hMMFeature->pCoord))
    4538           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    4539             :         }
    4540             : 
    4541          89 :         result = MMAddPointRecordToMMDB(hMiraMonLayer, hMMFeature, nElemCount);
    4542          89 :         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          89 :     hMiraMonLayer->TopHeader.nElemCount = nElemCount;
    4548             : 
    4549             :     // Everything OK.
    4550          89 :     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         797 : int MMCheckVersionForFID(struct MiraMonVectLayerInfo *hMiraMonLayer,
    4556             :                          MM_INTERNAL_FID FID)
    4557             : {
    4558         797 :     if (!hMiraMonLayer)
    4559           0 :         return 1;
    4560             : 
    4561         797 :     if (hMiraMonLayer->LayerVersion != MM_32BITS_VERSION)
    4562          56 :         return 0;
    4563             : 
    4564         741 :     if (FID >= MAXIMUM_OBJECT_INDEX_IN_2GB_VECTORS)
    4565           0 :         return 1;
    4566         741 :     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         176 : 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         176 :     if (!hMiraMonLayer)
    4598           0 :         return 1;
    4599             : 
    4600             :     // Checking if the final version is 1.1 or 2.0
    4601         176 :     if (hMiraMonLayer->LayerVersion != MM_32BITS_VERSION)
    4602           6 :         return 0;
    4603             : 
    4604             :     // User decided that if necessary, output version can be 2.0
    4605         170 :     if (hMiraMonLayer->bIsPoint)
    4606          83 :         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         170 :     LastOffset += MM_SIZE_OF_ZH;
    4614         170 :     LastOffset += nElemCount * MM_SIZE_OF_ZD_32_BITS;
    4615         170 :     LastOffset += nZLOffset;
    4616             : 
    4617         170 :     if (LastOffset < MAXIMUM_OFFSET_IN_2GB_VECTORS)
    4618         170 :         return 0;
    4619             : 
    4620           0 :     return 1;
    4621             : }
    4622             : 
    4623             : // Adds a feature in a MiraMon layer.
    4624         212 : int MMAddFeature(struct MiraMonVectLayerInfo *hMiraMonLayer,
    4625             :                  struct MiraMonFeature *hMiraMonFeature)
    4626             : {
    4627             :     int re;
    4628         212 :     MM_INTERNAL_FID previousFID = 0;
    4629             : 
    4630         212 :     if (!hMiraMonLayer)
    4631           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    4632             : 
    4633         212 :     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         212 :     if (hMiraMonFeature)
    4644         212 :         previousFID = hMiraMonLayer->TopHeader.nElemCount;
    4645             : 
    4646         212 :     if (hMiraMonLayer->bIsPoint)
    4647             :     {
    4648          89 :         re = MMCreateFeaturePoint(hMiraMonLayer, hMiraMonFeature);
    4649          89 :         if (hMiraMonFeature)
    4650             :         {
    4651          89 :             hMiraMonFeature->nReadFeatures =
    4652          89 :                 hMiraMonLayer->TopHeader.nElemCount - previousFID;
    4653             :         }
    4654          89 :         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         317 : void MMInitBoundingBox(struct MMBoundingBox *dfBB)
    4686             : {
    4687         317 :     if (!dfBB)
    4688           0 :         return;
    4689         317 :     dfBB->dfMinX = STATISTICAL_UNDEF_VALUE;
    4690         317 :     dfBB->dfMaxX = -STATISTICAL_UNDEF_VALUE;
    4691         317 :     dfBB->dfMinY = STATISTICAL_UNDEF_VALUE;
    4692         317 :     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         759 : void MMUpdateBoundingBoxXY(struct MMBoundingBox *dfBB,
    4715             :                            struct MM_POINT_2D *pCoord)
    4716             : {
    4717         759 :     if (!pCoord)
    4718           0 :         return;
    4719             : 
    4720         759 :     if (pCoord->dfX < dfBB->dfMinX)
    4721         267 :         dfBB->dfMinX = pCoord->dfX;
    4722             : 
    4723         759 :     if (pCoord->dfY < dfBB->dfMinY)
    4724         292 :         dfBB->dfMinY = pCoord->dfY;
    4725             : 
    4726         759 :     if (pCoord->dfX > dfBB->dfMaxX)
    4727         394 :         dfBB->dfMaxX = pCoord->dfX;
    4728             : 
    4729         759 :     if (pCoord->dfY > dfBB->dfMaxY)
    4730         354 :         dfBB->dfMaxY = pCoord->dfY;
    4731             : }
    4732             : 
    4733             : /* -------------------------------------------------------------------- */
    4734             : /*      Resize structures for reuse                                     */
    4735             : /* -------------------------------------------------------------------- */
    4736        1398 : 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        1398 :     if (nNum < *nMax)
    4747        1379 :         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         190 : 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         190 :     if (nNum < *nMax)
    4852         133 :         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        2656 : 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        2656 :     if (nNum < *nMax)
    4988        1193 :         return 0;
    4989             : 
    4990        1463 :     nPrevMax = *nMax;
    4991        1463 :     nNewMax = MAX(nNum + nIncr, nProposedMax);
    4992        1463 :     if (MMCheckSize_t(nNewMax, sizeof(**pVrt)))
    4993             :     {
    4994           0 :         return 1;
    4995             :     }
    4996        1463 :     if (nNewMax == 0 && *pVrt)
    4997           0 :         return 0;
    4998        1463 :     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        1463 :     *nMax = nNewMax;
    5006        1463 :     *pVrt = pTmp;
    5007             : 
    5008        1463 :     memset((*pVrt) + nPrevMax, 0, (size_t)(*nMax - nPrevMax) * sizeof(**pVrt));
    5009        1463 :     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        2669 : 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        2669 :     if (nNum < *nMax)
    5052        2284 :         return 0;
    5053             : 
    5054         385 :     nPrevMax = *nMax;
    5055         385 :     nNewMax = MAX(nNum + nIncr, nProposedMax);
    5056         385 :     if (MMCheckSize_t(nNewMax, sizeof(**pPoint2D)))
    5057             :     {
    5058           0 :         return 1;
    5059             :     }
    5060         385 :     if (nNewMax == 0 && *pPoint2D)
    5061           0 :         return 0;
    5062         385 :     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         385 :     *nMax = nNewMax;
    5071         385 :     *pPoint2D = pTmp;
    5072             : 
    5073         385 :     memset((*pPoint2D) + nPrevMax, 0,
    5074         385 :            (size_t)(*nMax - nPrevMax) * sizeof(**pPoint2D));
    5075         385 :     return 0;
    5076             : }
    5077             : 
    5078        1729 : 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        1729 :     if (nNum < *nMax)
    5086        1565 :         return 0;
    5087             : 
    5088         164 :     nPrevMax = *nMax;
    5089         164 :     nNewMax = MAX(nNum + nIncr, nProposedMax);
    5090         164 :     if (MMCheckSize_t(nNewMax, sizeof(**pDouble)))
    5091             :     {
    5092           0 :         return 1;
    5093             :     }
    5094         164 :     if (nNewMax == 0 && *pDouble)
    5095           0 :         return 0;
    5096         164 :     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         164 :     *nMax = nNewMax;
    5105         164 :     *pDouble = pTmp;
    5106             : 
    5107         164 :     memset((*pDouble) + nPrevMax, 0,
    5108         164 :            (size_t)(*nMax - nPrevMax) * sizeof(**pDouble));
    5109         164 :     return 0;
    5110             : }
    5111             : 
    5112       22943 : int MMResizeStringToOperateIfNeeded(struct MiraMonVectLayerInfo *hMiraMonLayer,
    5113             :                                     MM_EXT_DBF_N_FIELDS nNewSize)
    5114             : {
    5115       22943 :     if (!hMiraMonLayer)
    5116           0 :         return 1;
    5117             : 
    5118       22943 :     if (nNewSize >= hMiraMonLayer->nNumStringToOperate)
    5119             :     {
    5120             :         char *p;
    5121         444 :         if (MMCheckSize_t(nNewSize, 1))
    5122           0 :             return 1;
    5123         444 :         p = (char *)VSICalloc(1, (size_t)nNewSize);
    5124         444 :         if (!p)
    5125             :         {
    5126           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
    5127             :                      "Memory error in MiraMon "
    5128             :                      "driver (MMResizeStringToOperateIfNeeded())");
    5129           0 :             return 1;
    5130             :         }
    5131         444 :         VSIFree(hMiraMonLayer->szStringToOperate);
    5132         444 :         hMiraMonLayer->szStringToOperate = p;
    5133         444 :         hMiraMonLayer->nNumStringToOperate = nNewSize;
    5134             :     }
    5135       22943 :     return 0;
    5136             : }
    5137             : 
    5138             : // Checks if a string is empty
    5139        6354 : int MMIsEmptyString(const char *string)
    5140             : {
    5141        6354 :     const char *ptr = string;
    5142             : 
    5143       14635 :     for (; *ptr; ptr++)
    5144       13951 :         if (*ptr != ' ' && *ptr != '\t')
    5145        5670 :             return 0;
    5146             : 
    5147         684 :     return 1;
    5148             : }
    5149             : 
    5150             : /* -------------------------------------------------------------------- */
    5151             : /*      Metadata Functions                                              */
    5152             : /* -------------------------------------------------------------------- */
    5153             : 
    5154             : #define LineReturn "\r\n"
    5155             : 
    5156             : // Generates an identifier that REL 4 MiraMon metadata needs.
    5157         175 : 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         175 :     memset(aFileIdentifier, '\0', MM_MAX_LEN_LAYER_IDENTIFIER);
    5166             : 
    5167         175 :     aCharRand[0] = '_';
    5168         175 :     len_charset = (int)strlen(aCharset);
    5169        1225 :     for (i = 1; i < 7; i++)
    5170             :     {
    5171             : #ifndef __COVERITY__
    5172        1050 :         aCharRand[i] = aCharset[rand() % (len_charset - 1)];
    5173             : #else
    5174             :         aCharRand[i] = aCharset[i % (len_charset - 1)];
    5175             : #endif
    5176             :     }
    5177         175 :     aCharRand[7] = '\0';
    5178         175 :     CPLStrlcpy(aFileIdentifier, pMMFN, MM_MAX_LEN_LAYER_IDENTIFIER - 7);
    5179         175 :     strcat(aFileIdentifier, aCharRand);
    5180         175 :     return;
    5181             : }
    5182             : 
    5183             : // Converts a string from UTF-8 to ANSI to be written in a REL 4 file
    5184             : static void
    5185         751 : MMWrite_ANSI_MetadataKeyDescriptor(struct MiraMonVectorMetaData *hMMMD,
    5186             :                                    VSILFILE *pF, const char *pszEng,
    5187             :                                    const char *pszCat, const char *pszEsp)
    5188             : {
    5189         751 :     char *pszString = nullptr;
    5190             : 
    5191         751 :     switch (hMMMD->nMMLanguage)
    5192             :     {
    5193           3 :         case MM_CAT_LANGUAGE:
    5194           3 :             pszString = CPLRecode(pszCat, CPL_ENC_UTF8, CPL_ENC_ISO8859_1);
    5195           3 :             break;
    5196           3 :         case MM_SPA_LANGUAGE:
    5197           3 :             pszString = CPLRecode(pszEsp, CPL_ENC_UTF8, CPL_ENC_ISO8859_1);
    5198           3 :             break;
    5199         745 :         default:
    5200             :         case MM_ENG_LANGUAGE:
    5201         745 :             pszString = CPLRecode(pszEng, CPL_ENC_UTF8, CPL_ENC_ISO8859_1);
    5202         745 :             break;
    5203             :     }
    5204         751 :     if (pszString)
    5205             :     {
    5206         751 :         VSIFPrintfL(pF, "%s", KEY_descriptor);
    5207         751 :         VSIFPrintfL(pF, "=");
    5208         751 :         VSIFPrintfL(pF, "%s", pszString);
    5209         751 :         VSIFPrintfL(pF, "%s", LineReturn);
    5210         751 :         CPLFree(pszString);
    5211             :     }
    5212         751 : }
    5213             : 
    5214             : /*
    5215             :     Writes a MiraMon REL 4 metadata file. Next sections are included:
    5216             :     VERSION, METADADES, IDENTIFICATION, EXTENT, OVERVIEW,
    5217             :     TAULA_PRINCIPAL and GEOMETRIA_I_TOPOLOGIA
    5218             : 
    5219             :     Please, consult the meaning of all them at:
    5220             :     https://www.miramon.cat/help/eng/GeMPlus/ClausREL.htm
    5221             : */
    5222         175 : static int MMWriteMetadataFile(struct MiraMonVectorMetaData *hMMMD)
    5223             : {
    5224             :     char aMessage[MM_MESSAGE_LENGTH],
    5225             :         aFileIdentifier[MM_MAX_LEN_LAYER_IDENTIFIER], aMMIDSRS[MM_MAX_ID_SNY];
    5226             :     MM_EXT_DBF_N_FIELDS nIField;
    5227             :     VSILFILE *pF;
    5228             :     time_t currentTime;
    5229             :     char aTimeString[200];
    5230             : 
    5231         175 :     if (!hMMMD->aLayerName)
    5232           0 :         return 0;
    5233             : 
    5234         175 :     if (nullptr == (pF = VSIFOpenL(hMMMD->aLayerName, "wb")))
    5235             :     {
    5236           0 :         CPLError(CE_Failure, CPLE_OpenFailed, "The file %s must exist.",
    5237             :                  hMMMD->aLayerName);
    5238           0 :         return 1;
    5239             :     }
    5240             : 
    5241             :     // Writing MiraMon version section
    5242         175 :     VSIFPrintfL(pF, "[%s]" LineReturn, SECTION_VERSIO);
    5243             : 
    5244         175 :     VSIFPrintfL(pF, "%s=%u" LineReturn, KEY_Vers, (unsigned)MM_VERS);
    5245         175 :     VSIFPrintfL(pF, "%s=%u" LineReturn, KEY_SubVers, (unsigned)MM_SUBVERS);
    5246             : 
    5247         175 :     VSIFPrintfL(pF, "%s=%u" LineReturn, KEY_VersMetaDades,
    5248             :                 (unsigned)MM_VERS_METADADES);
    5249         175 :     VSIFPrintfL(pF, "%s=%u" LineReturn, KEY_SubVersMetaDades,
    5250             :                 (unsigned)MM_SUBVERS_METADADES);
    5251             : 
    5252             :     // Writing METADADES section
    5253         175 :     VSIFPrintfL(pF, "\r\n[%s]" LineReturn, SECTION_METADADES);
    5254         175 :     CPLStrlcpy(aMessage, hMMMD->aLayerName, sizeof(aMessage));
    5255         175 :     MMGenerateFileIdentifierFromMetadataFileName(aMessage, aFileIdentifier);
    5256         175 :     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_FileIdentifier, aFileIdentifier);
    5257         175 :     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_language, KEY_Value_eng);
    5258         175 :     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_MDIdiom, KEY_Value_eng);
    5259         175 :     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_characterSet,
    5260             :                 KEY_Value_characterSet);
    5261             : 
    5262             :     // Writing IDENTIFICATION section
    5263         175 :     VSIFPrintfL(pF, LineReturn "[%s]" LineReturn, SECTION_IDENTIFICATION);
    5264         175 :     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_code, aFileIdentifier);
    5265         175 :     VSIFPrintfL(pF, "%s=" LineReturn, KEY_codeSpace);
    5266         175 :     if (hMMMD->szLayerTitle && !MMIsEmptyString(hMMMD->szLayerTitle))
    5267             :     {
    5268         175 :         if (hMMMD->ePlainLT == MM_LayerType_Point)
    5269          34 :             VSIFPrintfL(pF, "%s=%s (pnt)" LineReturn, KEY_DatasetTitle,
    5270             :                         hMMMD->szLayerTitle);
    5271         175 :         if (hMMMD->ePlainLT == MM_LayerType_Arc)
    5272          57 :             VSIFPrintfL(pF, "%s=%s (arc)" LineReturn, KEY_DatasetTitle,
    5273             :                         hMMMD->szLayerTitle);
    5274         175 :         if (hMMMD->ePlainLT == MM_LayerType_Pol)
    5275          27 :             VSIFPrintfL(pF, "%s=%s (pol)" LineReturn, KEY_DatasetTitle,
    5276             :                         hMMMD->szLayerTitle);
    5277             :     }
    5278         175 :     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_language, KEY_Value_eng);
    5279             : 
    5280         175 :     if (hMMMD->ePlainLT != MM_LayerType_Node &&
    5281         118 :         hMMMD->ePlainLT != MM_LayerType_Pol)
    5282             :     {
    5283             :         // SPATIAL_REFERENCE_SYSTEM:HORIZONTAL
    5284          91 :         VSIFPrintfL(pF, LineReturn "[%s:%s]" LineReturn,
    5285             :                     SECTION_SPATIAL_REFERENCE_SYSTEM, SECTION_HORIZONTAL);
    5286         112 :         if (!ReturnMMIDSRSFromEPSGCodeSRS(hMMMD->pSRS, aMMIDSRS) &&
    5287          21 :             !MMIsEmptyString(aMMIDSRS))
    5288          21 :             VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_HorizontalSystemIdentifier,
    5289             :                         aMMIDSRS);
    5290             :         else
    5291             :         {
    5292          70 :             CPLError(CE_Warning, CPLE_NotSupported,
    5293             :                      "The MiraMon driver cannot assign any HRS.");
    5294             :             // Horizontal Reference System
    5295          70 :             VSIFPrintfL(pF, "%s=plane" LineReturn,
    5296             :                         KEY_HorizontalSystemIdentifier);
    5297          70 :             VSIFPrintfL(pF, "%s=local" LineReturn,
    5298             :                         KEY_HorizontalSystemDefinition);
    5299          70 :             if (hMMMD->pXUnit)
    5300           0 :                 VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_unitats, hMMMD->pXUnit);
    5301          70 :             if (hMMMD->pYUnit)
    5302             :             {
    5303           0 :                 if (!hMMMD->pXUnit || strcasecmp(hMMMD->pXUnit, hMMMD->pYUnit))
    5304           0 :                     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_unitatsY,
    5305             :                                 hMMMD->pYUnit);
    5306             :             }
    5307             :         }
    5308             : 
    5309             :         // SPATIAL_REFERENCE_SYSTEM:VERTICAL
    5310             :         // Llegim les unitats del Sist. ref. vertical
    5311          91 :         if (hMMMD->pZUnit)
    5312             :         {
    5313           0 :             VSIFPrintfL(pF, LineReturn "[%s:%s]" LineReturn,
    5314             :                         SECTION_SPATIAL_REFERENCE_SYSTEM, SECTION_VERTICAL);
    5315           0 :             VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_unitats, hMMMD->pZUnit);
    5316             :         }
    5317             :     }
    5318             : 
    5319         175 :     if (hMMMD->ePlainLT == MM_LayerType_Pol && hMMMD->aArcFile)
    5320             :     {
    5321             :         // Writing OVERVIEW:ASPECTES_TECNICS in polygon metadata file.
    5322             :         // ArcSource=fitx_pol.arc
    5323          27 :         VSIFPrintfL(pF, LineReturn "[%s]" LineReturn,
    5324             :                     SECTION_OVVW_ASPECTES_TECNICS);
    5325          27 :         VSIFPrintfL(pF, "%s=\"%s\"" LineReturn, KEY_ArcSource, hMMMD->aArcFile);
    5326             :     }
    5327         148 :     else if (hMMMD->ePlainLT == MM_LayerType_Arc && hMMMD->aArcFile)
    5328             :     {
    5329             :         // Writing OVERVIEW:ASPECTES_TECNICS in arc metadata file.
    5330             :         // Ciclat1=fitx_arc.pol
    5331          27 :         VSIFPrintfL(pF, LineReturn "[%s]" LineReturn,
    5332             :                     SECTION_OVVW_ASPECTES_TECNICS);
    5333          27 :         VSIFPrintfL(pF, "Ciclat1=\"%s\"" LineReturn, hMMMD->aArcFile);
    5334             :     }
    5335             : 
    5336             :     // Writing EXTENT section
    5337         175 :     VSIFPrintfL(pF, LineReturn "[%s]" LineReturn, SECTION_EXTENT);
    5338         175 :     VSIFPrintfL(pF, "%s=0" LineReturn, KEY_toler_env);
    5339             : 
    5340         175 :     if (hMMMD->hBB.dfMinX != MM_UNDEFINED_STATISTICAL_VALUE &&
    5341         175 :         hMMMD->hBB.dfMaxX != -MM_UNDEFINED_STATISTICAL_VALUE &&
    5342         175 :         hMMMD->hBB.dfMinY != MM_UNDEFINED_STATISTICAL_VALUE &&
    5343         175 :         hMMMD->hBB.dfMaxY != -MM_UNDEFINED_STATISTICAL_VALUE)
    5344             :     {
    5345         175 :         VSIFPrintfL(pF, "%s=%lf" LineReturn, KEY_MinX, hMMMD->hBB.dfMinX);
    5346         175 :         VSIFPrintfL(pF, "%s=%lf" LineReturn, KEY_MaxX, hMMMD->hBB.dfMaxX);
    5347         175 :         VSIFPrintfL(pF, "%s=%lf" LineReturn, KEY_MinY, hMMMD->hBB.dfMinY);
    5348         175 :         VSIFPrintfL(pF, "%s=%lf" LineReturn, KEY_MaxY, hMMMD->hBB.dfMaxY);
    5349             :     }
    5350             : 
    5351             :     // Writing OVERVIEW section
    5352         175 :     VSIFPrintfL(pF, LineReturn "[%s]" LineReturn, SECTION_OVERVIEW);
    5353             : 
    5354         175 :     currentTime = time(nullptr);
    5355             : 
    5356             :     struct tm ltime;
    5357         175 :     VSILocalTime(&currentTime, &ltime);
    5358         175 :     snprintf(aTimeString, sizeof(aTimeString), "%04d%02d%02d %02d%02d%02d%02d",
    5359         175 :              ltime.tm_year + 1900, ltime.tm_mon + 1, ltime.tm_mday,
    5360             :              ltime.tm_hour, ltime.tm_min, ltime.tm_sec, 0);
    5361         175 :     VSIFPrintfL(pF, "%s=%s" LineReturn, KEY_CreationDate, aTimeString);
    5362         175 :     VSIFPrintfL(pF, LineReturn);
    5363             : 
    5364             :     // Writing TAULA_PRINCIPAL section
    5365         175 :     VSIFPrintfL(pF, "[%s]" LineReturn, SECTION_TAULA_PRINCIPAL);
    5366         175 :     VSIFPrintfL(pF, "IdGrafic=%s" LineReturn, szMMNomCampIdGraficDefecte);
    5367         175 :     VSIFPrintfL(pF, "TipusRelacio=RELACIO_1_1_DICC" LineReturn);
    5368             : 
    5369         175 :     VSIFPrintfL(pF, LineReturn);
    5370         175 :     VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5371             :                 szMMNomCampIdGraficDefecte);
    5372         175 :     VSIFPrintfL(pF, "visible=0" LineReturn);
    5373         175 :     VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5374             : 
    5375         175 :     MMWrite_ANSI_MetadataKeyDescriptor(
    5376             :         hMMMD, pF, szInternalGraphicIdentifierEng,
    5377             :         szInternalGraphicIdentifierCat, szInternalGraphicIdentifierSpa);
    5378             : 
    5379         175 :     if (hMMMD->ePlainLT == MM_LayerType_Arc)
    5380             :     {
    5381          57 :         VSIFPrintfL(pF, LineReturn);
    5382          57 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5383             :                     szMMNomCampNVertexsDefecte);
    5384          57 :         VSIFPrintfL(pF, "visible=0" LineReturn);
    5385          57 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5386          57 :         MMWrite_ANSI_MetadataKeyDescriptor(hMMMD, pF, szNumberOfVerticesEng,
    5387             :                                            szNumberOfVerticesCat,
    5388             :                                            szNumberOfVerticesSpa);
    5389             : 
    5390          57 :         VSIFPrintfL(pF, LineReturn);
    5391          57 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5392             :                     szMMNomCampLongitudArcDefecte);
    5393          57 :         MMWrite_ANSI_MetadataKeyDescriptor(
    5394             :             hMMMD, pF, szLengthOfAarcEng, szLengthOfAarcCat, szLengthOfAarcSpa);
    5395             : 
    5396          57 :         VSIFPrintfL(pF, LineReturn);
    5397          57 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5398             :                     szMMNomCampNodeIniDefecte);
    5399          57 :         VSIFPrintfL(pF, "visible=0" LineReturn);
    5400          57 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5401          57 :         MMWrite_ANSI_MetadataKeyDescriptor(hMMMD, pF, szInitialNodeEng,
    5402             :                                            szInitialNodeCat, szInitialNodeSpa);
    5403             : 
    5404          57 :         VSIFPrintfL(pF, LineReturn);
    5405          57 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5406             :                     szMMNomCampNodeFiDefecte);
    5407          57 :         VSIFPrintfL(pF, "visible=0" LineReturn);
    5408          57 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5409          57 :         MMWrite_ANSI_MetadataKeyDescriptor(hMMMD, pF, szFinalNodeEng,
    5410             :                                            szFinalNodeCat, szFinalNodeSpa);
    5411             : 
    5412          57 :         VSIFPrintfL(pF, LineReturn);
    5413          57 :         VSIFPrintfL(pF, "[GEOMETRIA_I_TOPOLOGIA]" LineReturn);
    5414          57 :         VSIFPrintfL(pF, "NomCampNVertexs=%s" LineReturn,
    5415             :                     szMMNomCampNVertexsDefecte);
    5416          57 :         VSIFPrintfL(pF, "NomCampLongitudArc=%s" LineReturn,
    5417             :                     szMMNomCampLongitudArcDefecte);
    5418          57 :         VSIFPrintfL(pF, "NomCampNodeIni=%s" LineReturn,
    5419             :                     szMMNomCampNodeIniDefecte);
    5420          57 :         VSIFPrintfL(pF, "NomCampNodeFi=%s" LineReturn,
    5421             :                     szMMNomCampNodeFiDefecte);
    5422             :     }
    5423         118 :     else if (hMMMD->ePlainLT == MM_LayerType_Node)
    5424             :     {
    5425          57 :         VSIFPrintfL(pF, LineReturn);
    5426          57 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5427             :                     szMMNomCampArcsANodeDefecte);
    5428          57 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5429          57 :         MMWrite_ANSI_MetadataKeyDescriptor(hMMMD, pF, szNumberOfArcsToNodeEng,
    5430             :                                            szNumberOfArcsToNodeCat,
    5431             :                                            szNumberOfArcsToNodeSpa);
    5432             : 
    5433          57 :         VSIFPrintfL(pF, LineReturn);
    5434          57 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5435             :                     szMMNomCampTipusNodeDefecte);
    5436          57 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5437          57 :         MMWrite_ANSI_MetadataKeyDescriptor(hMMMD, pF, szNodeTypeEng,
    5438             :                                            szNodeTypeCat, szNodeTypeSpa);
    5439             : 
    5440          57 :         VSIFPrintfL(pF, LineReturn);
    5441          57 :         VSIFPrintfL(pF, "[GEOMETRIA_I_TOPOLOGIA]" LineReturn);
    5442          57 :         VSIFPrintfL(pF, "NomCampArcsANode=%s" LineReturn,
    5443             :                     szMMNomCampArcsANodeDefecte);
    5444          57 :         VSIFPrintfL(pF, "NomCampTipusNode=%s" LineReturn,
    5445             :                     szMMNomCampTipusNodeDefecte);
    5446             :     }
    5447          61 :     else if (hMMMD->ePlainLT == MM_LayerType_Pol)
    5448             :     {
    5449          27 :         VSIFPrintfL(pF, LineReturn);
    5450          27 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5451             :                     szMMNomCampNVertexsDefecte);
    5452          27 :         VSIFPrintfL(pF, "visible=0" LineReturn);
    5453          27 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5454          27 :         MMWrite_ANSI_MetadataKeyDescriptor(hMMMD, pF, szNumberOfVerticesEng,
    5455             :                                            szNumberOfVerticesCat,
    5456             :                                            szNumberOfVerticesSpa);
    5457             : 
    5458          27 :         VSIFPrintfL(pF, LineReturn);
    5459          27 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5460             :                     szMMNomCampPerimetreDefecte);
    5461          27 :         MMWrite_ANSI_MetadataKeyDescriptor(
    5462             :             hMMMD, pF, szPerimeterOfThePolygonEng, szPerimeterOfThePolygonCat,
    5463             :             szPerimeterOfThePolygonSpa);
    5464             : 
    5465          27 :         VSIFPrintfL(pF, LineReturn);
    5466          27 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5467             :                     szMMNomCampAreaDefecte);
    5468          27 :         MMWrite_ANSI_MetadataKeyDescriptor(hMMMD, pF, szAreaOfThePolygonEng,
    5469             :                                            szAreaOfThePolygonCat,
    5470             :                                            szAreaOfThePolygonSpa);
    5471             : 
    5472          27 :         VSIFPrintfL(pF, LineReturn);
    5473          27 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5474             :                     szMMNomCampNArcsDefecte);
    5475          27 :         VSIFPrintfL(pF, "visible=0" LineReturn);
    5476          27 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5477          27 :         MMWrite_ANSI_MetadataKeyDescriptor(
    5478             :             hMMMD, pF, szNumberOfArcsEng, szNumberOfArcsCat, szNumberOfArcsSpa);
    5479             : 
    5480          27 :         VSIFPrintfL(pF, LineReturn);
    5481          27 :         VSIFPrintfL(pF, "[%s:%s]" LineReturn, SECTION_TAULA_PRINCIPAL,
    5482             :                     szMMNomCampNPoligonsDefecte);
    5483          27 :         VSIFPrintfL(pF, "visible=0" LineReturn);
    5484          27 :         VSIFPrintfL(pF, "simbolitzable=0" LineReturn);
    5485          27 :         MMWrite_ANSI_MetadataKeyDescriptor(
    5486             :             hMMMD, pF, szNumberOfElementaryPolygonsEng,
    5487             :             szNumberOfElementaryPolygonsCat, szNumberOfElementaryPolygonsSpa);
    5488             : 
    5489          27 :         VSIFPrintfL(pF, LineReturn);
    5490          27 :         VSIFPrintfL(pF, "[GEOMETRIA_I_TOPOLOGIA]" LineReturn);
    5491          27 :         VSIFPrintfL(pF, "NomCampNVertexs=%s" LineReturn,
    5492             :                     szMMNomCampNVertexsDefecte);
    5493          27 :         VSIFPrintfL(pF, "NomCampPerimetre=%s" LineReturn,
    5494             :                     szMMNomCampPerimetreDefecte);
    5495          27 :         VSIFPrintfL(pF, "NomCampArea=%s" LineReturn, szMMNomCampAreaDefecte);
    5496          27 :         VSIFPrintfL(pF, "NomCampNArcs=%s" LineReturn, szMMNomCampNArcsDefecte);
    5497          27 :         VSIFPrintfL(pF, "NomCampNPoligons=%s" LineReturn,
    5498             :                     szMMNomCampNPoligonsDefecte);
    5499             :     }
    5500             : 
    5501         175 :     if (hMMMD->pLayerDB && hMMMD->pLayerDB->nNFields > 0)
    5502             :     {
    5503             :         // For each field of the databes
    5504         586 :         for (nIField = 0; nIField < hMMMD->pLayerDB->nNFields; nIField++)
    5505             :         {
    5506         495 :             VSIFPrintfL(pF, LineReturn "[%s:%s]" LineReturn,
    5507             :                         SECTION_TAULA_PRINCIPAL,
    5508         495 :                         hMMMD->pLayerDB->pFields[nIField].pszFieldName);
    5509             : 
    5510         495 :             if (!MMIsEmptyString(
    5511         594 :                     hMMMD->pLayerDB->pFields[nIField].pszFieldDescription) &&
    5512          99 :                 !MMIsEmptyString(
    5513          99 :                     hMMMD->pLayerDB->pFields[nIField].pszFieldName))
    5514             :             {
    5515          99 :                 MMWrite_ANSI_MetadataKeyDescriptor(
    5516             :                     hMMMD, pF,
    5517          99 :                     hMMMD->pLayerDB->pFields[nIField].pszFieldDescription,
    5518          99 :                     hMMMD->pLayerDB->pFields[nIField].pszFieldDescription,
    5519          99 :                     hMMMD->pLayerDB->pFields[nIField].pszFieldDescription);
    5520             :             }
    5521             : 
    5522             :             // Exception in a particular case: "altura" is a catalan word that means
    5523             :             // "height". Its unit by default will be "m" instead of "unknown".
    5524             :             // The same goes for "z", which easily means height.
    5525         495 :             if (EQUAL("altura",
    5526         495 :                       hMMMD->pLayerDB->pFields[nIField].pszFieldName) ||
    5527         495 :                 EQUAL("z", hMMMD->pLayerDB->pFields[nIField].pszFieldName))
    5528             :             {
    5529           0 :                 VSIFPrintfL(pF, "unitats=m" LineReturn);
    5530             :             }
    5531             :             else
    5532             :             {
    5533             :                 // By default units of field values will not be shown.
    5534         495 :                 VSIFPrintfL(pF, "MostrarUnitats=0" LineReturn);
    5535             :             }
    5536             :         }
    5537             :     }
    5538         175 :     VSIFCloseL(pF);
    5539         175 :     return 0;
    5540             : }
    5541             : 
    5542             : // Writes metadata files for MiraMon vector layers
    5543         192 : static int MMWriteVectorMetadataFile(struct MiraMonVectLayerInfo *hMiraMonLayer,
    5544             :                                      int layerPlainType, int layerMainPlainType)
    5545             : {
    5546             :     struct MiraMonVectorMetaData hMMMD;
    5547             : 
    5548         192 :     if (!hMiraMonLayer)
    5549           0 :         return 1;
    5550             : 
    5551             :     // MiraMon writes a REL file of each .pnt, .arc, .nod or .pol
    5552         192 :     memset(&hMMMD, 0, sizeof(hMMMD));
    5553         192 :     hMMMD.ePlainLT = layerPlainType;
    5554         192 :     hMMMD.pSRS = hMiraMonLayer->pSRS;
    5555         192 :     hMMMD.pZUnit = hMiraMonLayer->pZUnit;
    5556         192 :     hMMMD.nMMLanguage = hMiraMonLayer->nMMLanguage;
    5557             : 
    5558         192 :     hMMMD.szLayerTitle = hMiraMonLayer->szLayerTitle;
    5559         192 :     if (layerPlainType == MM_LayerType_Point)
    5560             :     {
    5561          34 :         hMMMD.aLayerName = hMiraMonLayer->MMPoint.pszREL_LayerName;
    5562          34 :         if (MMIsEmptyString(hMMMD.aLayerName))
    5563           0 :             return 0;  // If no file, no error. Just continue.
    5564          34 :         memcpy(&hMMMD.hBB, &hMiraMonLayer->TopHeader.hBB, sizeof(hMMMD.hBB));
    5565          34 :         hMMMD.pLayerDB = hMiraMonLayer->pLayerDB;
    5566          34 :         return MMWriteMetadataFile(&hMMMD);
    5567             :     }
    5568         158 :     else if (layerPlainType == MM_LayerType_Arc)
    5569             :     {
    5570             :         int nResult;
    5571             : 
    5572             :         // Arcs and not polygons
    5573          57 :         if (layerMainPlainType == MM_LayerType_Arc)
    5574             :         {
    5575          30 :             hMMMD.aLayerName = hMiraMonLayer->MMArc.pszREL_LayerName;
    5576          30 :             if (MMIsEmptyString(hMMMD.aLayerName))
    5577           0 :                 return 0;  // If no file, no error. Just continue.
    5578          30 :             memcpy(&hMMMD.hBB, &hMiraMonLayer->TopHeader.hBB,
    5579             :                    sizeof(hMMMD.hBB));
    5580          30 :             hMMMD.pLayerDB = hMiraMonLayer->pLayerDB;
    5581             :         }
    5582             :         // Arcs and polygons
    5583             :         else
    5584             :         {
    5585             :             // Arc from polygon
    5586          27 :             hMMMD.aLayerName = hMiraMonLayer->MMPolygon.MMArc.pszREL_LayerName;
    5587          27 :             if (MMIsEmptyString(hMMMD.aLayerName))
    5588           0 :                 return 0;  // If no file, no error. Just continue.
    5589             : 
    5590          27 :             memcpy(&hMMMD.hBB, &hMiraMonLayer->MMPolygon.TopArcHeader.hBB,
    5591             :                    sizeof(hMMMD.hBB));
    5592          27 :             hMMMD.pLayerDB = nullptr;
    5593          27 :             hMMMD.aArcFile = CPLStrdup(
    5594          27 :                 CPLGetFilename(hMiraMonLayer->MMPolygon.pszLayerName));
    5595             :         }
    5596          57 :         nResult = MMWriteMetadataFile(&hMMMD);
    5597          57 :         VSIFree(hMMMD.aArcFile);
    5598          57 :         return nResult;
    5599             :     }
    5600         101 :     else if (layerPlainType == MM_LayerType_Pol)
    5601             :     {
    5602             :         int nResult;
    5603             : 
    5604          27 :         hMMMD.aLayerName = hMiraMonLayer->MMPolygon.pszREL_LayerName;
    5605             : 
    5606          27 :         if (MMIsEmptyString(hMMMD.aLayerName))
    5607           0 :             return 0;  // If no file, no error. Just continue.
    5608             : 
    5609          27 :         memcpy(&hMMMD.hBB, &hMiraMonLayer->TopHeader.hBB, sizeof(hMMMD.hBB));
    5610          27 :         hMMMD.pLayerDB = hMiraMonLayer->pLayerDB;
    5611          27 :         hMMMD.aArcFile = CPLStrdup(
    5612          27 :             CPLGetFilename(hMiraMonLayer->MMPolygon.MMArc.pszLayerName));
    5613          27 :         nResult = MMWriteMetadataFile(&hMMMD);
    5614          27 :         VSIFree(hMMMD.aArcFile);
    5615          27 :         return nResult;
    5616             :     }
    5617          74 :     else if (layerPlainType == MM_LayerType_Node)
    5618             :     {
    5619             :         // Node from arc
    5620          57 :         if (layerMainPlainType == MM_LayerType_Arc)
    5621             :         {
    5622          30 :             hMMMD.aLayerName = hMiraMonLayer->MMArc.MMNode.pszREL_LayerName;
    5623          30 :             if (MMIsEmptyString(hMMMD.aLayerName))
    5624           0 :                 return 0;  // If no file, no error. Just continue.
    5625          30 :             memcpy(&hMMMD.hBB, &hMiraMonLayer->MMArc.TopNodeHeader.hBB,
    5626             :                    sizeof(hMMMD.hBB));
    5627             :         }
    5628             :         else  // Node from polygon
    5629             :         {
    5630          27 :             hMMMD.aLayerName =
    5631          27 :                 hMiraMonLayer->MMPolygon.MMArc.MMNode.pszREL_LayerName;
    5632          27 :             if (MMIsEmptyString(hMMMD.aLayerName))
    5633           0 :                 return 0;  // If no file, no error. Just continue.
    5634          27 :             memcpy(&hMMMD.hBB,
    5635          27 :                    &hMiraMonLayer->MMPolygon.MMArc.TopNodeHeader.hBB,
    5636             :                    sizeof(hMMMD.hBB));
    5637             :         }
    5638          57 :         hMMMD.pLayerDB = nullptr;
    5639          57 :         return MMWriteMetadataFile(&hMMMD);
    5640             :     }
    5641          17 :     return 0;
    5642             : }
    5643             : 
    5644         108 : int MMWriteVectorMetadata(struct MiraMonVectLayerInfo *hMiraMonLayer)
    5645             : {
    5646         108 :     if (!hMiraMonLayer)
    5647           0 :         return 1;
    5648             : 
    5649         108 :     if (hMiraMonLayer->bIsPoint)
    5650          34 :         return MMWriteVectorMetadataFile(hMiraMonLayer, MM_LayerType_Point,
    5651             :                                          MM_LayerType_Point);
    5652          74 :     if (hMiraMonLayer->bIsArc && !hMiraMonLayer->bIsPolygon)
    5653             :     {
    5654          30 :         if (MMWriteVectorMetadataFile(hMiraMonLayer, MM_LayerType_Node,
    5655             :                                       MM_LayerType_Arc))
    5656           0 :             return 1;
    5657          30 :         return MMWriteVectorMetadataFile(hMiraMonLayer, MM_LayerType_Arc,
    5658             :                                          MM_LayerType_Arc);
    5659             :     }
    5660          44 :     if (hMiraMonLayer->bIsPolygon)
    5661             :     {
    5662          27 :         if (MMWriteVectorMetadataFile(hMiraMonLayer, MM_LayerType_Node,
    5663             :                                       MM_LayerType_Pol))
    5664           0 :             return 1;
    5665          27 :         if (MMWriteVectorMetadataFile(hMiraMonLayer, MM_LayerType_Arc,
    5666             :                                       MM_LayerType_Pol))
    5667           0 :             return 1;
    5668          27 :         return MMWriteVectorMetadataFile(hMiraMonLayer, MM_LayerType_Pol,
    5669             :                                          MM_LayerType_Pol);
    5670             :     }
    5671          17 :     if (hMiraMonLayer->bIsDBF)
    5672             :     {
    5673          17 :         return MMWriteVectorMetadataFile(hMiraMonLayer, MM_LayerType_Unknown,
    5674             :                                          MM_LayerType_Unknown);
    5675             :     }
    5676           0 :     return 0;
    5677             : }
    5678             : 
    5679             : /* -------------------------------------------------------------------- */
    5680             : /*      MiraMon database functions                                      */
    5681             : /* -------------------------------------------------------------------- */
    5682             : 
    5683             : // Initializes a MiraMon database associated with a vector layer:
    5684             : // Sets the usual fields that MiraMon needs and after them, adds
    5685             : // all fields of the input layer
    5686         192 : static int MMInitMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    5687             :                       struct MMAdmDatabase *pMMAdmDB)
    5688             : {
    5689         192 :     if (!hMiraMonLayer || !pMMAdmDB)
    5690           0 :         return 1;
    5691             : 
    5692         192 :     if (MMIsEmptyString(pMMAdmDB->pszExtDBFLayerName))
    5693           0 :         return 0;  // No file, no error. Just continue
    5694             : 
    5695         192 :     strcpy(pMMAdmDB->pMMBDXP->ReadingMode, "wb+");
    5696         192 :     if (FALSE == MM_CreateAndOpenDBFFile(pMMAdmDB->pMMBDXP,
    5697         192 :                                          pMMAdmDB->pszExtDBFLayerName))
    5698             :     {
    5699           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
    5700             :                  "Error pMMAdmDB: Cannot create or open file %s.",
    5701           0 :                  pMMAdmDB->pszExtDBFLayerName);
    5702           0 :         return 1;
    5703             :     }
    5704             : 
    5705         192 :     VSIFSeekL(pMMAdmDB->pMMBDXP->pfDataBase,
    5706         192 :               pMMAdmDB->pMMBDXP->FirstRecordOffset, SEEK_SET);
    5707             : 
    5708         192 :     if (MMInitFlush(&pMMAdmDB->FlushRecList, pMMAdmDB->pMMBDXP->pfDataBase,
    5709             :                     MM_1MB, &pMMAdmDB->pRecList,
    5710         192 :                     pMMAdmDB->pMMBDXP->FirstRecordOffset, 0))
    5711           0 :         return 1;
    5712             : 
    5713         192 :     pMMAdmDB->nNumRecordOnCourse =
    5714         192 :         (GUInt64)pMMAdmDB->pMMBDXP->BytesPerRecord + 1;
    5715         192 :     if (MMCheckSize_t(pMMAdmDB->nNumRecordOnCourse, 1))
    5716           0 :         return 1;
    5717         192 :     pMMAdmDB->szRecordOnCourse =
    5718         192 :         VSICalloc(1, (size_t)pMMAdmDB->nNumRecordOnCourse);
    5719         192 :     if (!pMMAdmDB->szRecordOnCourse)
    5720             :     {
    5721           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    5722             :                  "Memory error in MiraMon "
    5723             :                  "driver (MMInitMMDB())");
    5724           0 :         return 1;
    5725             :     }
    5726         192 :     return 0;
    5727             : }
    5728             : 
    5729             : // Creates a MiraMon database associated with a vector layer.
    5730             : // It determines the number of fields and initializes the database header
    5731             : // accordingly. Depending on the layer type (point, arc, polygon, or generic),
    5732             : // it defines the fields and initializes the corresponding MiraMon database
    5733             : // structures.
    5734         108 : int MMCreateMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    5735             :                  struct MM_POINT_2D *pFirstCoord)
    5736             : {
    5737         108 :     struct MM_DATA_BASE_XP *pBD_XP = nullptr, *pBD_XP_Aux = nullptr;
    5738             :     struct MM_FIELD MMField;
    5739             :     size_t nIFieldLayer;
    5740         108 :     MM_EXT_DBF_N_FIELDS nIField = 0;
    5741             :     MM_EXT_DBF_N_FIELDS nNFields;
    5742             : 
    5743         108 :     if (!hMiraMonLayer)
    5744           0 :         return 1;
    5745             : 
    5746             :     // If the SRS is unknown, we attempt to deduce the appropriate number
    5747             :     // of decimals to be used in the reserved fields as LONG_ARC, PERIMETRE,
    5748             :     // or AREA using the coordinate values. It's not 100% reliable, but it's a
    5749             :     // good approximation.
    5750         108 :     if (hMiraMonLayer->nSRSType == MM_SRS_LAYER_IS_UNKNOWN_TYPE && pFirstCoord)
    5751             :     {
    5752          70 :         if (pFirstCoord->dfX < -360 || pFirstCoord->dfX > 360)
    5753           8 :             hMiraMonLayer->nSRSType = MM_SRS_LAYER_IS_PROJECTED_TYPE;
    5754             :         else
    5755          62 :             hMiraMonLayer->nSRSType = MM_SRS_LAYER_IS_GEOGRAPHIC_TYPE;
    5756             :     }
    5757             : 
    5758         108 :     if (hMiraMonLayer->bIsPoint)
    5759             :     {
    5760          34 :         if (hMiraMonLayer->pLayerDB)
    5761          34 :             nNFields =
    5762          34 :                 MM_PRIVATE_POINT_DB_FIELDS + hMiraMonLayer->pLayerDB->nNFields;
    5763             :         else
    5764           0 :             nNFields = MM_PRIVATE_POINT_DB_FIELDS;
    5765             : 
    5766             :         // Before allocating new memory, there might be some previously allocated but unused memory.
    5767             :         // Let's free that memory first.
    5768          34 :         if (hMiraMonLayer->MMPoint.MMAdmDB.pMMBDXP)
    5769           0 :             MM_ReleaseDBFHeader(&hMiraMonLayer->MMPoint.MMAdmDB.pMMBDXP);
    5770             : 
    5771          34 :         pBD_XP = hMiraMonLayer->MMPoint.MMAdmDB.pMMBDXP =
    5772          34 :             MM_CreateDBFHeader(nNFields, hMiraMonLayer->nCharSet);
    5773             : 
    5774          34 :         if (!pBD_XP)
    5775           0 :             return 1;
    5776             : 
    5777          34 :         if (0 == (nIField = (MM_EXT_DBF_N_FIELDS)MM_DefineFirstPointFieldsDB_XP(
    5778             :                       pBD_XP)))
    5779           0 :             return 1;
    5780             :     }
    5781          74 :     else if (hMiraMonLayer->bIsArc && !hMiraMonLayer->bIsPolygon)
    5782             :     {
    5783          30 :         if (hMiraMonLayer->pLayerDB)
    5784          30 :             nNFields =
    5785          30 :                 MM_PRIVATE_ARC_DB_FIELDS + hMiraMonLayer->pLayerDB->nNFields;
    5786             :         else
    5787           0 :             nNFields = MM_PRIVATE_ARC_DB_FIELDS;
    5788             : 
    5789             :         // Before allocating new memory, there might be some previously allocated but unused memory.
    5790             :         // Let's free that memory first.
    5791          30 :         if (hMiraMonLayer->MMArc.MMAdmDB.pMMBDXP)
    5792           0 :             MM_ReleaseDBFHeader(&hMiraMonLayer->MMArc.MMAdmDB.pMMBDXP);
    5793             : 
    5794          30 :         pBD_XP = hMiraMonLayer->MMArc.MMAdmDB.pMMBDXP =
    5795          30 :             MM_CreateDBFHeader(nNFields, hMiraMonLayer->nCharSet);
    5796             : 
    5797          30 :         if (!pBD_XP)
    5798           0 :             return 1;
    5799             : 
    5800          30 :         if (0 == (nIField = (MM_EXT_DBF_N_FIELDS)MM_DefineFirstArcFieldsDB_XP(
    5801             :                       pBD_XP,
    5802          30 :                       hMiraMonLayer->nSRSType == MM_SRS_LAYER_IS_PROJECTED_TYPE
    5803             :                           ? 3
    5804             :                           : 9)))
    5805           0 :             return 1;
    5806             : 
    5807             :         // Before allocating new memory, there might be some previously allocated but unused memory.
    5808             :         // Let's free that memory first.
    5809          30 :         if (hMiraMonLayer->MMArc.MMNode.MMAdmDB.pMMBDXP)
    5810           0 :             MM_ReleaseDBFHeader(&hMiraMonLayer->MMArc.MMNode.MMAdmDB.pMMBDXP);
    5811             : 
    5812          30 :         pBD_XP_Aux = hMiraMonLayer->MMArc.MMNode.MMAdmDB.pMMBDXP =
    5813          30 :             MM_CreateDBFHeader(3, hMiraMonLayer->nCharSet);
    5814             : 
    5815          30 :         if (!pBD_XP_Aux)
    5816           0 :             return 1;
    5817             : 
    5818          30 :         if (0 == MM_DefineFirstNodeFieldsDB_XP(pBD_XP_Aux))
    5819           0 :             return 1;
    5820             :     }
    5821          44 :     else if (hMiraMonLayer->bIsPolygon)
    5822             :     {
    5823          27 :         if (hMiraMonLayer->pLayerDB)
    5824          27 :             nNFields = MM_PRIVATE_POLYGON_DB_FIELDS +
    5825          27 :                        hMiraMonLayer->pLayerDB->nNFields;
    5826             :         else
    5827           0 :             nNFields = MM_PRIVATE_POLYGON_DB_FIELDS;
    5828             : 
    5829             :         // Before allocating new memory, there might be some previously allocated but unused memory.
    5830             :         // Let's free that memory first.
    5831          27 :         if (hMiraMonLayer->MMPolygon.MMAdmDB.pMMBDXP)
    5832           0 :             MM_ReleaseDBFHeader(&hMiraMonLayer->MMPolygon.MMAdmDB.pMMBDXP);
    5833             : 
    5834          27 :         pBD_XP = hMiraMonLayer->MMPolygon.MMAdmDB.pMMBDXP =
    5835          27 :             MM_CreateDBFHeader(nNFields, hMiraMonLayer->nCharSet);
    5836             : 
    5837          27 :         if (!pBD_XP)
    5838           0 :             return 1;
    5839             : 
    5840          27 :         if (0 ==
    5841          54 :             (nIField = (MM_EXT_DBF_N_FIELDS)MM_DefineFirstPolygonFieldsDB_XP(
    5842             :                  pBD_XP,
    5843          27 :                  hMiraMonLayer->nSRSType == MM_SRS_LAYER_IS_PROJECTED_TYPE ? 3
    5844             :                                                                            : 9,
    5845          27 :                  hMiraMonLayer->nSRSType == MM_SRS_LAYER_IS_PROJECTED_TYPE
    5846             :                      ? 3
    5847             :                      : 12)))
    5848           0 :             return 1;
    5849             : 
    5850             :         // Before allocating new memory, there might be some previously allocated but unused memory.
    5851             :         // Let's free that memory first.
    5852          27 :         if (hMiraMonLayer->MMPolygon.MMArc.MMAdmDB.pMMBDXP)
    5853           0 :             MM_ReleaseDBFHeader(
    5854             :                 &hMiraMonLayer->MMPolygon.MMArc.MMAdmDB.pMMBDXP);
    5855             : 
    5856          27 :         pBD_XP_Aux = hMiraMonLayer->MMPolygon.MMArc.MMAdmDB.pMMBDXP =
    5857          27 :             MM_CreateDBFHeader(5, hMiraMonLayer->nCharSet);
    5858             : 
    5859          27 :         if (!pBD_XP_Aux)
    5860           0 :             return 1;
    5861             : 
    5862          27 :         if (0 == MM_DefineFirstArcFieldsDB_XP(
    5863             :                      pBD_XP_Aux,
    5864          27 :                      hMiraMonLayer->nSRSType == MM_SRS_LAYER_IS_PROJECTED_TYPE
    5865             :                          ? 3
    5866             :                          : 9))
    5867           0 :             return 1;
    5868             : 
    5869             :         // Before allocating new memory, there might be some previously allocated but unused memory.
    5870             :         // Let's free that memory first.
    5871          27 :         if (hMiraMonLayer->MMPolygon.MMArc.MMNode.MMAdmDB.pMMBDXP)
    5872           0 :             MM_ReleaseDBFHeader(
    5873             :                 &hMiraMonLayer->MMPolygon.MMArc.MMNode.MMAdmDB.pMMBDXP);
    5874             : 
    5875          27 :         pBD_XP_Aux = hMiraMonLayer->MMPolygon.MMArc.MMNode.MMAdmDB.pMMBDXP =
    5876          27 :             MM_CreateDBFHeader(3, hMiraMonLayer->nCharSet);
    5877             : 
    5878          27 :         if (!pBD_XP_Aux)
    5879           0 :             return 1;
    5880             : 
    5881          27 :         if (0 == MM_DefineFirstNodeFieldsDB_XP(pBD_XP_Aux))
    5882           0 :             return 1;
    5883             :     }
    5884          17 :     else if (hMiraMonLayer->bIsDBF)
    5885             :     {
    5886             :         // Creating only a DBF
    5887          17 :         if (hMiraMonLayer->pLayerDB)
    5888          17 :             nNFields = hMiraMonLayer->pLayerDB->nNFields;
    5889             :         else
    5890           0 :             nNFields = 0;
    5891             : 
    5892          17 :         pBD_XP = hMiraMonLayer->MMAdmDBWriting.pMMBDXP =
    5893          17 :             MM_CreateDBFHeader(nNFields, hMiraMonLayer->nCharSet);
    5894             : 
    5895          17 :         if (!pBD_XP)
    5896           0 :             return 1;
    5897             :     }
    5898             :     else
    5899           0 :         return 0;
    5900             : 
    5901             :     // After private MiraMon fields, other fields are added.
    5902             :     // If names are no compatible, some changes are done.
    5903         108 :     if (hMiraMonLayer->pLayerDB)
    5904             :     {
    5905         684 :         for (nIFieldLayer = 0; nIField < nNFields; nIField++, nIFieldLayer++)
    5906             :         {
    5907         576 :             MM_InitializeField(&MMField);
    5908         576 :             CPLStrlcpy(
    5909             :                 MMField.FieldName,
    5910         576 :                 hMiraMonLayer->pLayerDB->pFields[nIFieldLayer].pszFieldName,
    5911             :                 MM_MAX_LON_FIELD_NAME_DBF);
    5912             : 
    5913         576 :             CPLStrlcpy(MMField.FieldDescription[0],
    5914         576 :                        hMiraMonLayer->pLayerDB->pFields[nIFieldLayer]
    5915         576 :                            .pszFieldDescription,
    5916             :                        MM_MAX_BYTES_FIELD_DESC);
    5917             : 
    5918         576 :             MMField.BytesPerField =
    5919         576 :                 hMiraMonLayer->pLayerDB->pFields[nIFieldLayer].nFieldSize;
    5920         576 :             switch (hMiraMonLayer->pLayerDB->pFields[nIFieldLayer].eFieldType)
    5921             :             {
    5922         283 :                 case MM_Numeric:
    5923         283 :                     MMField.FieldType = 'N';
    5924         283 :                     if (hMiraMonLayer->pLayerDB->pFields[nIFieldLayer]
    5925         283 :                             .bIs64BitInteger)
    5926          79 :                         MMField.Is64 = 1;
    5927         283 :                     if (MMField.BytesPerField == 0)
    5928           0 :                         MMField.BytesPerField = MM_MAX_AMPLADA_CAMP_N_DBF;
    5929         283 :                     break;
    5930         192 :                 case MM_Character:
    5931         192 :                     MMField.FieldType = 'C';
    5932         192 :                     if (MMField.BytesPerField == 0)
    5933           0 :                         MMField.BytesPerField = MM_MAX_AMPLADA_CAMP_C_DBF;
    5934         192 :                     break;
    5935          68 :                 case MM_Data:
    5936          68 :                     MMField.FieldType = 'D';
    5937          68 :                     if (MMField.BytesPerField == 0)
    5938           0 :                         MMField.BytesPerField = MM_MAX_AMPLADA_CAMP_D_DBF;
    5939          68 :                     break;
    5940          33 :                 case MM_Logic:
    5941          33 :                     MMField.FieldType = 'L';
    5942          33 :                     if (MMField.BytesPerField == 0)
    5943           0 :                         MMField.BytesPerField = 1;
    5944          33 :                     break;
    5945           0 :                 default:
    5946           0 :                     MMField.FieldType = 'C';
    5947           0 :                     if (MMField.BytesPerField == 0)
    5948           0 :                         MMField.BytesPerField = MM_MAX_AMPLADA_CAMP_C_DBF;
    5949             :             };
    5950             : 
    5951         576 :             MMField.DecimalsIfFloat =
    5952         576 :                 (MM_BYTE)hMiraMonLayer->pLayerDB->pFields[nIFieldLayer]
    5953         576 :                     .nNumberOfDecimals;
    5954             : 
    5955         576 :             MM_DuplicateFieldDBXP(pBD_XP->pField + nIField, &MMField);
    5956         576 :             MM_ModifyFieldNameAndDescriptorIfPresentBD_XP(
    5957         576 :                 pBD_XP->pField + nIField, pBD_XP, FALSE, 0);
    5958         576 :             if (pBD_XP->pField[nIField].FieldType == 'F')
    5959           0 :                 pBD_XP->pField[nIField].FieldType = 'N';
    5960             :         }
    5961             :     }
    5962             : 
    5963         108 :     if (hMiraMonLayer->bIsPoint)
    5964             :     {
    5965          34 :         if (MMInitMMDB(hMiraMonLayer, &hMiraMonLayer->MMPoint.MMAdmDB))
    5966           0 :             return 1;
    5967             :     }
    5968          74 :     else if (hMiraMonLayer->bIsArc && !hMiraMonLayer->bIsPolygon)
    5969             :     {
    5970          30 :         if (MMInitMMDB(hMiraMonLayer, &hMiraMonLayer->MMArc.MMAdmDB))
    5971           0 :             return 1;
    5972             : 
    5973          30 :         if (MMInitMMDB(hMiraMonLayer, &hMiraMonLayer->MMArc.MMNode.MMAdmDB))
    5974           0 :             return 1;
    5975             :     }
    5976          44 :     else if (hMiraMonLayer->bIsPolygon)
    5977             :     {
    5978          27 :         if (MMInitMMDB(hMiraMonLayer, &hMiraMonLayer->MMPolygon.MMAdmDB))
    5979           0 :             return 1;
    5980             : 
    5981          27 :         if (MMInitMMDB(hMiraMonLayer, &hMiraMonLayer->MMPolygon.MMArc.MMAdmDB))
    5982           0 :             return 1;
    5983             : 
    5984          27 :         if (MMInitMMDB(hMiraMonLayer,
    5985             :                        &hMiraMonLayer->MMPolygon.MMArc.MMNode.MMAdmDB))
    5986           0 :             return 1;
    5987             :     }
    5988          17 :     else if (hMiraMonLayer->bIsDBF)
    5989             :     {
    5990          17 :         if (MMInitMMDB(hMiraMonLayer, &hMiraMonLayer->MMAdmDBWriting))
    5991           0 :             return 1;
    5992             :     }
    5993         108 :     return 0;
    5994             : }
    5995             : 
    5996             : // Checks and fits the width of a specific field in a MiraMon database
    5997             : // associated with a vector layer. It examines the length of the provided
    5998             : // value and resizes the field width, if necessary, to accommodate the new
    5999             : // value. If the new width exceeds the current width of the field,
    6000             : // it updates the database structure, including the field width and
    6001             : // the size of the record. Additionally, it reallocates memory if needed
    6002             : // for the record handling buffer.
    6003             : 
    6004             : static int
    6005        2966 : MMTestAndFixValueToRecordDBXP(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6006             :                               struct MMAdmDatabase *pMMAdmDB,
    6007             :                               MM_EXT_DBF_N_FIELDS nIField, char *szValue)
    6008             : {
    6009             :     struct MM_FIELD *camp;
    6010             :     MM_BYTES_PER_FIELD_TYPE_DBF nNewWidth;
    6011             : 
    6012        2966 :     if (!hMiraMonLayer || !pMMAdmDB || !pMMAdmDB->pMMBDXP ||
    6013        2966 :         !pMMAdmDB->pMMBDXP->pField || !pMMAdmDB->pMMBDXP->pfDataBase)
    6014           0 :         return 1;
    6015             : 
    6016        2966 :     camp = pMMAdmDB->pMMBDXP->pField + nIField;
    6017             : 
    6018        2966 :     if (!szValue)
    6019         282 :         return 0;
    6020             : 
    6021        2684 :     nNewWidth = (MM_BYTES_PER_FIELD_TYPE_DBF)strlen(szValue);
    6022        2684 :     if (MMResizeStringToOperateIfNeeded(hMiraMonLayer, nNewWidth + 1))
    6023           0 :         return 1;
    6024             : 
    6025        2684 :     if (nNewWidth > camp->BytesPerField)
    6026             :     {
    6027         117 :         if (MM_WriteNRecordsMMBD_XPFile(pMMAdmDB))
    6028           0 :             return 1;
    6029             : 
    6030             :         // Flushing all to be flushed
    6031         117 :         pMMAdmDB->FlushRecList.SizeOfBlockToBeSaved = 0;
    6032         117 :         if (MMAppendBlockToBuffer(&pMMAdmDB->FlushRecList))
    6033           0 :             return 1;
    6034             : 
    6035         117 :         if (MM_ChangeDBFWidthField(
    6036             :                 pMMAdmDB->pMMBDXP, nIField, nNewWidth,
    6037         117 :                 pMMAdmDB->pMMBDXP->pField[nIField].DecimalsIfFloat))
    6038           0 :             return 1;
    6039             : 
    6040             :         // The record on course also has to change its size.
    6041         117 :         if ((GUInt64)pMMAdmDB->pMMBDXP->BytesPerRecord + 1 >=
    6042         117 :             pMMAdmDB->nNumRecordOnCourse)
    6043             :         {
    6044             :             void *pTmp;
    6045         117 :             if (nullptr == (pTmp = VSIRealloc(
    6046         117 :                                 pMMAdmDB->szRecordOnCourse,
    6047         117 :                                 (size_t)pMMAdmDB->pMMBDXP->BytesPerRecord + 1)))
    6048             :             {
    6049           0 :                 CPLError(CE_Failure, CPLE_OutOfMemory,
    6050             :                          "Memory error in MiraMon "
    6051             :                          "driver (MMTestAndFixValueToRecordDBXP())");
    6052           0 :                 return 1;
    6053             :             }
    6054         117 :             pMMAdmDB->szRecordOnCourse = pTmp;
    6055             :         }
    6056             : 
    6057             :         // File has changed its size, so it has to be updated
    6058             :         // at the Flush tool
    6059         117 :         VSIFSeekL(pMMAdmDB->pMMBDXP->pfDataBase, 0, SEEK_END);
    6060         117 :         pMMAdmDB->FlushRecList.OffsetWhereToFlush =
    6061         117 :             VSIFTellL(pMMAdmDB->pMMBDXP->pfDataBase);
    6062             :     }
    6063        2684 :     return 0;
    6064             : }
    6065             : 
    6066             : static int
    6067        3438 : MMWriteValueToszStringToOperate(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6068             :                                 const struct MM_FIELD *camp, const void *valor,
    6069             :                                 MM_BOOLEAN is_64)
    6070             : {
    6071        3438 :     if (!hMiraMonLayer)
    6072           0 :         return 1;
    6073             : 
    6074        3438 :     if (!camp)
    6075           0 :         return 0;
    6076             : 
    6077        3438 :     if (MMResizeStringToOperateIfNeeded(hMiraMonLayer,
    6078        3438 :                                         camp->BytesPerField + 10))
    6079           0 :         return 1;
    6080             : 
    6081        3438 :     if (!valor)
    6082           0 :         *hMiraMonLayer->szStringToOperate = '\0';
    6083             :     else
    6084             :     {
    6085        3438 :         if (camp->FieldType == 'N')
    6086             :         {
    6087        2840 :             if (!is_64)
    6088             :             {
    6089         962 :                 snprintf(hMiraMonLayer->szStringToOperate,
    6090         962 :                          (size_t)hMiraMonLayer->nNumStringToOperate, "%*.*f",
    6091         962 :                          camp->BytesPerField, camp->DecimalsIfFloat,
    6092             :                          *(const double *)valor);
    6093             :             }
    6094             :             else
    6095             :             {
    6096        1878 :                 snprintf(hMiraMonLayer->szStringToOperate,
    6097        1878 :                          (size_t)hMiraMonLayer->nNumStringToOperate, "%*lld",
    6098             :                          camp->BytesPerField, *(const GInt64 *)valor);
    6099             :             }
    6100             :         }
    6101             :         else
    6102             :         {
    6103         598 :             snprintf(hMiraMonLayer->szStringToOperate,
    6104         598 :                      (size_t)hMiraMonLayer->nNumStringToOperate, "%-*s",
    6105             :                      camp->BytesPerField, (const char *)valor);
    6106             :         }
    6107             :     }
    6108             : 
    6109        3438 :     return 0;
    6110             : }
    6111             : 
    6112         559 : int MMWritePreformatedNumberValueToRecordDBXP(
    6113             :     struct MiraMonVectLayerInfo *hMiraMonLayer, char *registre,
    6114             :     const struct MM_FIELD *camp, const char *valor)
    6115             : {
    6116         559 :     if (!hMiraMonLayer)
    6117           0 :         return 1;
    6118             : 
    6119         559 :     if (!camp)
    6120           0 :         return 0;
    6121             : 
    6122         559 :     if (MMResizeStringToOperateIfNeeded(hMiraMonLayer,
    6123         559 :                                         camp->BytesPerField + 10))
    6124           0 :         return 1;
    6125             : 
    6126         559 :     if (!valor)
    6127           0 :         memset(hMiraMonLayer->szStringToOperate, 0, camp->BytesPerField);
    6128             :     else
    6129             :     {
    6130         559 :         snprintf(hMiraMonLayer->szStringToOperate,
    6131         559 :                  (size_t)hMiraMonLayer->nNumStringToOperate, "%*s",
    6132             :                  camp->BytesPerField, valor);
    6133             :     }
    6134             : 
    6135         559 :     memcpy(registre + camp->AccumulatedBytes, hMiraMonLayer->szStringToOperate,
    6136         559 :            camp->BytesPerField);
    6137         559 :     return 0;
    6138             : }
    6139             : 
    6140        2124 : int MMWriteValueToRecordDBXP(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6141             :                              char *registre, const struct MM_FIELD *camp,
    6142             :                              const void *valor, MM_BOOLEAN is_64)
    6143             : {
    6144        2124 :     if (!hMiraMonLayer)
    6145           0 :         return 1;
    6146             : 
    6147        2124 :     if (!camp)
    6148           0 :         return 0;
    6149             : 
    6150        2124 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, camp, valor, is_64))
    6151           0 :         return 1;
    6152             : 
    6153        2124 :     memcpy(registre + camp->AccumulatedBytes, hMiraMonLayer->szStringToOperate,
    6154        2124 :            camp->BytesPerField);
    6155        2124 :     return 0;
    6156             : }
    6157             : 
    6158         212 : static int MMAddFeatureRecordToMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6159             :                                     struct MiraMonFeature *hMMFeature,
    6160             :                                     struct MMAdmDatabase *pMMAdmDB,
    6161             :                                     char *pszRecordOnCourse,
    6162             :                                     struct MM_FLUSH_INFO *pFlushRecList,
    6163             :                                     MM_EXT_DBF_N_RECORDS *nNumRecords,
    6164             :                                     MM_EXT_DBF_N_FIELDS nNumPrivateMMField)
    6165             : {
    6166             :     MM_EXT_DBF_N_MULTIPLE_RECORDS nIRecord;
    6167             :     MM_EXT_DBF_N_FIELDS nIField;
    6168         212 :     struct MM_DATA_BASE_XP *pBD_XP = nullptr;
    6169             : 
    6170         212 :     if (!hMiraMonLayer)
    6171           0 :         return 1;
    6172             : 
    6173         212 :     if (!hMMFeature)
    6174           0 :         return 1;
    6175             : 
    6176         212 :     pBD_XP = pMMAdmDB->pMMBDXP;
    6177         451 :     for (nIRecord = 0; nIRecord < hMMFeature->nNumMRecords; nIRecord++)
    6178             :     {
    6179        1891 :         for (nIField = 0; nIField < hMMFeature->pRecords[nIRecord].nNumField;
    6180        1652 :              nIField++)
    6181             :         {
    6182             :             // A field with no valid value is written as blank
    6183        1652 :             if (!hMMFeature->pRecords[nIRecord].pField[nIField].bIsValid)
    6184             :             {
    6185         283 :                 memset(
    6186         283 :                     pszRecordOnCourse +
    6187         283 :                         pBD_XP->pField[nIField + nNumPrivateMMField]
    6188         283 :                             .AccumulatedBytes,
    6189             :                     ' ',
    6190         283 :                     pBD_XP->pField[nIField + nNumPrivateMMField].BytesPerField);
    6191             : 
    6192         283 :                 continue;
    6193             :             }
    6194        1369 :             if (pBD_XP->pField[nIField + nNumPrivateMMField].FieldType == 'C' ||
    6195         983 :                 pBD_XP->pField[nIField + nNumPrivateMMField].FieldType == 'L' ||
    6196         880 :                 pBD_XP->pField[nIField + nNumPrivateMMField].FieldType == 'D')
    6197             :             {
    6198         598 :                 if (MMWriteValueToRecordDBXP(hMiraMonLayer, pszRecordOnCourse,
    6199         598 :                                              pBD_XP->pField + nIField +
    6200             :                                                  nNumPrivateMMField,
    6201         598 :                                              hMMFeature->pRecords[nIRecord]
    6202         598 :                                                  .pField[nIField]
    6203         598 :                                                  .pDinValue,
    6204             :                                              FALSE))
    6205           0 :                     return 1;
    6206             :             }
    6207         771 :             else if (pBD_XP->pField[nIField + nNumPrivateMMField].FieldType ==
    6208         771 :                          'N' &&
    6209         771 :                      !pBD_XP->pField[nIField + nNumPrivateMMField].Is64)
    6210             :             {
    6211         559 :                 if (MMWritePreformatedNumberValueToRecordDBXP(
    6212             :                         hMiraMonLayer, pszRecordOnCourse,
    6213         559 :                         pBD_XP->pField + nIField + nNumPrivateMMField,
    6214         559 :                         hMMFeature->pRecords[nIRecord]
    6215         559 :                             .pField[nIField]
    6216         559 :                             .pDinValue))
    6217           0 :                     return 1;
    6218             :             }
    6219         212 :             else if (pBD_XP->pField[nIField + nNumPrivateMMField].FieldType ==
    6220             :                      'N')
    6221             :             {
    6222         212 :                 if (pBD_XP->pField[nIField + nNumPrivateMMField].Is64)
    6223             :                 {
    6224         212 :                     if (MMWriteValueToRecordDBXP(
    6225             :                             hMiraMonLayer, pszRecordOnCourse,
    6226         212 :                             pBD_XP->pField + nIField + nNumPrivateMMField,
    6227         212 :                             &hMMFeature->pRecords[nIRecord]
    6228         212 :                                  .pField[nIField]
    6229             :                                  .iValue,
    6230             :                             TRUE))
    6231           0 :                         return 1;
    6232             :                 }
    6233             :             }
    6234             :         }
    6235             : 
    6236         239 :         if (MMAppendBlockToBuffer(pFlushRecList))
    6237           0 :             return 1;
    6238             : 
    6239         239 :         (*nNumRecords)++;
    6240             :     }
    6241         212 :     return 0;
    6242             : }
    6243             : 
    6244             : // Adds feature records to a MiraMon database associated with a vector layer.
    6245        1652 : static int MMDetectAndFixDBFWidthChange(
    6246             :     struct MiraMonVectLayerInfo *hMiraMonLayer,
    6247             :     struct MiraMonFeature *hMMFeature, struct MMAdmDatabase *pMMAdmDB,
    6248             :     MM_EXT_DBF_N_FIELDS nNumPrivateMMField,
    6249             :     MM_EXT_DBF_N_MULTIPLE_RECORDS nIRecord, MM_EXT_DBF_N_FIELDS nIField)
    6250             : {
    6251        1652 :     if (!hMiraMonLayer)
    6252           0 :         return 1;
    6253             : 
    6254        1652 :     if (!hMMFeature)
    6255           0 :         return 1;
    6256             : 
    6257        1652 :     if (nIRecord >= hMMFeature->nNumMRecords)
    6258           0 :         return 1;
    6259             : 
    6260        1652 :     if (nIField >= hMMFeature->pRecords[nIRecord].nNumField)
    6261           0 :         return 1;
    6262             : 
    6263        1652 :     if (MMTestAndFixValueToRecordDBXP(
    6264             :             hMiraMonLayer, pMMAdmDB, nIField + nNumPrivateMMField,
    6265        1652 :             hMMFeature->pRecords[nIRecord].pField[nIField].pDinValue))
    6266           0 :         return 1;
    6267             : 
    6268             :     // We analyze next fields
    6269        1652 :     if (nIField == hMMFeature->pRecords[nIRecord].nNumField - 1)
    6270             :     {
    6271         239 :         if (nIRecord + 1 < hMMFeature->nNumMRecords)
    6272             :         {
    6273          27 :             if (MMDetectAndFixDBFWidthChange(hMiraMonLayer, hMMFeature,
    6274             :                                              pMMAdmDB, nNumPrivateMMField,
    6275             :                                              nIRecord + 1, 0))
    6276           0 :                 return 1;
    6277             :         }
    6278             :         else
    6279         212 :             return 0;
    6280             :     }
    6281             :     else
    6282             :     {
    6283        1413 :         if (nIField + 1 < hMMFeature->pRecords[nIRecord].nNumField)
    6284             :         {
    6285        1413 :             if (MMDetectAndFixDBFWidthChange(hMiraMonLayer, hMMFeature,
    6286             :                                              pMMAdmDB, nNumPrivateMMField,
    6287             :                                              nIRecord, nIField + 1))
    6288           0 :                 return 1;
    6289             :         }
    6290             :         else
    6291           0 :             return 0;
    6292             :     }
    6293        1440 :     return 0;
    6294             : }  // End of MMDetectAndFixDBFWidthChange()
    6295             : 
    6296             : // Adds a DBF record to a MiraMon table associated with a vector layer.
    6297             : // It sets up flush settings for writing to the table and initializes
    6298             : // variables needed for the process. Then, it checks and fixes the width
    6299             : // change if necessary.
    6300          34 : int MMAddDBFRecordToMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6301             :                          struct MiraMonFeature *hMMFeature)
    6302             : {
    6303          34 :     struct MM_DATA_BASE_XP *pBD_XP = nullptr;
    6304          34 :     MM_EXT_DBF_N_FIELDS nNumPrivateMMField = 0;
    6305             :     struct MM_FLUSH_INFO *pFlushRecList;
    6306             : 
    6307          34 :     if (!hMiraMonLayer)
    6308           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6309             : 
    6310          34 :     pBD_XP = hMiraMonLayer->MMAdmDBWriting.pMMBDXP;
    6311             : 
    6312             :     // Test length
    6313          34 :     if (hMMFeature && hMMFeature->nNumMRecords &&
    6314          34 :         hMMFeature->pRecords[0].nNumField)
    6315             :     {
    6316          34 :         if (MMDetectAndFixDBFWidthChange(hMiraMonLayer, hMMFeature,
    6317             :                                          &hMiraMonLayer->MMAdmDBWriting,
    6318             :                                          nNumPrivateMMField, 0, 0))
    6319           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6320             :     }
    6321             : 
    6322             :     // Adding record to the MiraMon table (extended DBF)
    6323             :     // Flush settings
    6324          34 :     pFlushRecList = &hMiraMonLayer->MMAdmDBWriting.FlushRecList;
    6325          34 :     pFlushRecList->pBlockWhereToSaveOrRead =
    6326          34 :         (void *)hMiraMonLayer->MMAdmDBWriting.pRecList;
    6327             : 
    6328          34 :     pFlushRecList->pBlockToBeSaved =
    6329          34 :         (void *)hMiraMonLayer->MMAdmDBWriting.szRecordOnCourse;
    6330          34 :     pFlushRecList->SizeOfBlockToBeSaved = pBD_XP->BytesPerRecord;
    6331             : 
    6332          34 :     if (MMAddFeatureRecordToMMDB(
    6333             :             hMiraMonLayer, hMMFeature, &hMiraMonLayer->MMAdmDBWriting,
    6334             :             hMiraMonLayer->MMAdmDBWriting.szRecordOnCourse, pFlushRecList,
    6335          34 :             &hMiraMonLayer->MMAdmDBWriting.pMMBDXP->nRecords,
    6336             :             nNumPrivateMMField))
    6337           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6338             : 
    6339             :     // In this case, the number of features is also updated
    6340          34 :     hMiraMonLayer->TopHeader.nElemCount =
    6341          34 :         hMiraMonLayer->MMAdmDBWriting.pMMBDXP->nRecords;
    6342             : 
    6343          34 :     return MM_CONTINUE_WRITING_FEATURES;
    6344             : }
    6345             : 
    6346             : // Adds a point record to a MiraMon table associated with a vector layer.
    6347          89 : int MMAddPointRecordToMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6348             :                            struct MiraMonFeature *hMMFeature,
    6349             :                            MM_INTERNAL_FID nElemCount)
    6350             : {
    6351          89 :     struct MM_DATA_BASE_XP *pBD_XP = nullptr;
    6352          89 :     MM_EXT_DBF_N_FIELDS nNumPrivateMMField = MM_PRIVATE_POINT_DB_FIELDS;
    6353             :     struct MM_FLUSH_INFO *pFlushRecList;
    6354             : 
    6355          89 :     if (!hMiraMonLayer)
    6356           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6357             : 
    6358          89 :     if (!hMMFeature)
    6359           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6360             : 
    6361             :     // In V1.1 only _UI32_MAX records number is allowed
    6362          89 :     if (MMCheckVersionForFID(hMiraMonLayer,
    6363          89 :                              hMiraMonLayer->MMPoint.MMAdmDB.pMMBDXP->nRecords +
    6364          89 :                                  hMMFeature->nNumMRecords))
    6365             :     {
    6366           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    6367             :                  "Error in MMCheckVersionForFID() (6)");
    6368           0 :         return MM_STOP_WRITING_FEATURES;
    6369             :     }
    6370             : 
    6371          89 :     pBD_XP = hMiraMonLayer->MMPoint.MMAdmDB.pMMBDXP;
    6372             : 
    6373             :     // Test length
    6374             :     // Private fields
    6375             :     // ID_GRAFIC
    6376          89 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField,
    6377             :                                         &nElemCount, TRUE))
    6378           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6379          89 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer,
    6380             :                                       &hMiraMonLayer->MMPoint.MMAdmDB, 0,
    6381             :                                       hMiraMonLayer->szStringToOperate))
    6382           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6383             : 
    6384             :     // GDAL fields
    6385          89 :     if (hMMFeature->nNumMRecords && hMMFeature->pRecords[0].nNumField)
    6386             :     {
    6387          89 :         if (MMDetectAndFixDBFWidthChange(hMiraMonLayer, hMMFeature,
    6388             :                                          &hMiraMonLayer->MMPoint.MMAdmDB,
    6389             :                                          nNumPrivateMMField, 0, 0))
    6390           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6391             :     }
    6392             : 
    6393             :     // Now length is sure, write
    6394          89 :     memset(hMiraMonLayer->MMPoint.MMAdmDB.szRecordOnCourse, 0,
    6395          89 :            pBD_XP->BytesPerRecord);
    6396          89 :     MMWriteValueToRecordDBXP(hMiraMonLayer,
    6397             :                              hMiraMonLayer->MMPoint.MMAdmDB.szRecordOnCourse,
    6398          89 :                              pBD_XP->pField, &nElemCount, TRUE);
    6399             : 
    6400             :     // Adding record to the MiraMon table (extended DBF)
    6401             :     // Flush settings
    6402          89 :     pFlushRecList = &hMiraMonLayer->MMPoint.MMAdmDB.FlushRecList;
    6403          89 :     pFlushRecList->pBlockWhereToSaveOrRead =
    6404          89 :         (void *)hMiraMonLayer->MMPoint.MMAdmDB.pRecList;
    6405             : 
    6406          89 :     pFlushRecList->pBlockToBeSaved =
    6407          89 :         (void *)hMiraMonLayer->MMPoint.MMAdmDB.szRecordOnCourse;
    6408          89 :     pFlushRecList->SizeOfBlockToBeSaved = pBD_XP->BytesPerRecord;
    6409             : 
    6410          89 :     if (MMAddFeatureRecordToMMDB(
    6411             :             hMiraMonLayer, hMMFeature, &hMiraMonLayer->MMPoint.MMAdmDB,
    6412             :             hMiraMonLayer->MMPoint.MMAdmDB.szRecordOnCourse, pFlushRecList,
    6413          89 :             &hMiraMonLayer->MMPoint.MMAdmDB.pMMBDXP->nRecords,
    6414             :             nNumPrivateMMField))
    6415           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6416          89 :     return MM_CONTINUE_WRITING_FEATURES;
    6417             : }
    6418             : 
    6419             : // Adds a stringline record to a MiraMon table associated with a vector layer.
    6420         101 : int MMAddArcRecordToMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6421             :                          struct MiraMonFeature *hMMFeature,
    6422             :                          MM_INTERNAL_FID nElemCount, struct MM_AH *pArcHeader)
    6423             : {
    6424         101 :     struct MM_DATA_BASE_XP *pBD_XP = nullptr;
    6425             :     struct MiraMonArcLayer *pMMArcLayer;
    6426         101 :     MM_EXT_DBF_N_FIELDS nNumPrivateMMField = MM_PRIVATE_ARC_DB_FIELDS;
    6427             :     struct MM_FLUSH_INFO *pFlushRecList;
    6428             : 
    6429         101 :     if (!hMiraMonLayer)
    6430           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6431             : 
    6432         101 :     if (hMiraMonLayer->bIsPolygon)
    6433          53 :         pMMArcLayer = &hMiraMonLayer->MMPolygon.MMArc;
    6434             :     else
    6435          48 :         pMMArcLayer = &hMiraMonLayer->MMArc;
    6436             : 
    6437             :     // In V1.1 only _UI32_MAX records number is allowed
    6438         101 :     if (hMiraMonLayer->bIsPolygon)
    6439             :     {
    6440          53 :         if (MMCheckVersionForFID(hMiraMonLayer,
    6441          53 :                                  pMMArcLayer->MMAdmDB.pMMBDXP->nRecords + 1))
    6442             :         {
    6443           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    6444             :                      "Error in MMCheckVersionForFID() (7)");
    6445           0 :             return MM_STOP_WRITING_FEATURES;
    6446             :         }
    6447             :     }
    6448             :     else
    6449             :     {
    6450          48 :         if (MMCheckVersionForFID(hMiraMonLayer,
    6451          48 :                                  pMMArcLayer->MMAdmDB.pMMBDXP->nRecords +
    6452          48 :                                      hMMFeature->nNumMRecords))
    6453             :         {
    6454           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    6455             :                      "Error in MMCheckVersionForFID() (8)");
    6456           0 :             return MM_STOP_WRITING_FEATURES;
    6457             :         }
    6458             :     }
    6459             : 
    6460         101 :     pBD_XP = pMMArcLayer->MMAdmDB.pMMBDXP;
    6461             : 
    6462             :     // Test length
    6463             :     // Private fields
    6464             :     // ID_GRAFIC
    6465         101 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField,
    6466             :                                         &nElemCount, TRUE))
    6467           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6468         101 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMArcLayer->MMAdmDB, 0,
    6469             :                                       hMiraMonLayer->szStringToOperate))
    6470           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6471             : 
    6472             :     // N_VERTEXS
    6473         101 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 1,
    6474         101 :                                         &pArcHeader->nElemCount, TRUE))
    6475           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6476         101 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMArcLayer->MMAdmDB, 1,
    6477             :                                       hMiraMonLayer->szStringToOperate))
    6478           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6479             : 
    6480             :     // LENGTH
    6481         101 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 2,
    6482         101 :                                         &pArcHeader->dfLength, FALSE))
    6483           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6484         101 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMArcLayer->MMAdmDB, 2,
    6485             :                                       hMiraMonLayer->szStringToOperate))
    6486           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6487             : 
    6488             :     // NODE_INI
    6489         101 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 3,
    6490         101 :                                         &pArcHeader->nFirstIdNode, TRUE))
    6491           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6492         101 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMArcLayer->MMAdmDB, 3,
    6493             :                                       hMiraMonLayer->szStringToOperate))
    6494           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6495             : 
    6496             :     // NODE_FI
    6497         101 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 4,
    6498         101 :                                         &pArcHeader->nLastIdNode, TRUE))
    6499           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6500         101 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMArcLayer->MMAdmDB, 4,
    6501             :                                       hMiraMonLayer->szStringToOperate))
    6502           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6503             : 
    6504             :     // GDAL fields
    6505         101 :     if (!hMiraMonLayer->bIsPolygon)
    6506             :     {
    6507          48 :         if (hMMFeature->nNumMRecords && hMMFeature->pRecords[0].nNumField)
    6508             :         {
    6509          48 :             if (MMDetectAndFixDBFWidthChange(hMiraMonLayer, hMMFeature,
    6510             :                                              &pMMArcLayer->MMAdmDB,
    6511             :                                              nNumPrivateMMField, 0, 0))
    6512           0 :                 return MM_FATAL_ERROR_WRITING_FEATURES;
    6513             :         }
    6514             :     }
    6515             : 
    6516             :     // Now length is sure, write
    6517         101 :     memset(pMMArcLayer->MMAdmDB.szRecordOnCourse, 0, pBD_XP->BytesPerRecord);
    6518         101 :     MMWriteValueToRecordDBXP(hMiraMonLayer,
    6519             :                              pMMArcLayer->MMAdmDB.szRecordOnCourse,
    6520         101 :                              pBD_XP->pField, &nElemCount, TRUE);
    6521             : 
    6522         101 :     MMWriteValueToRecordDBXP(hMiraMonLayer,
    6523             :                              pMMArcLayer->MMAdmDB.szRecordOnCourse,
    6524         101 :                              pBD_XP->pField + 1, &pArcHeader->nElemCount, TRUE);
    6525             : 
    6526         101 :     MMWriteValueToRecordDBXP(hMiraMonLayer,
    6527             :                              pMMArcLayer->MMAdmDB.szRecordOnCourse,
    6528         101 :                              pBD_XP->pField + 2, &pArcHeader->dfLength, FALSE);
    6529             : 
    6530         101 :     MMWriteValueToRecordDBXP(
    6531             :         hMiraMonLayer, pMMArcLayer->MMAdmDB.szRecordOnCourse,
    6532         101 :         pBD_XP->pField + 3, &pArcHeader->nFirstIdNode, TRUE);
    6533             : 
    6534         101 :     MMWriteValueToRecordDBXP(
    6535             :         hMiraMonLayer, pMMArcLayer->MMAdmDB.szRecordOnCourse,
    6536         101 :         pBD_XP->pField + 4, &pArcHeader->nLastIdNode, TRUE);
    6537             : 
    6538             :     // Adding record to the MiraMon table (extended DBF)
    6539             :     // Flush settings
    6540         101 :     pFlushRecList = &pMMArcLayer->MMAdmDB.FlushRecList;
    6541         101 :     pFlushRecList->pBlockWhereToSaveOrRead =
    6542         101 :         (void *)pMMArcLayer->MMAdmDB.pRecList;
    6543             : 
    6544         101 :     pFlushRecList->SizeOfBlockToBeSaved = pBD_XP->BytesPerRecord;
    6545         101 :     pFlushRecList->pBlockToBeSaved =
    6546         101 :         (void *)pMMArcLayer->MMAdmDB.szRecordOnCourse;
    6547             : 
    6548         101 :     if (hMiraMonLayer->bIsPolygon)
    6549             :     {
    6550          53 :         if (MMAppendBlockToBuffer(pFlushRecList))
    6551           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6552          53 :         pMMArcLayer->MMAdmDB.pMMBDXP->nRecords++;
    6553          53 :         return MM_CONTINUE_WRITING_FEATURES;
    6554             :     }
    6555             : 
    6556          48 :     pFlushRecList->SizeOfBlockToBeSaved = pBD_XP->BytesPerRecord;
    6557          48 :     if (MMAddFeatureRecordToMMDB(
    6558             :             hMiraMonLayer, hMMFeature, &pMMArcLayer->MMAdmDB,
    6559             :             pMMArcLayer->MMAdmDB.szRecordOnCourse, pFlushRecList,
    6560          48 :             &pMMArcLayer->MMAdmDB.pMMBDXP->nRecords, nNumPrivateMMField))
    6561           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6562          48 :     return MM_CONTINUE_WRITING_FEATURES;
    6563             : }
    6564             : 
    6565             : // Adds a node record to a MiraMon table associated with a vector layer.
    6566         149 : int MMAddNodeRecordToMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6567             :                           MM_INTERNAL_FID nElemCount, struct MM_NH *pNodeHeader)
    6568             : {
    6569         149 :     struct MM_DATA_BASE_XP *pBD_XP = nullptr;
    6570             :     struct MiraMonNodeLayer *pMMNodeLayer;
    6571             :     double nDoubleValue;
    6572             : 
    6573         149 :     if (!hMiraMonLayer)
    6574           0 :         return 1;
    6575             : 
    6576         149 :     if (hMiraMonLayer->bIsPolygon)
    6577          53 :         pMMNodeLayer = &hMiraMonLayer->MMPolygon.MMArc.MMNode;
    6578             :     else
    6579          96 :         pMMNodeLayer = &hMiraMonLayer->MMArc.MMNode;
    6580             : 
    6581         149 :     if (!pMMNodeLayer)
    6582             :     {
    6583           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Error in pMMNodeLayer() (1)");
    6584           0 :         return MM_STOP_WRITING_FEATURES;
    6585             :     }
    6586             : 
    6587             :     // In V1.1 only _UI32_MAX records number is allowed
    6588         149 :     if (MMCheckVersionForFID(hMiraMonLayer,
    6589         149 :                              pMMNodeLayer->MMAdmDB.pMMBDXP->nRecords + 1))
    6590             :     {
    6591           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    6592             :                  "Error in MMCheckVersionForFID() (9)");
    6593           0 :         return MM_STOP_WRITING_FEATURES;
    6594             :     }
    6595             : 
    6596             :     // Test length
    6597             :     // Private fields
    6598             :     // ID_GRAFIC
    6599         149 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer,
    6600         149 :                                         pMMNodeLayer->MMAdmDB.pMMBDXP->pField,
    6601             :                                         &nElemCount, TRUE))
    6602           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6603         149 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMNodeLayer->MMAdmDB, 0,
    6604             :                                       hMiraMonLayer->szStringToOperate))
    6605           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6606             : 
    6607             :     // ARCS_A_NOD
    6608         149 :     nDoubleValue = pNodeHeader->nArcsCount;
    6609         149 :     if (MMWriteValueToszStringToOperate(
    6610         149 :             hMiraMonLayer, pMMNodeLayer->MMAdmDB.pMMBDXP->pField + 1,
    6611             :             &nDoubleValue, FALSE))
    6612           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6613         149 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMNodeLayer->MMAdmDB, 1,
    6614             :                                       hMiraMonLayer->szStringToOperate))
    6615           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6616             : 
    6617             :     // TIPUS_NODE
    6618         149 :     nDoubleValue = pNodeHeader->cNodeType;
    6619         149 :     if (MMWriteValueToszStringToOperate(
    6620         149 :             hMiraMonLayer, pMMNodeLayer->MMAdmDB.pMMBDXP->pField + 2,
    6621             :             &nDoubleValue, FALSE))
    6622           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6623         149 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer, &pMMNodeLayer->MMAdmDB, 2,
    6624             :                                       hMiraMonLayer->szStringToOperate))
    6625           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6626             : 
    6627             :     // Adding record to the MiraMon table (extended DBF)
    6628             :     // Flush settings
    6629         149 :     pMMNodeLayer->MMAdmDB.FlushRecList.pBlockWhereToSaveOrRead =
    6630         149 :         (void *)pMMNodeLayer->MMAdmDB.pRecList;
    6631             : 
    6632         149 :     pBD_XP = pMMNodeLayer->MMAdmDB.pMMBDXP;
    6633             : 
    6634         149 :     pMMNodeLayer->MMAdmDB.FlushRecList.SizeOfBlockToBeSaved =
    6635         149 :         pBD_XP->BytesPerRecord;
    6636         149 :     pMMNodeLayer->MMAdmDB.FlushRecList.pBlockToBeSaved =
    6637         149 :         (void *)pMMNodeLayer->MMAdmDB.szRecordOnCourse;
    6638             : 
    6639         149 :     memset(pMMNodeLayer->MMAdmDB.szRecordOnCourse, 0, pBD_XP->BytesPerRecord);
    6640         149 :     MMWriteValueToRecordDBXP(hMiraMonLayer,
    6641             :                              pMMNodeLayer->MMAdmDB.szRecordOnCourse,
    6642         149 :                              pBD_XP->pField, &nElemCount, TRUE);
    6643             : 
    6644         149 :     nDoubleValue = pNodeHeader->nArcsCount;
    6645         149 :     MMWriteValueToRecordDBXP(hMiraMonLayer,
    6646             :                              pMMNodeLayer->MMAdmDB.szRecordOnCourse,
    6647         149 :                              pBD_XP->pField + 1, &nDoubleValue, FALSE);
    6648             : 
    6649         149 :     nDoubleValue = pNodeHeader->cNodeType;
    6650         149 :     MMWriteValueToRecordDBXP(hMiraMonLayer,
    6651             :                              pMMNodeLayer->MMAdmDB.szRecordOnCourse,
    6652         149 :                              pBD_XP->pField + 2, &nDoubleValue, FALSE);
    6653             : 
    6654         149 :     if (MMAppendBlockToBuffer(&pMMNodeLayer->MMAdmDB.FlushRecList))
    6655           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6656         149 :     pMMNodeLayer->MMAdmDB.pMMBDXP->nRecords++;
    6657         149 :     return MM_CONTINUE_WRITING_FEATURES;
    6658             : }
    6659             : 
    6660             : // Adds a polygon or multipolygon record to a MiraMon table
    6661             : // associated with a vector layer.
    6662          68 : int MMAddPolygonRecordToMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6663             :                              struct MiraMonFeature *hMMFeature,
    6664             :                              MM_INTERNAL_FID nElemCount,
    6665             :                              MM_N_VERTICES_TYPE nVerticesCount,
    6666             :                              struct MM_PH *pPolHeader)
    6667             : {
    6668          68 :     struct MM_DATA_BASE_XP *pBD_XP = nullptr;
    6669          68 :     MM_EXT_DBF_N_FIELDS nNumPrivateMMField = MM_PRIVATE_POLYGON_DB_FIELDS;
    6670             :     struct MM_FLUSH_INFO *pFlushRecList;
    6671             : 
    6672          68 :     if (!hMiraMonLayer)
    6673           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6674             : 
    6675             :     // In V1.1 only _UI32_MAX records number is allowed
    6676          68 :     if (MMCheckVersionForFID(
    6677          68 :             hMiraMonLayer, hMiraMonLayer->MMPolygon.MMAdmDB.pMMBDXP->nRecords +
    6678          68 :                                (hMMFeature ? hMMFeature->nNumMRecords : 0)))
    6679           0 :         return MM_STOP_WRITING_FEATURES;
    6680             : 
    6681          68 :     pBD_XP = hMiraMonLayer->MMPolygon.MMAdmDB.pMMBDXP;
    6682             : 
    6683             :     // Test length
    6684             :     // Private fields
    6685             :     // ID_GRAFIC
    6686          68 :     if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField,
    6687             :                                         &nElemCount, TRUE))
    6688           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6689          68 :     if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer,
    6690             :                                       &hMiraMonLayer->MMPolygon.MMAdmDB, 0,
    6691             :                                       hMiraMonLayer->szStringToOperate))
    6692           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6693             : 
    6694             :     // The other fields are valid if pPolHeader exists (it is not
    6695             :     // the universal polygon)
    6696          68 :     if (pPolHeader)
    6697             :     {
    6698             :         // N_VERTEXS
    6699          41 :         if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 1,
    6700             :                                             &nVerticesCount, TRUE))
    6701           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6702          41 :         if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer,
    6703             :                                           &hMiraMonLayer->MMPolygon.MMAdmDB, 1,
    6704             :                                           hMiraMonLayer->szStringToOperate))
    6705           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6706             : 
    6707             :         // PERIMETER
    6708          41 :         if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 2,
    6709          41 :                                             &pPolHeader->dfPerimeter, FALSE))
    6710           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6711          41 :         if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer,
    6712             :                                           &hMiraMonLayer->MMPolygon.MMAdmDB, 2,
    6713             :                                           hMiraMonLayer->szStringToOperate))
    6714           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6715             : 
    6716             :         // AREA
    6717          41 :         if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 3,
    6718          41 :                                             &pPolHeader->dfArea, FALSE))
    6719           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6720          41 :         if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer,
    6721             :                                           &hMiraMonLayer->MMPolygon.MMAdmDB, 3,
    6722             :                                           hMiraMonLayer->szStringToOperate))
    6723           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6724             : 
    6725             :         // N_ARCS
    6726          41 :         if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 4,
    6727          41 :                                             &pPolHeader->nArcsCount, TRUE))
    6728           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6729          41 :         if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer,
    6730             :                                           &hMiraMonLayer->MMPolygon.MMAdmDB, 4,
    6731             :                                           hMiraMonLayer->szStringToOperate))
    6732           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6733             : 
    6734             :         // N_POLIG
    6735          41 :         if (MMWriteValueToszStringToOperate(hMiraMonLayer, pBD_XP->pField + 5,
    6736          41 :                                             &pPolHeader->nRingsCount, TRUE))
    6737           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6738          41 :         if (MMTestAndFixValueToRecordDBXP(hMiraMonLayer,
    6739             :                                           &hMiraMonLayer->MMPolygon.MMAdmDB, 5,
    6740             :                                           hMiraMonLayer->szStringToOperate))
    6741           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6742             :     }
    6743             : 
    6744             :     // GDAL fields
    6745          68 :     if (hMMFeature && hMMFeature->nNumMRecords &&
    6746          41 :         hMMFeature->pRecords[0].nNumField)
    6747             :     {
    6748          41 :         if (MMDetectAndFixDBFWidthChange(hMiraMonLayer, hMMFeature,
    6749             :                                          &hMiraMonLayer->MMPolygon.MMAdmDB,
    6750             :                                          nNumPrivateMMField, 0, 0))
    6751           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6752             :     }
    6753             : 
    6754             :     // Adding record to the MiraMon table (extended DBF)
    6755             :     // Flush settings
    6756          68 :     pFlushRecList = &hMiraMonLayer->MMPolygon.MMAdmDB.FlushRecList;
    6757          68 :     pFlushRecList->pBlockWhereToSaveOrRead =
    6758          68 :         (void *)hMiraMonLayer->MMPolygon.MMAdmDB.pRecList;
    6759             : 
    6760          68 :     pFlushRecList->SizeOfBlockToBeSaved = pBD_XP->BytesPerRecord;
    6761          68 :     pFlushRecList->pBlockToBeSaved =
    6762          68 :         (void *)hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse;
    6763             : 
    6764             :     // Now length is sure, write
    6765          68 :     memset(hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse, ' ',
    6766          68 :            pBD_XP->BytesPerRecord);
    6767          68 :     if (MMWriteValueToRecordDBXP(
    6768             :             hMiraMonLayer, hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse,
    6769          68 :             pBD_XP->pField, &nElemCount, TRUE))
    6770           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6771             : 
    6772          68 :     if (!hMMFeature)
    6773             :     {
    6774          27 :         if (MMAppendBlockToBuffer(pFlushRecList))
    6775           0 :             return MM_FATAL_ERROR_WRITING_FEATURES;
    6776          27 :         hMiraMonLayer->MMPolygon.MMAdmDB.pMMBDXP->nRecords++;
    6777          27 :         return MM_CONTINUE_WRITING_FEATURES;
    6778             :     }
    6779             : 
    6780          41 :     if (pPolHeader)
    6781             :     {
    6782          41 :         MMWriteValueToRecordDBXP(
    6783             :             hMiraMonLayer, hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse,
    6784          41 :             pBD_XP->pField + 1, &nVerticesCount, TRUE);
    6785             : 
    6786          41 :         MMWriteValueToRecordDBXP(
    6787             :             hMiraMonLayer, hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse,
    6788          41 :             pBD_XP->pField + 2, &pPolHeader->dfPerimeter, FALSE);
    6789             : 
    6790          41 :         MMWriteValueToRecordDBXP(
    6791             :             hMiraMonLayer, hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse,
    6792          41 :             pBD_XP->pField + 3, &pPolHeader->dfArea, FALSE);
    6793             : 
    6794          41 :         MMWriteValueToRecordDBXP(
    6795             :             hMiraMonLayer, hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse,
    6796          41 :             pBD_XP->pField + 4, &pPolHeader->nArcsCount, TRUE);
    6797             : 
    6798          41 :         MMWriteValueToRecordDBXP(
    6799             :             hMiraMonLayer, hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse,
    6800          41 :             pBD_XP->pField + 5, &pPolHeader->nRingsCount, TRUE);
    6801             :     }
    6802             : 
    6803          41 :     pFlushRecList->SizeOfBlockToBeSaved = pBD_XP->BytesPerRecord;
    6804          41 :     if (MMAddFeatureRecordToMMDB(
    6805             :             hMiraMonLayer, hMMFeature, &hMiraMonLayer->MMPolygon.MMAdmDB,
    6806             :             hMiraMonLayer->MMPolygon.MMAdmDB.szRecordOnCourse, pFlushRecList,
    6807          41 :             &hMiraMonLayer->MMPolygon.MMAdmDB.pMMBDXP->nRecords,
    6808             :             nNumPrivateMMField))
    6809           0 :         return MM_FATAL_ERROR_WRITING_FEATURES;
    6810          41 :     return MM_CONTINUE_WRITING_FEATURES;
    6811             : }
    6812             : 
    6813             : // Close the MiraMon database associated with a vector layer.
    6814         438 : static int MMCloseMMBD_XPFile(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6815             :                               struct MMAdmDatabase *MMAdmDB)
    6816             : {
    6817         438 :     int ret_code = 1;
    6818         438 :     if (!hMiraMonLayer)
    6819           0 :         return 1;
    6820             : 
    6821         438 :     if (hMiraMonLayer->ReadOrWrite == MM_WRITING_MODE)
    6822             :     {
    6823         192 :         if (!MMAdmDB->pMMBDXP ||
    6824         192 :             (MMAdmDB->pMMBDXP && !MMAdmDB->pMMBDXP->pfDataBase))
    6825             :         {
    6826             :             // In case of 0 elements created we have to
    6827             :             // create an empty DBF
    6828           0 :             if (hMiraMonLayer->bIsPolygon)
    6829             :             {
    6830           0 :                 if (hMiraMonLayer->TopHeader.nElemCount <= 1)
    6831             :                 {
    6832           0 :                     if (MMCreateMMDB(hMiraMonLayer, nullptr))
    6833             :                     {
    6834           0 :                         CPLError(CE_Failure, CPLE_OutOfMemory,
    6835             :                                  "Memory error in MiraMon "
    6836             :                                  "driver (MMCreateMMDB())");
    6837           0 :                         goto end_label;
    6838             :                     }
    6839             :                 }
    6840             :             }
    6841           0 :             else if (hMiraMonLayer->bIsPoint || hMiraMonLayer->bIsArc)
    6842             :             {
    6843           0 :                 if (hMiraMonLayer->TopHeader.nElemCount == 0)
    6844             :                 {
    6845           0 :                     if (MMCreateMMDB(hMiraMonLayer, nullptr))
    6846             :                     {
    6847           0 :                         CPLError(CE_Failure, CPLE_OutOfMemory,
    6848             :                                  "Memory error in MiraMon "
    6849             :                                  "driver (MMCreateMMDB())");
    6850           0 :                         goto end_label;
    6851             :                     }
    6852             :                 }
    6853             :             }
    6854             :         }
    6855             : 
    6856         192 :         if (MM_WriteNRecordsMMBD_XPFile(MMAdmDB))
    6857           0 :             goto end_label;
    6858             : 
    6859             :         // Flushing all to be flushed
    6860         192 :         MMAdmDB->FlushRecList.SizeOfBlockToBeSaved = 0;
    6861         192 :         if (MMAppendBlockToBuffer(&MMAdmDB->FlushRecList))
    6862           0 :             goto end_label;
    6863             :     }
    6864             : 
    6865         438 :     ret_code = 0;
    6866         438 : end_label:
    6867             :     // Closing database files
    6868         438 :     if (MMAdmDB && MMAdmDB->pMMBDXP && MMAdmDB->pMMBDXP->pfDataBase)
    6869         192 :         fclose_and_nullify(&MMAdmDB->pMMBDXP->pfDataBase);
    6870             : 
    6871         438 :     return ret_code;
    6872             : }
    6873             : 
    6874         228 : int MMCloseMMBD_XP(struct MiraMonVectLayerInfo *hMiraMonLayer)
    6875             : {
    6876         228 :     int ret_code = 0;
    6877         228 :     if (!hMiraMonLayer)
    6878           0 :         return 1;
    6879             : 
    6880         228 :     if (hMiraMonLayer->pMMBDXP && hMiraMonLayer->pMMBDXP->pfDataBase)
    6881             :     {
    6882         112 :         fclose_and_nullify(&hMiraMonLayer->pMMBDXP->pfDataBase);
    6883             :     }
    6884             : 
    6885         228 :     if (hMiraMonLayer->bIsPoint)
    6886             :         ret_code =
    6887          76 :             MMCloseMMBD_XPFile(hMiraMonLayer, &hMiraMonLayer->MMPoint.MMAdmDB);
    6888         152 :     else if (hMiraMonLayer->bIsArc && !hMiraMonLayer->bIsPolygon)
    6889             :     {
    6890          60 :         if (MMCloseMMBD_XPFile(hMiraMonLayer, &hMiraMonLayer->MMArc.MMAdmDB))
    6891           0 :             ret_code = 1;
    6892          60 :         if (MMCloseMMBD_XPFile(hMiraMonLayer,
    6893             :                                &hMiraMonLayer->MMArc.MMNode.MMAdmDB))
    6894           0 :             ret_code = 1;
    6895             :     }
    6896          92 :     else if (hMiraMonLayer->bIsPolygon)
    6897             :     {
    6898          75 :         if (MMCloseMMBD_XPFile(hMiraMonLayer,
    6899             :                                &hMiraMonLayer->MMPolygon.MMAdmDB))
    6900           0 :             ret_code = 1;
    6901          75 :         if (MMCloseMMBD_XPFile(hMiraMonLayer,
    6902             :                                &hMiraMonLayer->MMPolygon.MMArc.MMAdmDB))
    6903           0 :             ret_code = 1;
    6904          75 :         if (MMCloseMMBD_XPFile(hMiraMonLayer,
    6905             :                                &hMiraMonLayer->MMPolygon.MMArc.MMNode.MMAdmDB))
    6906           0 :             ret_code = 1;
    6907             :     }
    6908          17 :     else if (hMiraMonLayer->bIsDBF)
    6909             :         ret_code =
    6910          17 :             MMCloseMMBD_XPFile(hMiraMonLayer, &hMiraMonLayer->MMAdmDBWriting);
    6911             : 
    6912         228 :     return ret_code;
    6913             : }
    6914             : 
    6915             : // Destroys the memory used to create a MiraMon table associated
    6916             : // with a vector layer.
    6917         438 : static void MMDestroyMMDBFile(struct MiraMonVectLayerInfo *hMiraMonLayer,
    6918             :                               struct MMAdmDatabase *pMMAdmDB)
    6919             : {
    6920         438 :     if (!hMiraMonLayer)
    6921           0 :         return;
    6922             : 
    6923         438 :     if (pMMAdmDB && pMMAdmDB->szRecordOnCourse)
    6924             :     {
    6925          44 :         VSIFree(pMMAdmDB->szRecordOnCourse);
    6926          44 :         pMMAdmDB->szRecordOnCourse = nullptr;
    6927             :     }
    6928         438 :     if (hMiraMonLayer->szStringToOperate)
    6929             :     {
    6930           0 :         VSIFree(hMiraMonLayer->szStringToOperate);
    6931           0 :         hMiraMonLayer->szStringToOperate = nullptr;
    6932           0 :         hMiraMonLayer->nNumStringToOperate = 0;
    6933             :     }
    6934             : 
    6935         438 :     if (pMMAdmDB && pMMAdmDB->pMMBDXP)
    6936             :     {
    6937         309 :         MM_ReleaseDBFHeader(&pMMAdmDB->pMMBDXP);
    6938         309 :         hMiraMonLayer->pMMBDXP = nullptr;
    6939             :     }
    6940         438 :     if (pMMAdmDB && pMMAdmDB->pRecList)
    6941             :     {
    6942          44 :         VSIFree(pMMAdmDB->pRecList);
    6943          44 :         pMMAdmDB->pRecList = nullptr;
    6944             :     }
    6945             : }
    6946             : 
    6947         812 : void MMDestroyMMDB(struct MiraMonVectLayerInfo *hMiraMonLayer)
    6948             : {
    6949         812 :     if (!hMiraMonLayer)
    6950           0 :         return;
    6951             : 
    6952         812 :     if (hMiraMonLayer->bIsPoint)
    6953             :     {
    6954          76 :         MMDestroyMMDBFile(hMiraMonLayer, &hMiraMonLayer->MMPoint.MMAdmDB);
    6955          76 :         return;
    6956             :     }
    6957         736 :     if (hMiraMonLayer->bIsArc && !hMiraMonLayer->bIsPolygon)
    6958             :     {
    6959          60 :         MMDestroyMMDBFile(hMiraMonLayer, &hMiraMonLayer->MMArc.MMAdmDB);
    6960          60 :         MMDestroyMMDBFile(hMiraMonLayer, &hMiraMonLayer->MMArc.MMNode.MMAdmDB);
    6961          60 :         return;
    6962             :     }
    6963         676 :     if (hMiraMonLayer->bIsPolygon)
    6964             :     {
    6965          75 :         MMDestroyMMDBFile(hMiraMonLayer, &hMiraMonLayer->MMPolygon.MMAdmDB);
    6966          75 :         MMDestroyMMDBFile(hMiraMonLayer,
    6967             :                           &hMiraMonLayer->MMPolygon.MMArc.MMAdmDB);
    6968          75 :         MMDestroyMMDBFile(hMiraMonLayer,
    6969             :                           &hMiraMonLayer->MMPolygon.MMArc.MMNode.MMAdmDB);
    6970             :     }
    6971         676 :     if (hMiraMonLayer->bIsDBF)
    6972          17 :         MMDestroyMMDBFile(hMiraMonLayer, &hMiraMonLayer->MMAdmDBWriting);
    6973             : }
    6974             : 
    6975             : CPL_C_END  // Necessary for compiling in GDAL project

Generated by: LCOV version 1.14