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: 2791 3692 75.6 %
Date: 2026-06-19 21:24:00 Functions: 99 99 100.0 %

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

Generated by: LCOV version 1.14