Coverage Report

Created: 2025-07-23 09:13

/src/gdal/ogr/ogrsf_frmts/miramon/ogrmiramonlayer.cpp
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Project:  OpenGIS Simple Features Reference Implementation
4
 * Purpose:  Implements OGRMiraMonLayer class.
5
 * Author:   Abel Pau
6
 ******************************************************************************
7
 * Copyright (c) 2024, Xavier Pons
8
 *
9
 * SPDX-License-Identifier: MIT
10
 ****************************************************************************/
11
#include "ogrmiramon.h"
12
13
#include "mm_gdal_functions.h"  // For MMCreateExtendedDBFIndex()
14
#include "mm_rdlayr.h"          // For MMInitLayerToRead()
15
#include <algorithm>            // For std::clamp()
16
#include <string>               // For std::string
17
#include <algorithm>            // For std::max
18
19
/****************************************************************************/
20
/*                            OGRMiraMonLayer()                             */
21
/****************************************************************************/
22
OGRMiraMonLayer::OGRMiraMonLayer(GDALDataset *poDS, const char *pszFilename,
23
                                 VSILFILE *fp, const OGRSpatialReference *poSRS,
24
                                 int bUpdateIn, CSLConstList papszOpenOptions,
25
                                 struct MiraMonVectMapInfo *MMMap)
26
7.20k
    : m_poDS(poDS), m_poSRS(nullptr), m_poFeatureDefn(nullptr), m_iNextFID(0),
27
7.20k
      phMiraMonLayer(nullptr), hMiraMonLayerPNT(), hMiraMonLayerARC(),
28
7.20k
      hMiraMonLayerPOL(), hMiraMonLayerReadOrNonGeom(), hMMFeature(),
29
7.20k
      m_bUpdate(CPL_TO_BOOL(bUpdateIn)),
30
7.20k
      m_fp(fp ? fp : VSIFOpenL(pszFilename, (bUpdateIn ? "r+" : "r"))),
31
7.20k
      padfValues(nullptr), pnInt64Values(nullptr), bValidFile(false)
32
7.20k
{
33
34
7.20k
    CPLDebugOnly("MiraMon", "Creating/Opening MiraMon layer...");
35
    /* -------------------------------------------------------------------- */
36
    /*      Create the feature definition                                   */
37
    /* -------------------------------------------------------------------- */
38
7.20k
    m_poFeatureDefn =
39
7.20k
        new OGRFeatureDefn(CPLGetBasenameSafe(pszFilename).c_str());
40
7.20k
    SetDescription(m_poFeatureDefn->GetName());
41
7.20k
    m_poFeatureDefn->Reference();
42
43
7.20k
    if (m_bUpdate)
44
891
    {
45
        /* ---------------------------------------------------------------- */
46
        /*      Establish the version to use                                */
47
        /* ---------------------------------------------------------------- */
48
891
        const char *pszVersion = CSLFetchNameValue(papszOpenOptions, "Version");
49
891
        int nMMVersion;
50
51
891
        if (pszVersion)
52
0
        {
53
0
            if (EQUAL(pszVersion, "V1.1"))
54
0
                nMMVersion = MM_32BITS_VERSION;
55
0
            else if (EQUAL(pszVersion, "V2.0") ||
56
0
                     EQUAL(pszVersion, "last_version"))
57
0
                nMMVersion = MM_64BITS_VERSION;
58
0
            else
59
0
                nMMVersion = MM_32BITS_VERSION;  // Default
60
0
        }
61
891
        else
62
891
            nMMVersion = MM_32BITS_VERSION;  // Default
63
64
        /* ---------------------------------------------------------------- */
65
        /*      Establish the charset of the .dbf files                     */
66
        /* ---------------------------------------------------------------- */
67
891
        const char *pszdbfEncoding =
68
891
            CSLFetchNameValue(papszOpenOptions, "DBFEncoding");
69
891
        char nMMRecode;
70
71
891
        if (pszdbfEncoding)
72
0
        {
73
0
            if (EQUAL(pszdbfEncoding, "UTF8"))
74
0
                nMMRecode = MM_RECODE_UTF8;
75
0
            else  //if (EQUAL(pszdbfEncoding, "ANSI"))
76
0
                nMMRecode = MM_RECODE_ANSI;
77
0
        }
78
891
        else
79
891
            nMMRecode = MM_RECODE_ANSI;  // Default
80
81
        /* ----------------------------------------------------------------- */
82
        /*   Establish the descriptors language when                         */
83
        /*   creating .rel files                                             */
84
        /* ----------------------------------------------------------------- */
85
891
        const char *pszLanguage =
86
891
            CSLFetchNameValue(papszOpenOptions, "CreationLanguage");
87
891
        char nMMLanguage;
88
89
891
        if (pszLanguage)
90
0
        {
91
0
            if (EQUAL(pszLanguage, "CAT"))
92
0
                nMMLanguage = MM_CAT_LANGUAGE;
93
0
            else if (EQUAL(pszLanguage, "SPA"))
94
0
                nMMLanguage = MM_SPA_LANGUAGE;
95
0
            else
96
0
                nMMLanguage = MM_ENG_LANGUAGE;
97
0
        }
98
891
        else
99
891
            nMMLanguage = MM_DEF_LANGUAGE;  // Default
100
101
        /* ---------------------------------------------------------------- */
102
        /*      Preparing to write the layer                                */
103
        /* ---------------------------------------------------------------- */
104
        // Init the feature (memory, num,...)
105
891
        if (MMInitFeature(&hMMFeature))
106
0
        {
107
0
            bValidFile = false;
108
0
            return;
109
0
        }
110
111
        // Init the Layers (not in disk, only in memory until
112
        // the first element is read)
113
891
        CPLDebugOnly("MiraMon", "Initializing MiraMon points layer...");
114
891
        if (MMInitLayer(&hMiraMonLayerPNT, pszFilename, nMMVersion, nMMRecode,
115
891
                        nMMLanguage, nullptr, MM_WRITING_MODE, MMMap))
116
0
        {
117
0
            bValidFile = false;
118
0
            return;
119
0
        }
120
891
        hMiraMonLayerPNT.bIsBeenInit = 0;
121
122
891
        CPLDebugOnly("MiraMon", "Initializing MiraMon arcs layer...");
123
891
        if (MMInitLayer(&hMiraMonLayerARC, pszFilename, nMMVersion, nMMRecode,
124
891
                        nMMLanguage, nullptr, MM_WRITING_MODE, MMMap))
125
0
        {
126
0
            bValidFile = false;
127
0
            return;
128
0
        }
129
891
        hMiraMonLayerARC.bIsBeenInit = 0;
130
131
891
        CPLDebugOnly("MiraMon", "Initializing MiraMon polygons layer...");
132
891
        if (MMInitLayer(&hMiraMonLayerPOL, pszFilename, nMMVersion, nMMRecode,
133
891
                        nMMLanguage, nullptr, MM_WRITING_MODE, MMMap))
134
0
        {
135
0
            bValidFile = false;
136
0
            return;
137
0
        }
138
891
        hMiraMonLayerPOL.bIsBeenInit = 0;
139
140
        // Just in case that there is no geometry but some other
141
        // information to get. A DBF will be generated
142
891
        CPLDebugOnly("MiraMon", "Initializing MiraMon only-ext-DBF layer...");
143
891
        if (MMInitLayer(&hMiraMonLayerReadOrNonGeom, pszFilename, nMMVersion,
144
891
                        nMMRecode, nMMLanguage, nullptr, MM_WRITING_MODE,
145
891
                        nullptr))
146
0
        {
147
0
            bValidFile = false;
148
0
            return;
149
0
        }
150
891
        hMiraMonLayerPOL.bIsBeenInit = 0;
151
152
        // This helps the map to be created
153
        //GetLayerDefn()->SetName(hMiraMonLayerPNT.pszSrcLayerName);
154
891
        m_poFeatureDefn->SetName(hMiraMonLayerPNT.pszSrcLayerName);
155
156
        // Saving the HRS in the layer structure
157
891
        if (poSRS)
158
64
        {
159
64
            const char *pszTargetKey = nullptr;
160
64
            const char *pszAuthorityName = nullptr;
161
64
            const char *pszAuthorityCode = nullptr;
162
163
            // Reading Z units (in case of 3D vector file)
164
64
            if (poSRS->GetAuthorityCode("VERT_CS") != nullptr)
165
2
            {
166
2
                const char *pszUnits = nullptr;
167
2
                const double dfUnits =
168
2
                    poSRS->GetTargetLinearUnits("VERT_CS", &pszUnits);
169
2
                const auto IsAlmostEqual = [](double x, double y)
170
2
                { return std::fabs(x - y) <= 1e-10; };
171
2
                if (pszUnits)
172
2
                {
173
2
                    if (!strcmp(pszUnits, "metre") && IsAlmostEqual(dfUnits, 1))
174
2
                    {
175
2
                        hMiraMonLayerPNT.pZUnit = strdup("m");
176
2
                        hMiraMonLayerARC.pZUnit = strdup("m");
177
2
                        hMiraMonLayerPOL.pZUnit = strdup("m");
178
2
                    }
179
0
                    else
180
0
                    {
181
0
                        hMiraMonLayerPNT.pZUnit = strdup(pszUnits);
182
0
                        hMiraMonLayerARC.pZUnit = strdup(pszUnits);
183
0
                        hMiraMonLayerPOL.pZUnit = strdup(pszUnits);
184
0
                    }
185
2
                }
186
2
            }
187
188
            // Reading horizontal reference system and horizontal units
189
64
            if (poSRS->IsProjected())
190
44
                pszTargetKey = "PROJCS";
191
20
            else if (poSRS->IsGeographic() || poSRS->IsDerivedGeographic())
192
1
                pszTargetKey = "GEOGCS";
193
19
            else if (poSRS->IsGeocentric())
194
0
                pszTargetKey = "GEOCCS";
195
19
            else if (poSRS->IsLocal())
196
0
                pszTargetKey = "LOCAL_CS";
197
198
64
            if (!poSRS->IsLocal())
199
64
            {
200
64
                pszAuthorityName = poSRS->GetAuthorityName(pszTargetKey);
201
64
                pszAuthorityCode = poSRS->GetAuthorityCode(pszTargetKey);
202
64
            }
203
204
64
            if (pszAuthorityName && pszAuthorityCode &&
205
64
                EQUAL(pszAuthorityName, "EPSG"))
206
41
            {
207
41
                CPLDebugOnly("MiraMon", "Setting EPSG code %s",
208
41
                             pszAuthorityCode);
209
41
                hMiraMonLayerPNT.pSRS = CPLStrdup(pszAuthorityCode);
210
41
                hMiraMonLayerARC.pSRS = CPLStrdup(pszAuthorityCode);
211
41
                hMiraMonLayerPOL.pSRS = CPLStrdup(pszAuthorityCode);
212
41
            }
213
            // In the DBF, there are some reserved fields that need to
214
            // know if the layer is geographic or not to write the
215
            // precision (they are real)
216
64
            if (poSRS->IsGeographic())
217
1
            {
218
1
                hMiraMonLayerPNT.nSRSType = hMiraMonLayerARC.nSRSType =
219
1
                    hMiraMonLayerPOL.nSRSType = MM_SRS_LAYER_IS_GEOGRAPHIC_TYPE;
220
1
            }
221
63
            else
222
63
            {
223
63
                hMiraMonLayerPNT.nSRSType = hMiraMonLayerARC.nSRSType =
224
63
                    hMiraMonLayerPOL.nSRSType = MM_SRS_LAYER_IS_PROJECTED_TYPE;
225
63
            }
226
64
        }
227
827
        else
228
827
        {
229
827
            hMiraMonLayerPNT.nSRSType = hMiraMonLayerARC.nSRSType =
230
827
                hMiraMonLayerPOL.nSRSType = MM_SRS_LAYER_IS_UNKNOWN_TYPE;
231
827
        }
232
891
    }
233
6.31k
    else
234
6.31k
    {
235
6.31k
        if (m_fp == nullptr)
236
0
        {
237
0
            bValidFile = false;
238
0
            return;
239
0
        }
240
241
        /* ------------------------------------------------------------------*/
242
        /*      Read the header.                                             */
243
        /* ------------------------------------------------------------------*/
244
6.31k
        int nMMLayerVersion;
245
246
6.31k
        if (MMInitLayerToRead(&hMiraMonLayerReadOrNonGeom, m_fp, pszFilename))
247
5.26k
        {
248
5.26k
            phMiraMonLayer = &hMiraMonLayerReadOrNonGeom;
249
5.26k
            bValidFile = false;
250
5.26k
            return;
251
5.26k
        }
252
1.05k
        phMiraMonLayer = &hMiraMonLayerReadOrNonGeom;
253
254
1.05k
        nMMLayerVersion = MMGetVectorVersion(&phMiraMonLayer->TopHeader);
255
1.05k
        if (nMMLayerVersion == MM_UNKNOWN_VERSION)
256
0
        {
257
0
            CPLError(CE_Failure, CPLE_NotSupported,
258
0
                     "MiraMon version file unknown.");
259
0
            bValidFile = false;
260
0
            return;
261
0
        }
262
1.05k
        if (phMiraMonLayer->bIsPoint)
263
474
        {
264
474
            if (phMiraMonLayer->TopHeader.bIs3d)
265
119
                m_poFeatureDefn->SetGeomType(wkbPoint25D);
266
355
            else
267
355
                m_poFeatureDefn->SetGeomType(wkbPoint);
268
474
        }
269
579
        else if (phMiraMonLayer->bIsArc && !phMiraMonLayer->bIsPolygon)
270
276
        {
271
276
            if (phMiraMonLayer->TopHeader.bIs3d)
272
211
                m_poFeatureDefn->SetGeomType(wkbLineString25D);
273
65
            else
274
65
                m_poFeatureDefn->SetGeomType(wkbLineString);
275
276
        }
276
303
        else if (phMiraMonLayer->bIsPolygon)
277
303
        {
278
            // 3D
279
303
            if (phMiraMonLayer->TopHeader.bIs3d)
280
179
            {
281
179
                if (phMiraMonLayer->TopHeader.bIsMultipolygon)
282
79
                    m_poFeatureDefn->SetGeomType(wkbMultiPolygon25D);
283
100
                else
284
100
                    m_poFeatureDefn->SetGeomType(wkbPolygon25D);
285
179
            }
286
124
            else
287
124
            {
288
124
                if (phMiraMonLayer->TopHeader.bIsMultipolygon)
289
45
                    m_poFeatureDefn->SetGeomType(wkbMultiPolygon);
290
79
                else
291
79
                    m_poFeatureDefn->SetGeomType(wkbPolygon);
292
124
            }
293
303
        }
294
0
        else
295
0
        {
296
0
            CPLError(CE_Failure, CPLE_NotSupported,
297
0
                     "MiraMon file type not supported.");
298
0
            bValidFile = false;
299
0
            return;
300
0
        }
301
302
1.05k
        if (phMiraMonLayer->TopHeader.bIs3d)
303
509
        {
304
509
            const char *szHeight =
305
509
                CSLFetchNameValue(papszOpenOptions, "Height");
306
509
            if (szHeight)
307
0
            {
308
0
                if (EQUAL(szHeight, "Highest"))
309
0
                    phMiraMonLayer->nSelectCoordz = MM_SELECT_HIGHEST_COORDZ;
310
0
                else if (EQUAL(szHeight, "Lowest"))
311
0
                    phMiraMonLayer->nSelectCoordz = MM_SELECT_LOWEST_COORDZ;
312
0
                else
313
0
                    phMiraMonLayer->nSelectCoordz = MM_SELECT_FIRST_COORDZ;
314
0
            }
315
509
            else
316
509
                phMiraMonLayer->nSelectCoordz = MM_SELECT_FIRST_COORDZ;
317
509
        }
318
319
        /* ------------------------------------------------------------ */
320
        /*   Establish the descriptors language when                    */
321
        /*   opening .rel files                                        */
322
        /* ------------------------------------------------------------ */
323
1.05k
        const char *pszLanguage =
324
1.05k
            CSLFetchNameValue(papszOpenOptions, "OpenLanguage");
325
326
1.05k
        if (pszLanguage)
327
0
        {
328
0
            if (EQUAL(pszLanguage, "CAT"))
329
0
                phMiraMonLayer->nMMLanguage = MM_CAT_LANGUAGE;
330
0
            else if (EQUAL(pszLanguage, "SPA"))
331
0
                phMiraMonLayer->nMMLanguage = MM_SPA_LANGUAGE;
332
0
            else
333
0
                phMiraMonLayer->nMMLanguage = MM_ENG_LANGUAGE;
334
0
        }
335
1.05k
        else
336
1.05k
            phMiraMonLayer->nMMLanguage = MM_DEF_LANGUAGE;  // Default
337
338
1.05k
        if (phMiraMonLayer->nSRS_EPSG != 0)
339
0
        {
340
0
            m_poSRS = new OGRSpatialReference();
341
0
            m_poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
342
0
            if (m_poSRS->importFromEPSG(phMiraMonLayer->nSRS_EPSG) !=
343
0
                OGRERR_NONE)
344
0
            {
345
0
                delete m_poSRS;
346
0
                m_poSRS = nullptr;
347
0
            }
348
0
            else
349
0
                m_poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(m_poSRS);
350
0
        }
351
352
        // If there is associated information
353
1.05k
        if (phMiraMonLayer->pMMBDXP)
354
1.05k
        {
355
1.05k
            if (!phMiraMonLayer->pMMBDXP->pfDataBase)
356
1.05k
            {
357
1.05k
                if ((phMiraMonLayer->pMMBDXP->pfDataBase = VSIFOpenL(
358
1.05k
                         phMiraMonLayer->pMMBDXP->szFileName, "r")) == nullptr)
359
0
                {
360
0
                    CPLDebugOnly("MiraMon", "File '%s' cannot be opened.",
361
0
                                 phMiraMonLayer->pMMBDXP->szFileName);
362
0
                    bValidFile = false;
363
0
                    return;
364
0
                }
365
366
1.05k
                if (phMiraMonLayer->pMMBDXP->nFields == 0)
367
3
                {
368
                    // TODO: is this correct? At least this prevents a
369
                    // nullptr dereference of phMiraMonLayer->pMMBDXP->pField
370
                    // below
371
3
                    CPLDebug("MiraMon",
372
3
                             "phMiraMonLayer->pMMBDXP->nFields == 0");
373
3
                    bValidFile = false;
374
3
                    return;
375
3
                }
376
377
                // First time we open the extended DBF we create an index
378
                // to fastly find all non geometrical features.
379
1.05k
                phMiraMonLayer->pMultRecordIndex = MMCreateExtendedDBFIndex(
380
1.05k
                    phMiraMonLayer->pMMBDXP->pfDataBase,
381
1.05k
                    phMiraMonLayer->pMMBDXP->nRecords,
382
1.05k
                    phMiraMonLayer->pMMBDXP->FirstRecordOffset,
383
1.05k
                    phMiraMonLayer->pMMBDXP->BytesPerRecord,
384
1.05k
                    phMiraMonLayer->pMMBDXP
385
1.05k
                        ->pField[phMiraMonLayer->pMMBDXP->IdGraficField]
386
1.05k
                        .AccumulatedBytes,
387
1.05k
                    phMiraMonLayer->pMMBDXP
388
1.05k
                        ->pField[phMiraMonLayer->pMMBDXP->IdGraficField]
389
1.05k
                        .BytesPerField,
390
1.05k
                    &phMiraMonLayer->isListField, &phMiraMonLayer->nMaxN);
391
392
                // Creation of maximum number needed for processing
393
                // multiple records
394
1.05k
                if (phMiraMonLayer->pMultRecordIndex)
395
615
                {
396
615
                    padfValues = static_cast<double *>(CPLCalloc(
397
615
                        (size_t)phMiraMonLayer->nMaxN, sizeof(*padfValues)));
398
399
615
                    pnInt64Values = static_cast<GInt64 *>(CPLCalloc(
400
615
                        (size_t)phMiraMonLayer->nMaxN, sizeof(*pnInt64Values)));
401
615
                }
402
403
1.05k
                phMiraMonLayer->iMultiRecord =
404
1.05k
                    MM_MULTIRECORD_NO_MULTIRECORD;  // No option iMultiRecord
405
1.05k
                const char *szMultiRecord =
406
1.05k
                    CSLFetchNameValue(papszOpenOptions, "MultiRecordIndex");
407
1.05k
                if (phMiraMonLayer->isListField && szMultiRecord)
408
0
                {
409
0
                    if (EQUAL(szMultiRecord, "Last"))
410
0
                        phMiraMonLayer->iMultiRecord = MM_MULTIRECORD_LAST;
411
0
                    else if (EQUAL(szMultiRecord, "JSON"))
412
0
                        phMiraMonLayer->iMultiRecord = MM_MULTIRECORD_JSON;
413
0
                    else
414
0
                        phMiraMonLayer->iMultiRecord = atoi(szMultiRecord);
415
0
                }
416
1.05k
            }
417
418
1.05k
            for (MM_EXT_DBF_N_FIELDS nIField = 0;
419
63.6k
                 nIField < phMiraMonLayer->pMMBDXP->nFields; nIField++)
420
62.5k
            {
421
62.5k
                OGRFieldDefn oField("", OFTString);
422
62.5k
                oField.SetName(
423
62.5k
                    phMiraMonLayer->pMMBDXP->pField[nIField].FieldName);
424
425
62.5k
                oField.SetAlternativeName(
426
62.5k
                    phMiraMonLayer->pMMBDXP->pField[nIField]
427
62.5k
                        .FieldDescription[phMiraMonLayer->nMMLanguage <
428
62.5k
                                                  MM_NUM_IDIOMES_MD_MULTIDIOMA
429
62.5k
                                              ? phMiraMonLayer->nMMLanguage
430
62.5k
                                              : 0]);
431
432
62.5k
                if (phMiraMonLayer->pMMBDXP->pField[nIField].FieldType == 'C' ||
433
62.5k
                    phMiraMonLayer->pMMBDXP->pField[nIField].FieldType == 'L')
434
6.71k
                {
435
                    // It's a list?
436
6.71k
                    if (phMiraMonLayer->iMultiRecord ==
437
6.71k
                        MM_MULTIRECORD_NO_MULTIRECORD)
438
6.71k
                    {
439
6.71k
                        if (phMiraMonLayer->pMMBDXP->pField[nIField]
440
6.71k
                                .FieldType == 'L')
441
1.65k
                        {
442
1.65k
                            if (phMiraMonLayer->isListField)
443
314
                                oField.SetType(OFTIntegerList);
444
1.33k
                            else
445
1.33k
                                oField.SetType(OFTInteger);
446
447
1.65k
                            oField.SetSubType(OFSTBoolean);
448
1.65k
                        }
449
5.06k
                        else
450
5.06k
                        {
451
5.06k
                            if (phMiraMonLayer->isListField)
452
450
                                oField.SetType(OFTStringList);
453
4.61k
                            else
454
4.61k
                                oField.SetType(OFTString);
455
5.06k
                        }
456
6.71k
                    }
457
                    // It's a serialized JSON array
458
0
                    else if (phMiraMonLayer->iMultiRecord ==
459
0
                             MM_MULTIRECORD_JSON)
460
0
                    {
461
0
                        oField.SetType(OFTString);
462
0
                        oField.SetSubType(OFSTJSON);
463
0
                    }
464
0
                    else  // iMultiRecord decides which Record translate
465
0
                        oField.SetType(OFTString);
466
6.71k
                }
467
55.8k
                else if (phMiraMonLayer->pMMBDXP->pField[nIField].FieldType ==
468
55.8k
                         'N')
469
5.07k
                {
470
                    // It's a list?
471
5.07k
                    if (phMiraMonLayer->iMultiRecord ==
472
5.07k
                        MM_MULTIRECORD_NO_MULTIRECORD)
473
5.07k
                    {
474
5.07k
                        if (phMiraMonLayer->pMMBDXP->pField[nIField]
475
5.07k
                                .DecimalsIfFloat)
476
3.29k
                            oField.SetType(phMiraMonLayer->isListField
477
3.29k
                                               ? OFTRealList
478
3.29k
                                               : OFTReal);
479
1.77k
                        else
480
1.77k
                        {
481
1.77k
                            if (phMiraMonLayer->pMMBDXP->pField[nIField]
482
1.77k
                                    .BytesPerField < 10)
483
868
                            {
484
868
                                oField.SetType(phMiraMonLayer->isListField
485
868
                                                   ? OFTIntegerList
486
868
                                                   : OFTInteger);
487
868
                            }
488
906
                            else
489
906
                            {
490
906
                                oField.SetType(phMiraMonLayer->isListField
491
906
                                                   ? OFTInteger64List
492
906
                                                   : OFTInteger64);
493
906
                            }
494
1.77k
                        }
495
5.07k
                    }
496
                    // It's a serialized JSON array
497
0
                    else if (phMiraMonLayer->iMultiRecord ==
498
0
                             MM_MULTIRECORD_JSON)
499
0
                    {
500
0
                        oField.SetType(OFTString);
501
0
                        oField.SetSubType(OFSTJSON);
502
0
                    }
503
0
                    else
504
0
                    {
505
0
                        if (phMiraMonLayer->pMMBDXP->pField[nIField]
506
0
                                .DecimalsIfFloat)
507
0
                            oField.SetType(OFTReal);
508
0
                        else
509
0
                            oField.SetType(OFTInteger);
510
0
                    }
511
5.07k
                }
512
50.7k
                else if (phMiraMonLayer->pMMBDXP->pField[nIField].FieldType ==
513
50.7k
                         'D')
514
1.66k
                {
515
                    // It's a serialized JSON array
516
1.66k
                    oField.SetType(OFTDate);
517
1.66k
                    if (phMiraMonLayer->iMultiRecord == MM_MULTIRECORD_JSON)
518
0
                    {
519
0
                        oField.SetType(OFTString);
520
0
                        oField.SetSubType(OFSTJSON);
521
0
                    }
522
1.66k
                }
523
524
62.5k
                oField.SetWidth(
525
62.5k
                    phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField);
526
62.5k
                oField.SetPrecision(
527
62.5k
                    phMiraMonLayer->pMMBDXP->pField[nIField].DecimalsIfFloat);
528
529
62.5k
                m_poFeatureDefn->AddFieldDefn(&oField);
530
62.5k
            }
531
1.05k
        }
532
1.05k
    }
533
534
1.94k
    bValidFile = true;
535
1.94k
}
536
537
/****************************************************************************/
538
/*                           ~OGRMiraMonLayer()                             */
539
/****************************************************************************/
540
541
OGRMiraMonLayer::~OGRMiraMonLayer()
542
543
7.20k
{
544
7.20k
    if (m_nFeaturesRead > 0 && m_poFeatureDefn != nullptr)
545
834
    {
546
834
        CPLDebugOnly("MiraMon", "%d features read on layer '%s'.",
547
834
                     static_cast<int>(m_nFeaturesRead),
548
834
                     m_poFeatureDefn->GetName());
549
834
    }
550
551
7.20k
    if (hMiraMonLayerPOL.bIsPolygon)
552
22
    {
553
22
        CPLDebugOnly("MiraMon", "Closing MiraMon polygons layer...");
554
22
        if (MMCloseLayer(&hMiraMonLayerPOL))
555
12
        {
556
12
            CPLDebugOnly("MiraMon", "Error closing polygons layer");
557
558
            // In case of closing we need to destroy memory
559
12
            MMDestroyLayer(&hMiraMonLayerPOL);
560
12
        }
561
22
        if (hMiraMonLayerPOL.TopHeader.nElemCount)
562
22
        {
563
22
            CPLDebugOnly("MiraMon",
564
22
                         sprintf_UINT64 " polygon(s) written in file %s.pol",
565
22
                         hMiraMonLayerPOL.TopHeader.nElemCount,
566
22
                         hMiraMonLayerPOL.pszSrcLayerName);
567
22
        }
568
22
        CPLDebugOnly("MiraMon", "MiraMon polygons layer closed");
569
22
    }
570
7.18k
    else if (hMiraMonLayerPOL.ReadOrWrite == MM_WRITING_MODE)
571
869
    {
572
869
        CPLDebugOnly("MiraMon", "No MiraMon polygons layer created.");
573
869
    }
574
575
7.20k
    if (hMiraMonLayerARC.bIsArc)
576
11
    {
577
11
        CPLDebugOnly("MiraMon", "Closing MiraMon arcs layer...");
578
11
        if (MMCloseLayer(&hMiraMonLayerARC))
579
1
        {
580
1
            CPLDebugOnly("MiraMon", "Error closing arcs layer");
581
582
            // In case of closing we need to destroy memory
583
1
            MMDestroyLayer(&hMiraMonLayerARC);
584
1
        }
585
11
        if (hMiraMonLayerARC.TopHeader.nElemCount)
586
10
        {
587
10
            CPLDebugOnly("MiraMon",
588
10
                         sprintf_UINT64 " arc(s) written in file %s.arc",
589
10
                         hMiraMonLayerARC.TopHeader.nElemCount,
590
10
                         hMiraMonLayerARC.pszSrcLayerName);
591
10
        }
592
593
11
        CPLDebugOnly("MiraMon", "MiraMon arcs layer closed");
594
11
    }
595
7.19k
    else if (hMiraMonLayerARC.ReadOrWrite == MM_WRITING_MODE)
596
880
    {
597
880
        CPLDebugOnly("MiraMon", "No MiraMon arcs layer created.");
598
880
    }
599
600
7.20k
    if (hMiraMonLayerPNT.bIsPoint)
601
23
    {
602
23
        CPLDebugOnly("MiraMon", "Closing MiraMon points layer...");
603
23
        if (MMCloseLayer(&hMiraMonLayerPNT))
604
5
        {
605
5
            CPLDebugOnly("MiraMon", "Error closing points layer");
606
607
            // In case of closing we need to destroy memory
608
5
            MMDestroyLayer(&hMiraMonLayerPNT);
609
5
        }
610
23
        if (hMiraMonLayerPNT.TopHeader.nElemCount)
611
18
        {
612
18
            CPLDebugOnly("MiraMon",
613
18
                         sprintf_UINT64 " point(s) written in file %s.pnt",
614
18
                         hMiraMonLayerPNT.TopHeader.nElemCount,
615
18
                         hMiraMonLayerPNT.pszSrcLayerName);
616
18
        }
617
23
        CPLDebugOnly("MiraMon", "MiraMon points layer closed");
618
23
    }
619
7.18k
    else if (hMiraMonLayerPNT.ReadOrWrite == MM_WRITING_MODE)
620
868
    {
621
868
        CPLDebugOnly("MiraMon", "No MiraMon points layer created.");
622
868
    }
623
624
7.20k
    if (hMiraMonLayerARC.ReadOrWrite == MM_WRITING_MODE)
625
891
    {
626
891
        if (hMiraMonLayerReadOrNonGeom.bIsDBF)
627
750
        {
628
750
            if (hMiraMonLayerReadOrNonGeom.ReadOrWrite == MM_WRITING_MODE)
629
750
            {
630
750
                CPLDebugOnly("MiraMon", "Closing MiraMon DBF table ...");
631
750
            }
632
750
            if (MMCloseLayer(&hMiraMonLayerReadOrNonGeom))
633
0
            {
634
                // In case of closing we need to destroy memory
635
0
                MMDestroyLayer(&hMiraMonLayerReadOrNonGeom);
636
0
            }
637
750
            if (hMiraMonLayerReadOrNonGeom.ReadOrWrite == MM_WRITING_MODE)
638
750
            {
639
750
                CPLDebugOnly("MiraMon", "MiraMon DBF table closed");
640
750
            }
641
750
        }
642
141
        else if (hMiraMonLayerReadOrNonGeom.ReadOrWrite == MM_WRITING_MODE)
643
141
        {
644
141
            CPLDebugOnly("MiraMon", "No MiraMon DBF table created.");
645
141
        }
646
891
    }
647
6.31k
    else
648
6.31k
    {
649
6.31k
        if (hMiraMonLayerReadOrNonGeom.ReadOrWrite == MM_WRITING_MODE)
650
0
        {
651
0
            CPLDebugOnly("MiraMon", "Closing MiraMon layer ...");
652
0
        }
653
6.31k
        if (MMCloseLayer(&hMiraMonLayerReadOrNonGeom))
654
0
        {
655
            // In case of closing we need to destroy memory
656
0
            MMDestroyLayer(&hMiraMonLayerReadOrNonGeom);
657
0
        }
658
6.31k
        if (hMiraMonLayerReadOrNonGeom.ReadOrWrite == MM_WRITING_MODE)
659
0
        {
660
0
            CPLDebugOnly("MiraMon", "MiraMon layer closed");
661
0
        }
662
6.31k
    }
663
664
7.20k
    if (hMiraMonLayerPOL.ReadOrWrite == MM_WRITING_MODE)
665
891
    {
666
891
        CPLDebugOnly("MiraMon", "Destroying MiraMon polygons layer memory");
667
891
    }
668
7.20k
    MMDestroyLayer(&hMiraMonLayerPOL);
669
7.20k
    if (hMiraMonLayerPOL.ReadOrWrite == MM_WRITING_MODE)
670
891
    {
671
891
        CPLDebugOnly("MiraMon", "MiraMon polygons layer memory destroyed");
672
891
    }
673
674
7.20k
    if (hMiraMonLayerARC.ReadOrWrite == MM_WRITING_MODE)
675
891
    {
676
891
        CPLDebugOnly("MiraMon", "Destroying MiraMon arcs layer memory");
677
891
    }
678
7.20k
    MMDestroyLayer(&hMiraMonLayerARC);
679
7.20k
    if (hMiraMonLayerARC.ReadOrWrite == MM_WRITING_MODE)
680
891
    {
681
891
        CPLDebugOnly("MiraMon", "MiraMon arcs layer memory destroyed");
682
891
    }
683
684
7.20k
    if (hMiraMonLayerPNT.ReadOrWrite == MM_WRITING_MODE)
685
891
    {
686
891
        CPLDebugOnly("MiraMon", "Destroying MiraMon points layer memory");
687
891
    }
688
7.20k
    MMDestroyLayer(&hMiraMonLayerPNT);
689
7.20k
    if (hMiraMonLayerPNT.ReadOrWrite == MM_WRITING_MODE)
690
891
    {
691
891
        CPLDebugOnly("MiraMon", "MiraMon points layer memory destroyed");
692
891
    }
693
694
7.20k
    if (hMiraMonLayerReadOrNonGeom.ReadOrWrite == MM_WRITING_MODE)
695
891
    {
696
891
        CPLDebugOnly("MiraMon", "Destroying MiraMon DBF table layer memory");
697
891
    }
698
6.31k
    else
699
6.31k
    {
700
6.31k
        CPLDebugOnly("MiraMon", "Destroying MiraMon layer memory");
701
6.31k
    }
702
703
7.20k
    MMDestroyLayer(&hMiraMonLayerReadOrNonGeom);
704
7.20k
    if (hMiraMonLayerReadOrNonGeom.ReadOrWrite == MM_WRITING_MODE)
705
891
    {
706
891
        CPLDebugOnly("MiraMon", "MiraMon DBF table layer memory destroyed");
707
891
    }
708
6.31k
    else
709
6.31k
    {
710
6.31k
        CPLDebugOnly("MiraMon", "MiraMon layer memory destroyed");
711
6.31k
    }
712
713
7.20k
    memset(&hMiraMonLayerReadOrNonGeom, 0, sizeof(hMiraMonLayerReadOrNonGeom));
714
7.20k
    memset(&hMiraMonLayerPNT, 0, sizeof(hMiraMonLayerPNT));
715
7.20k
    memset(&hMiraMonLayerARC, 0, sizeof(hMiraMonLayerARC));
716
7.20k
    memset(&hMiraMonLayerPOL, 0, sizeof(hMiraMonLayerPOL));
717
718
7.20k
    CPLDebugOnly("MiraMon", "Destroying MiraMon temporary feature memory");
719
7.20k
    MMDestroyFeature(&hMMFeature);
720
7.20k
    CPLDebugOnly("MiraMon", "MiraMon temporary feature memory");
721
7.20k
    memset(&hMMFeature, 0, sizeof(hMMFeature));
722
723
    /* -------------------------------------------------------------------- */
724
    /*      Clean up.                                                       */
725
    /* -------------------------------------------------------------------- */
726
727
7.20k
    if (m_poFeatureDefn)
728
7.20k
        m_poFeatureDefn->Release();
729
730
7.20k
    if (m_poSRS)
731
0
        m_poSRS->Release();
732
733
7.20k
    if (m_fp != nullptr)
734
6.31k
        VSIFCloseL(m_fp);
735
736
7.20k
    if (padfValues != nullptr)
737
434
        CPLFree(padfValues);
738
739
7.20k
    if (pnInt64Values != nullptr)
740
434
        CPLFree(pnInt64Values);
741
7.20k
}
742
743
/****************************************************************************/
744
/*                            ResetReading()                                */
745
/****************************************************************************/
746
747
void OGRMiraMonLayer::ResetReading()
748
749
0
{
750
0
    if (m_iNextFID == 0)
751
0
        return;
752
753
0
    m_iNextFID = 0;
754
755
    //VSIFSeekL(m_fp, 0, SEEK_SET);
756
0
    if (!phMiraMonLayer)
757
0
        return;
758
759
0
    if (phMiraMonLayer->bIsPoint && phMiraMonLayer->MMPoint.pF)
760
0
    {
761
0
        VSIFSeekL(phMiraMonLayer->MMPoint.pF, 0, SEEK_SET);
762
0
        return;
763
0
    }
764
0
    if (phMiraMonLayer->bIsArc && !phMiraMonLayer->bIsPolygon &&
765
0
        phMiraMonLayer->MMArc.pF)
766
0
    {
767
0
        VSIFSeekL(phMiraMonLayer->MMArc.pF, 0, SEEK_SET);
768
0
        return;
769
0
    }
770
0
    if (phMiraMonLayer->bIsPolygon && phMiraMonLayer->MMPolygon.pF)
771
0
    {
772
0
        VSIFSeekL(phMiraMonLayer->MMPolygon.pF, 0, SEEK_SET);
773
0
        return;
774
0
    }
775
0
}
776
777
/****************************************************************************/
778
/*                         GetNextRawFeature()                              */
779
/****************************************************************************/
780
781
void OGRMiraMonLayer::GoToFieldOfMultipleRecord(MM_INTERNAL_FID iFID,
782
                                                MM_EXT_DBF_N_RECORDS nIRecord,
783
                                                MM_EXT_DBF_N_FIELDS nIField)
784
785
574k
{
786
    // Not an error. Simply there are no features, but there are fields
787
574k
    if (!phMiraMonLayer->pMultRecordIndex)
788
0
        return;
789
790
574k
    VSIFSeekL(phMiraMonLayer->pMMBDXP->pfDataBase,
791
574k
              phMiraMonLayer->pMultRecordIndex[iFID].offset +
792
574k
                  (MM_FILE_OFFSET)nIRecord *
793
574k
                      phMiraMonLayer->pMMBDXP->BytesPerRecord +
794
574k
                  phMiraMonLayer->pMMBDXP->pField[nIField].AccumulatedBytes,
795
574k
              SEEK_SET);
796
574k
}
797
798
/****************************************************************************/
799
/*                         GetNextRawFeature()                              */
800
/****************************************************************************/
801
802
OGRFeature *OGRMiraMonLayer::GetNextRawFeature()
803
19.4k
{
804
19.4k
    if (!phMiraMonLayer)
805
0
        return nullptr;
806
807
19.4k
    if (m_iNextFID >= (GUInt64)phMiraMonLayer->TopHeader.nElemCount)
808
203
        return nullptr;
809
810
19.2k
    OGRFeature *poFeature = GetFeature(m_iNextFID);
811
812
19.2k
    if (!poFeature)
813
845
        return nullptr;
814
815
18.4k
    m_iNextFID++;
816
18.4k
    return poFeature;
817
19.2k
}
818
819
/****************************************************************************/
820
/*                         GetFeature()                                     */
821
/****************************************************************************/
822
823
OGRFeature *OGRMiraMonLayer::GetFeature(GIntBig nFeatureId)
824
825
19.2k
{
826
19.2k
    OGRGeometry *poGeom = nullptr;
827
19.2k
    OGRPoint *poPoint = nullptr;
828
19.2k
    OGRLineString *poLS = nullptr;
829
19.2k
    MM_INTERNAL_FID nIElem;
830
19.2k
    MM_EXT_DBF_N_MULTIPLE_RECORDS nIRecord = 0;
831
832
19.2k
    if (!phMiraMonLayer)
833
0
        return nullptr;
834
835
19.2k
    if (nFeatureId < 0)
836
0
        return nullptr;
837
838
19.2k
    if (phMiraMonLayer->bIsPolygon)
839
538
    {
840
538
        if (nFeatureId == GINTBIG_MAX)
841
0
            return nullptr;
842
843
538
        nIElem = (MM_INTERNAL_FID)(nFeatureId + 1);
844
538
    }
845
18.7k
    else
846
18.7k
        nIElem = (MM_INTERNAL_FID)nFeatureId;
847
848
19.2k
    if (nIElem >= phMiraMonLayer->TopHeader.nElemCount)
849
15
        return nullptr;
850
851
    /* -------------------------------------------------------------------- */
852
    /*      Read nFeatureId feature directly from the file.                 */
853
    /* -------------------------------------------------------------------- */
854
19.2k
    switch (phMiraMonLayer->eLT)
855
19.2k
    {
856
13.6k
        case MM_LayerType_Point:
857
17.1k
        case MM_LayerType_Point3d:
858
            // Read point
859
17.1k
            poGeom = new OGRPoint();
860
17.1k
            poPoint = poGeom->toPoint();
861
862
            // Get X,Y (z). MiraMon has no multipoints
863
17.1k
            if (MMGetGeoFeatureFromVector(phMiraMonLayer, nIElem))
864
432
            {
865
432
                CPLError(CE_Failure, CPLE_AppDefined, "Wrong file format.");
866
432
                delete poGeom;
867
432
                return nullptr;
868
432
            }
869
870
16.6k
            poPoint->setX(phMiraMonLayer->ReadFeature.pCoord[0].dfX);
871
16.6k
            poPoint->setY(phMiraMonLayer->ReadFeature.pCoord[0].dfY);
872
16.6k
            if (phMiraMonLayer->TopHeader.bIs3d)
873
3.34k
                poPoint->setZ(phMiraMonLayer->ReadFeature.pZCoord[0]);
874
16.6k
            break;
875
876
571
        case MM_LayerType_Arc:
877
1.60k
        case MM_LayerType_Arc3d:
878
1.60k
            poGeom = new OGRLineString();
879
1.60k
            poLS = poGeom->toLineString();
880
881
            // Get X,Y (Z) n times MiraMon has no multilines
882
1.60k
            if (MMGetGeoFeatureFromVector(phMiraMonLayer, nIElem))
883
110
            {
884
110
                CPLError(CE_Failure, CPLE_AppDefined, "Wrong file format.");
885
110
                delete poGeom;
886
110
                return nullptr;
887
110
            }
888
889
1.49k
            for (MM_N_VERTICES_TYPE nIVrt = 0;
890
13.0k
                 nIVrt < phMiraMonLayer->ReadFeature.pNCoordRing[0]; nIVrt++)
891
11.5k
            {
892
11.5k
                if (phMiraMonLayer->TopHeader.bIs3d)
893
9.89k
                    poLS->addPoint(
894
9.89k
                        phMiraMonLayer->ReadFeature.pCoord[nIVrt].dfX,
895
9.89k
                        phMiraMonLayer->ReadFeature.pCoord[nIVrt].dfY,
896
9.89k
                        phMiraMonLayer->ReadFeature.pZCoord[nIVrt]);
897
1.66k
                else
898
1.66k
                    poLS->addPoint(
899
1.66k
                        phMiraMonLayer->ReadFeature.pCoord[nIVrt].dfX,
900
1.66k
                        phMiraMonLayer->ReadFeature.pCoord[nIVrt].dfY);
901
11.5k
            }
902
1.49k
            break;
903
904
279
        case MM_LayerType_Pol:
905
523
        case MM_LayerType_Pol3d:
906
            // Read polygon
907
523
            auto poPoly = std::make_unique<OGRPolygon>();
908
523
            MM_POLYGON_RINGS_COUNT nIRing;
909
523
            MM_N_VERTICES_TYPE nIVrtAcum;
910
911
523
            if (phMiraMonLayer->TopHeader.bIsMultipolygon)
912
229
            {
913
229
                OGRMultiPolygon *poMP = nullptr;
914
915
229
                poGeom = new OGRMultiPolygon();
916
229
                poMP = poGeom->toMultiPolygon();
917
918
                // Get X,Y (Z) n times MiraMon has no multilines
919
229
                if (MMGetGeoFeatureFromVector(phMiraMonLayer, nIElem))
920
114
                {
921
114
                    CPLError(CE_Failure, CPLE_AppDefined, "Wrong file format.");
922
114
                    delete poGeom;
923
114
                    return nullptr;
924
114
                }
925
926
115
                nIVrtAcum = 0;
927
115
                if (!(phMiraMonLayer->ReadFeature.flag_VFG[0] &
928
115
                      MM_EXTERIOR_ARC_SIDE))
929
5
                {
930
5
                    CPLError(CE_Failure, CPLE_NoWriteAccess,
931
5
                             "Wrong polygon format.");
932
5
                    delete poGeom;
933
5
                    return nullptr;
934
5
                }
935
936
5.09k
                for (nIRing = 0; nIRing < phMiraMonLayer->ReadFeature.nNRings;
937
4.98k
                     nIRing++)
938
4.98k
                {
939
4.98k
                    auto poRing = std::make_unique<OGRLinearRing>();
940
941
4.98k
                    for (MM_N_VERTICES_TYPE nIVrt = 0;
942
44.6M
                         nIVrt <
943
44.6M
                         phMiraMonLayer->ReadFeature.pNCoordRing[nIRing];
944
44.6M
                         nIVrt++)
945
44.6M
                    {
946
44.6M
                        if (phMiraMonLayer->TopHeader.bIs3d)
947
3.84M
                        {
948
3.84M
                            poRing->addPoint(
949
3.84M
                                phMiraMonLayer->ReadFeature.pCoord[nIVrtAcum]
950
3.84M
                                    .dfX,
951
3.84M
                                phMiraMonLayer->ReadFeature.pCoord[nIVrtAcum]
952
3.84M
                                    .dfY,
953
3.84M
                                phMiraMonLayer->ReadFeature.pZCoord[nIVrtAcum]);
954
3.84M
                        }
955
40.7M
                        else
956
40.7M
                        {
957
40.7M
                            poRing->addPoint(
958
40.7M
                                phMiraMonLayer->ReadFeature.pCoord[nIVrtAcum]
959
40.7M
                                    .dfX,
960
40.7M
                                phMiraMonLayer->ReadFeature.pCoord[nIVrtAcum]
961
40.7M
                                    .dfY);
962
40.7M
                        }
963
964
44.6M
                        nIVrtAcum++;
965
44.6M
                    }
966
967
                    // If I'm going to start a new polygon...
968
4.98k
                    if ((nIRing + 1 < phMiraMonLayer->ReadFeature.nNRings &&
969
4.98k
                         ((phMiraMonLayer->ReadFeature.flag_VFG[nIRing + 1]) &
970
4.87k
                          MM_EXTERIOR_ARC_SIDE)) ||
971
4.98k
                        nIRing + 1 >= phMiraMonLayer->ReadFeature.nNRings)
972
3.92k
                    {
973
3.92k
                        poPoly->addRingDirectly(poRing.release());
974
3.92k
                        poMP->addGeometryDirectly(poPoly.release());
975
3.92k
                        poPoly = std::make_unique<OGRPolygon>();
976
3.92k
                    }
977
1.05k
                    else
978
1.05k
                        poPoly->addRingDirectly(poRing.release());
979
4.98k
                }
980
110
            }
981
294
            else
982
294
            {
983
294
                OGRPolygon *poP = nullptr;
984
985
294
                poGeom = new OGRPolygon();
986
294
                poP = poGeom->toPolygon();
987
988
                // Get X,Y (Z) n times because MiraMon has no multilinetrings
989
294
                if (MMGetGeoFeatureFromVector(phMiraMonLayer, nIElem))
990
167
                {
991
167
                    CPLError(CE_Failure, CPLE_AppDefined, "Wrong file format.");
992
167
                    delete poGeom;
993
167
                    return nullptr;
994
167
                }
995
996
127
                if (phMiraMonLayer->ReadFeature.nNRings &&
997
127
                    phMiraMonLayer->ReadFeature.nNumpCoord)
998
84
                {
999
84
                    nIVrtAcum = 0;
1000
84
                    if (!(phMiraMonLayer->ReadFeature.flag_VFG[0] &
1001
84
                          MM_EXTERIOR_ARC_SIDE))
1002
1
                    {
1003
1
                        CPLError(CE_Failure, CPLE_AssertionFailed,
1004
1
                                 "Wrong polygon format.");
1005
1
                        delete poGeom;
1006
1
                        return nullptr;
1007
1
                    }
1008
1009
83
                    for (nIRing = 0;
1010
1.16k
                         nIRing < phMiraMonLayer->ReadFeature.nNRings; nIRing++)
1011
1.07k
                    {
1012
1.07k
                        auto poRing = std::make_unique<OGRLinearRing>();
1013
1014
1.07k
                        for (MM_N_VERTICES_TYPE nIVrt = 0;
1015
861k
                             nIVrt <
1016
861k
                             phMiraMonLayer->ReadFeature.pNCoordRing[nIRing];
1017
859k
                             nIVrt++)
1018
859k
                        {
1019
859k
                            if (phMiraMonLayer->TopHeader.bIs3d)
1020
818k
                            {
1021
818k
                                poRing->addPoint(phMiraMonLayer->ReadFeature
1022
818k
                                                     .pCoord[nIVrtAcum]
1023
818k
                                                     .dfX,
1024
818k
                                                 phMiraMonLayer->ReadFeature
1025
818k
                                                     .pCoord[nIVrtAcum]
1026
818k
                                                     .dfY,
1027
818k
                                                 phMiraMonLayer->ReadFeature
1028
818k
                                                     .pZCoord[nIVrtAcum]);
1029
818k
                            }
1030
41.3k
                            else
1031
41.3k
                            {
1032
41.3k
                                poRing->addPoint(phMiraMonLayer->ReadFeature
1033
41.3k
                                                     .pCoord[nIVrtAcum]
1034
41.3k
                                                     .dfX,
1035
41.3k
                                                 phMiraMonLayer->ReadFeature
1036
41.3k
                                                     .pCoord[nIVrtAcum]
1037
41.3k
                                                     .dfY);
1038
41.3k
                            }
1039
1040
859k
                            nIVrtAcum++;
1041
859k
                        }
1042
1.07k
                        poP->addRingDirectly(poRing.release());
1043
1.07k
                    }
1044
83
                }
1045
127
            }
1046
1047
236
            break;
1048
19.2k
    }
1049
1050
18.4k
    if (poGeom == nullptr)
1051
0
        return nullptr;
1052
1053
    /* -------------------------------------------------------------------- */
1054
    /*      Create feature.                                                 */
1055
    /* -------------------------------------------------------------------- */
1056
18.4k
    auto poFeature = std::make_unique<OGRFeature>(m_poFeatureDefn);
1057
18.4k
    poGeom->assignSpatialReference(m_poSRS);
1058
18.4k
    poFeature->SetGeometryDirectly(poGeom);
1059
1060
    /* -------------------------------------------------------------------- */
1061
    /*      Process field values if its possible.                           */
1062
    /* -------------------------------------------------------------------- */
1063
18.4k
    if (phMiraMonLayer->pMMBDXP &&
1064
18.4k
        (MM_EXT_DBF_N_RECORDS)nIElem < phMiraMonLayer->pMMBDXP->nRecords)
1065
12.8k
    {
1066
12.8k
        MM_EXT_DBF_N_FIELDS nIField;
1067
1068
319k
        for (nIField = 0; nIField < phMiraMonLayer->pMMBDXP->nFields; nIField++)
1069
306k
        {
1070
306k
            if (MMResizeStringToOperateIfNeeded(
1071
306k
                    phMiraMonLayer,
1072
306k
                    phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField + 1))
1073
1
            {
1074
1
                return nullptr;
1075
1
            }
1076
1077
306k
            if (poFeature->GetDefnRef()->GetFieldDefn(nIField)->GetType() ==
1078
306k
                    OFTStringList ||
1079
306k
                (poFeature->GetDefnRef()->GetFieldDefn(nIField)->GetType() ==
1080
302k
                     OFTString &&
1081
302k
                 poFeature->GetDefnRef()->GetFieldDefn(nIField)->GetSubType() ==
1082
248k
                     OFSTJSON))
1083
4.22k
            {
1084
4.22k
                if (!phMiraMonLayer->pMultRecordIndex ||
1085
4.22k
                    phMiraMonLayer->pMultRecordIndex[nIElem].nMR == 0)
1086
3.60k
                {
1087
3.60k
                    memset(
1088
3.60k
                        phMiraMonLayer->szStringToOperate, 0,
1089
3.60k
                        phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField);
1090
3.60k
                    continue;
1091
3.60k
                }
1092
624
                if (poFeature->GetDefnRef()
1093
624
                        ->GetFieldDefn(nIField)
1094
624
                        ->GetSubType() == OFSTJSON)
1095
0
                {
1096
0
                    if (MMResizeStringToOperateIfNeeded(
1097
0
                            phMiraMonLayer,
1098
0
                            phMiraMonLayer->pMMBDXP->BytesPerRecord +
1099
0
                                2 * phMiraMonLayer->pMultRecordIndex[nIElem]
1100
0
                                        .nMR +
1101
0
                                8))
1102
0
                    {
1103
0
                        return nullptr;
1104
0
                    }
1105
0
                    std::string szStringToOperate = "[";
1106
0
                    for (nIRecord = 0;
1107
0
                         nIRecord <
1108
0
                         phMiraMonLayer->pMultRecordIndex[nIElem].nMR;
1109
0
                         nIRecord++)
1110
0
                    {
1111
0
                        GoToFieldOfMultipleRecord(nIElem, nIRecord, nIField);
1112
1113
0
                        VSIFReadL(phMiraMonLayer->szStringToOperate,
1114
0
                                  phMiraMonLayer->pMMBDXP->pField[nIField]
1115
0
                                      .BytesPerField,
1116
0
                                  1, phMiraMonLayer->pMMBDXP->pfDataBase);
1117
0
                        phMiraMonLayer
1118
0
                            ->szStringToOperate[phMiraMonLayer->pMMBDXP
1119
0
                                                    ->pField[nIField]
1120
0
                                                    .BytesPerField] = '\0';
1121
0
                        MM_RemoveLeadingWhitespaceOfString(
1122
0
                            phMiraMonLayer->szStringToOperate);
1123
0
                        MM_RemoveWhitespacesFromEndOfString(
1124
0
                            phMiraMonLayer->szStringToOperate);
1125
1126
0
                        if (phMiraMonLayer->pMMBDXP->CharSet ==
1127
0
                            MM_JOC_CARAC_OEM850_DBASE)
1128
0
                            MM_oemansi_n(
1129
0
                                phMiraMonLayer->szStringToOperate,
1130
0
                                phMiraMonLayer->pMMBDXP->pField[nIField]
1131
0
                                    .BytesPerField);
1132
1133
0
                        if (phMiraMonLayer->pMMBDXP->CharSet !=
1134
0
                            MM_JOC_CARAC_UTF8_DBF)
1135
0
                        {
1136
                            // MiraMon encoding is ISO 8859-1 (Latin1) -> Recode to UTF-8
1137
0
                            char *pszString =
1138
0
                                CPLRecode(phMiraMonLayer->szStringToOperate,
1139
0
                                          CPL_ENC_ISO8859_1, CPL_ENC_UTF8);
1140
1141
0
                            CPLStrlcpy(
1142
0
                                phMiraMonLayer->szStringToOperate, pszString,
1143
0
                                (size_t)phMiraMonLayer->pMMBDXP->pField[nIField]
1144
0
                                        .BytesPerField +
1145
0
                                    1);
1146
1147
0
                            CPLFree(pszString);
1148
0
                        }
1149
0
                        szStringToOperate.append(
1150
0
                            phMiraMonLayer->szStringToOperate);
1151
1152
0
                        if (nIRecord <
1153
0
                            phMiraMonLayer->pMultRecordIndex[nIElem].nMR - 1)
1154
0
                        {
1155
0
                            szStringToOperate.append(",");
1156
0
                        }
1157
0
                        else
1158
0
                        {
1159
0
                            szStringToOperate.append("]");
1160
0
                        }
1161
0
                    }
1162
0
                    poFeature->SetField(nIField, szStringToOperate.c_str());
1163
0
                }
1164
624
                else
1165
624
                {
1166
624
                    CPLStringList aosValues;
1167
624
                    for (nIRecord = 0;
1168
355k
                         nIRecord <
1169
355k
                         phMiraMonLayer->pMultRecordIndex[nIElem].nMR;
1170
354k
                         nIRecord++)
1171
354k
                    {
1172
354k
                        GoToFieldOfMultipleRecord(nIElem, nIRecord, nIField);
1173
354k
                        memset(phMiraMonLayer->szStringToOperate, 0,
1174
354k
                               phMiraMonLayer->pMMBDXP->pField[nIField]
1175
354k
                                   .BytesPerField);
1176
354k
                        VSIFReadL(phMiraMonLayer->szStringToOperate,
1177
354k
                                  phMiraMonLayer->pMMBDXP->pField[nIField]
1178
354k
                                      .BytesPerField,
1179
354k
                                  1, phMiraMonLayer->pMMBDXP->pfDataBase);
1180
354k
                        phMiraMonLayer
1181
354k
                            ->szStringToOperate[phMiraMonLayer->pMMBDXP
1182
354k
                                                    ->pField[nIField]
1183
354k
                                                    .BytesPerField] = '\0';
1184
354k
                        MM_RemoveWhitespacesFromEndOfString(
1185
354k
                            phMiraMonLayer->szStringToOperate);
1186
1187
354k
                        if (phMiraMonLayer->pMMBDXP->CharSet ==
1188
354k
                            MM_JOC_CARAC_OEM850_DBASE)
1189
104k
                            MM_oemansi_n(
1190
104k
                                phMiraMonLayer->szStringToOperate,
1191
104k
                                phMiraMonLayer->pMMBDXP->pField[nIField]
1192
104k
                                    .BytesPerField);
1193
1194
354k
                        if (phMiraMonLayer->pMMBDXP->CharSet !=
1195
354k
                            MM_JOC_CARAC_UTF8_DBF)
1196
352k
                        {
1197
                            // MiraMon encoding is ISO 8859-1 (Latin1) -> Recode to UTF-8
1198
352k
                            char *pszString =
1199
352k
                                CPLRecode(phMiraMonLayer->szStringToOperate,
1200
352k
                                          CPL_ENC_ISO8859_1, CPL_ENC_UTF8);
1201
1202
352k
                            CPLStrlcpy(
1203
352k
                                phMiraMonLayer->szStringToOperate, pszString,
1204
352k
                                (size_t)phMiraMonLayer->pMMBDXP->pField[nIField]
1205
352k
                                        .BytesPerField +
1206
352k
                                    1);
1207
1208
352k
                            CPLFree(pszString);
1209
352k
                        }
1210
354k
                        aosValues.AddString(phMiraMonLayer->szStringToOperate);
1211
354k
                    }
1212
624
                    poFeature->SetField(nIField, aosValues.List());
1213
624
                }
1214
624
            }
1215
302k
            else if (poFeature->GetDefnRef()
1216
302k
                         ->GetFieldDefn(nIField)
1217
302k
                         ->GetType() == OFTString)
1218
248k
            {
1219
248k
                if (!phMiraMonLayer->pMultRecordIndex ||
1220
248k
                    phMiraMonLayer->pMultRecordIndex[nIElem].nMR == 0)
1221
246k
                {
1222
246k
                    memset(
1223
246k
                        phMiraMonLayer->szStringToOperate, 0,
1224
246k
                        phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField);
1225
246k
                    continue;
1226
246k
                }
1227
2.24k
                if (phMiraMonLayer->iMultiRecord !=
1228
2.24k
                    MM_MULTIRECORD_NO_MULTIRECORD)
1229
0
                {
1230
0
                    if (phMiraMonLayer->iMultiRecord == MM_MULTIRECORD_LAST)
1231
0
                        GoToFieldOfMultipleRecord(
1232
0
                            nIElem,
1233
0
                            phMiraMonLayer->pMultRecordIndex[nIElem].nMR - 1,
1234
0
                            nIField);
1235
0
                    else if ((MM_EXT_DBF_N_MULTIPLE_RECORDS)
1236
0
                                 phMiraMonLayer->iMultiRecord <
1237
0
                             phMiraMonLayer->pMultRecordIndex[nIElem].nMR)
1238
0
                        GoToFieldOfMultipleRecord(
1239
0
                            nIElem,
1240
0
                            (MM_EXT_DBF_N_MULTIPLE_RECORDS)
1241
0
                                phMiraMonLayer->iMultiRecord,
1242
0
                            nIField);
1243
0
                    else
1244
0
                    {
1245
0
                        memset(phMiraMonLayer->szStringToOperate, 0,
1246
0
                               phMiraMonLayer->pMMBDXP->pField[nIField]
1247
0
                                   .BytesPerField);
1248
0
                        continue;
1249
0
                    }
1250
0
                }
1251
2.24k
                else
1252
2.24k
                    GoToFieldOfMultipleRecord(nIElem, 0, nIField);
1253
1254
2.24k
                memset(phMiraMonLayer->szStringToOperate, 0,
1255
2.24k
                       phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField);
1256
2.24k
                VSIFReadL(
1257
2.24k
                    phMiraMonLayer->szStringToOperate,
1258
2.24k
                    phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField, 1,
1259
2.24k
                    phMiraMonLayer->pMMBDXP->pfDataBase);
1260
2.24k
                phMiraMonLayer
1261
2.24k
                    ->szStringToOperate[phMiraMonLayer->pMMBDXP->pField[nIField]
1262
2.24k
                                            .BytesPerField] = '\0';
1263
2.24k
                MM_RemoveWhitespacesFromEndOfString(
1264
2.24k
                    phMiraMonLayer->szStringToOperate);
1265
1266
2.24k
                if (phMiraMonLayer->pMMBDXP->CharSet ==
1267
2.24k
                    MM_JOC_CARAC_OEM850_DBASE)
1268
616
                    MM_oemansi(phMiraMonLayer->szStringToOperate);
1269
1270
2.24k
                if (phMiraMonLayer->pMMBDXP->CharSet != MM_JOC_CARAC_UTF8_DBF)
1271
1.31k
                {
1272
                    // MiraMon encoding is ISO 8859-1 (Latin1) -> Recode to UTF-8
1273
1.31k
                    char *pszString =
1274
1.31k
                        CPLRecode(phMiraMonLayer->szStringToOperate,
1275
1.31k
                                  CPL_ENC_ISO8859_1, CPL_ENC_UTF8);
1276
1.31k
                    CPLStrlcpy(phMiraMonLayer->szStringToOperate, pszString,
1277
1.31k
                               (size_t)phMiraMonLayer->pMMBDXP->pField[nIField]
1278
1.31k
                                       .BytesPerField +
1279
1.31k
                                   1);
1280
1.31k
                    CPLFree(pszString);
1281
1.31k
                }
1282
2.24k
                poFeature->SetField(nIField, phMiraMonLayer->szStringToOperate);
1283
2.24k
            }
1284
53.8k
            else if (poFeature->GetDefnRef()
1285
53.8k
                             ->GetFieldDefn(nIField)
1286
53.8k
                             ->GetType() == OFTIntegerList ||
1287
53.8k
                     poFeature->GetDefnRef()
1288
44.6k
                             ->GetFieldDefn(nIField)
1289
44.6k
                             ->GetType() == OFTRealList)
1290
11.6k
            {
1291
11.6k
                if (!phMiraMonLayer->pMultRecordIndex ||
1292
11.6k
                    phMiraMonLayer->pMultRecordIndex[nIElem].nMR == 0)
1293
9.20k
                {
1294
9.20k
                    memset(
1295
9.20k
                        phMiraMonLayer->szStringToOperate, 0,
1296
9.20k
                        phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField);
1297
9.20k
                    continue;
1298
9.20k
                }
1299
2.39k
                MM_EXT_DBF_N_MULTIPLE_RECORDS nRealMR = 0;
1300
2.39k
                for (nIRecord = 0;
1301
159k
                     nIRecord < phMiraMonLayer->pMultRecordIndex[nIElem].nMR;
1302
157k
                     nIRecord++)
1303
157k
                {
1304
157k
                    GoToFieldOfMultipleRecord(nIElem, nIRecord, nIField);
1305
157k
                    memset(
1306
157k
                        phMiraMonLayer->szStringToOperate, 0,
1307
157k
                        phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField);
1308
157k
                    VSIFReadL(
1309
157k
                        phMiraMonLayer->szStringToOperate,
1310
157k
                        phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField,
1311
157k
                        1, phMiraMonLayer->pMMBDXP->pfDataBase);
1312
157k
                    phMiraMonLayer->szStringToOperate[phMiraMonLayer->pMMBDXP
1313
157k
                                                          ->pField[nIField]
1314
157k
                                                          .BytesPerField] =
1315
157k
                        '\0';
1316
1317
157k
                    if (!MMIsEmptyString(phMiraMonLayer->szStringToOperate))
1318
155k
                    {
1319
155k
                        if (poFeature->GetDefnRef()
1320
155k
                                    ->GetFieldDefn(nIField)
1321
155k
                                    ->GetType() == OFTIntegerList &&
1322
155k
                            poFeature->GetDefnRef()
1323
135k
                                    ->GetFieldDefn(nIField)
1324
135k
                                    ->GetSubType() == OFSTBoolean)
1325
65.4k
                        {
1326
65.4k
                            if (*phMiraMonLayer->szStringToOperate == 'T' ||
1327
65.4k
                                *phMiraMonLayer->szStringToOperate == 'S' ||
1328
65.4k
                                *phMiraMonLayer->szStringToOperate == 'Y')
1329
191
                                padfValues[nRealMR] = 1;
1330
65.2k
                            else
1331
65.2k
                                padfValues[nRealMR] = 0;
1332
65.4k
                        }
1333
89.7k
                        else
1334
89.7k
                        {
1335
89.7k
                            padfValues[nRealMR] =
1336
89.7k
                                atof(phMiraMonLayer->szStringToOperate);
1337
89.7k
                        }
1338
155k
                        nRealMR++;
1339
155k
                    }
1340
157k
                }
1341
1342
2.39k
                poFeature->SetField(nIField, nRealMR, padfValues);
1343
2.39k
            }
1344
42.2k
            else if (poFeature->GetDefnRef()
1345
42.2k
                         ->GetFieldDefn(nIField)
1346
42.2k
                         ->GetType() == OFTInteger64List)
1347
1.27k
            {
1348
1.27k
                if (!phMiraMonLayer->pMultRecordIndex ||
1349
1.27k
                    phMiraMonLayer->pMultRecordIndex[nIElem].nMR == 0)
1350
1.00k
                {
1351
1.00k
                    memset(
1352
1.00k
                        phMiraMonLayer->szStringToOperate, 0,
1353
1.00k
                        phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField);
1354
1.00k
                    continue;
1355
1.00k
                }
1356
275
                MM_EXT_DBF_N_MULTIPLE_RECORDS nRealMR = 0;
1357
275
                for (nIRecord = 0;
1358
55.7k
                     nIRecord < phMiraMonLayer->pMultRecordIndex[nIElem].nMR;
1359
55.5k
                     nIRecord++)
1360
55.5k
                {
1361
55.5k
                    GoToFieldOfMultipleRecord(nIElem, nIRecord, nIField);
1362
55.5k
                    memset(
1363
55.5k
                        phMiraMonLayer->szStringToOperate, 0,
1364
55.5k
                        phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField);
1365
55.5k
                    VSIFReadL(
1366
55.5k
                        phMiraMonLayer->szStringToOperate,
1367
55.5k
                        phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField,
1368
55.5k
                        1, phMiraMonLayer->pMMBDXP->pfDataBase);
1369
55.5k
                    phMiraMonLayer->szStringToOperate[phMiraMonLayer->pMMBDXP
1370
55.5k
                                                          ->pField[nIField]
1371
55.5k
                                                          .BytesPerField] =
1372
55.5k
                        '\0';
1373
1374
55.5k
                    if (!MMIsEmptyString(phMiraMonLayer->szStringToOperate))
1375
55.1k
                    {
1376
55.1k
                        pnInt64Values[nRealMR] =
1377
55.1k
                            CPLAtoGIntBig(phMiraMonLayer->szStringToOperate);
1378
55.1k
                        nRealMR++;
1379
55.1k
                    }
1380
55.5k
                }
1381
1382
275
                poFeature->SetField(nIField, nRealMR, pnInt64Values);
1383
275
            }
1384
40.9k
            else if (poFeature->GetDefnRef()
1385
40.9k
                             ->GetFieldDefn(nIField)
1386
40.9k
                             ->GetType() == OFTInteger ||
1387
40.9k
                     poFeature->GetDefnRef()
1388
24.3k
                             ->GetFieldDefn(nIField)
1389
24.3k
                             ->GetType() == OFTInteger64 ||
1390
40.9k
                     poFeature->GetDefnRef()
1391
18.8k
                             ->GetFieldDefn(nIField)
1392
18.8k
                             ->GetType() == OFTReal)
1393
37.6k
            {
1394
37.6k
                if (!phMiraMonLayer->pMultRecordIndex ||
1395
37.6k
                    phMiraMonLayer->pMultRecordIndex[nIElem].nMR == 0)
1396
33.3k
                {
1397
33.3k
                    memset(
1398
33.3k
                        phMiraMonLayer->szStringToOperate, 0,
1399
33.3k
                        phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField);
1400
33.3k
                    continue;
1401
33.3k
                }
1402
4.32k
                if (phMiraMonLayer->iMultiRecord !=
1403
4.32k
                    MM_MULTIRECORD_NO_MULTIRECORD)
1404
0
                {
1405
0
                    if (phMiraMonLayer->iMultiRecord == MM_MULTIRECORD_LAST)
1406
0
                    {
1407
0
                        GoToFieldOfMultipleRecord(
1408
0
                            nIElem,
1409
0
                            phMiraMonLayer->pMultRecordIndex[nIElem].nMR - 1,
1410
0
                            nIField);
1411
0
                    }
1412
0
                    else if ((MM_EXT_DBF_N_MULTIPLE_RECORDS)
1413
0
                                 phMiraMonLayer->iMultiRecord <
1414
0
                             phMiraMonLayer->pMultRecordIndex[nIElem].nMR)
1415
0
                    {
1416
0
                        GoToFieldOfMultipleRecord(
1417
0
                            nIElem,
1418
0
                            (MM_EXT_DBF_N_MULTIPLE_RECORDS)
1419
0
                                phMiraMonLayer->iMultiRecord,
1420
0
                            nIField);
1421
0
                    }
1422
0
                    else
1423
0
                    {
1424
0
                        memset(phMiraMonLayer->szStringToOperate, 0,
1425
0
                               phMiraMonLayer->pMMBDXP->pField[nIField]
1426
0
                                   .BytesPerField);
1427
0
                        continue;
1428
0
                    }
1429
0
                }
1430
4.32k
                else
1431
4.32k
                    GoToFieldOfMultipleRecord(nIElem, 0, nIField);
1432
1433
4.32k
                memset(phMiraMonLayer->szStringToOperate, 0,
1434
4.32k
                       phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField);
1435
4.32k
                VSIFReadL(
1436
4.32k
                    phMiraMonLayer->szStringToOperate,
1437
4.32k
                    phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField, 1,
1438
4.32k
                    phMiraMonLayer->pMMBDXP->pfDataBase);
1439
4.32k
                phMiraMonLayer
1440
4.32k
                    ->szStringToOperate[phMiraMonLayer->pMMBDXP->pField[nIField]
1441
4.32k
                                            .BytesPerField] = '\0';
1442
4.32k
                MM_RemoveWhitespacesFromEndOfString(
1443
4.32k
                    phMiraMonLayer->szStringToOperate);
1444
1445
4.32k
                if (poFeature->GetDefnRef()->GetFieldDefn(nIField)->GetType() ==
1446
4.32k
                    OFTInteger64)
1447
374
                {
1448
374
                    poFeature->SetField(
1449
374
                        nIField,
1450
374
                        CPLAtoGIntBig(phMiraMonLayer->szStringToOperate));
1451
374
                }
1452
3.95k
                else
1453
3.95k
                {
1454
3.95k
                    if (poFeature->GetDefnRef()
1455
3.95k
                                ->GetFieldDefn(nIField)
1456
3.95k
                                ->GetType() == OFTInteger &&
1457
3.95k
                        poFeature->GetDefnRef()
1458
3.29k
                                ->GetFieldDefn(nIField)
1459
3.29k
                                ->GetSubType() == OFSTBoolean)
1460
904
                    {
1461
904
                        if (*phMiraMonLayer->szStringToOperate == 'T' ||
1462
904
                            *phMiraMonLayer->szStringToOperate == 'S' ||
1463
904
                            *phMiraMonLayer->szStringToOperate == 'Y')
1464
244
                            poFeature->SetField(nIField, 1);
1465
660
                        else
1466
660
                            poFeature->SetField(nIField, 0);
1467
904
                    }
1468
3.04k
                    else
1469
3.04k
                    {
1470
3.04k
                        poFeature->SetField(
1471
3.04k
                            nIField, atof(phMiraMonLayer->szStringToOperate));
1472
3.04k
                    }
1473
3.95k
                }
1474
4.32k
            }
1475
3.28k
            else if (poFeature->GetDefnRef()
1476
3.28k
                         ->GetFieldDefn(nIField)
1477
3.28k
                         ->GetType() == OFTDate)
1478
3.28k
            {
1479
3.28k
                if (!phMiraMonLayer->pMultRecordIndex ||
1480
3.28k
                    phMiraMonLayer->pMultRecordIndex[nIElem].nMR == 0)
1481
2.82k
                {
1482
2.82k
                    memset(
1483
2.82k
                        phMiraMonLayer->szStringToOperate, 0,
1484
2.82k
                        phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField);
1485
2.82k
                    continue;
1486
2.82k
                }
1487
462
                if (phMiraMonLayer->iMultiRecord !=
1488
462
                    MM_MULTIRECORD_NO_MULTIRECORD)
1489
0
                {
1490
0
                    if (phMiraMonLayer->iMultiRecord == MM_MULTIRECORD_LAST)
1491
0
                        GoToFieldOfMultipleRecord(
1492
0
                            nIElem,
1493
0
                            phMiraMonLayer->pMultRecordIndex[nIElem].nMR - 1,
1494
0
                            nIField);
1495
0
                    else if ((MM_EXT_DBF_N_MULTIPLE_RECORDS)
1496
0
                                 phMiraMonLayer->iMultiRecord <
1497
0
                             phMiraMonLayer->pMultRecordIndex[nIElem].nMR)
1498
0
                        GoToFieldOfMultipleRecord(
1499
0
                            nIElem,
1500
0
                            (MM_EXT_DBF_N_MULTIPLE_RECORDS)
1501
0
                                phMiraMonLayer->iMultiRecord,
1502
0
                            nIField);
1503
0
                    else
1504
0
                    {
1505
0
                        memset(phMiraMonLayer->szStringToOperate, 0,
1506
0
                               phMiraMonLayer->pMMBDXP->pField[nIField]
1507
0
                                   .BytesPerField);
1508
0
                        continue;
1509
0
                    }
1510
0
                }
1511
462
                else
1512
462
                    GoToFieldOfMultipleRecord(nIElem, 0, nIField);
1513
1514
462
                memset(phMiraMonLayer->szStringToOperate, 0,
1515
462
                       phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField);
1516
462
                VSIFReadL(
1517
462
                    phMiraMonLayer->szStringToOperate,
1518
462
                    phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField, 1,
1519
462
                    phMiraMonLayer->pMMBDXP->pfDataBase);
1520
462
                phMiraMonLayer
1521
462
                    ->szStringToOperate[phMiraMonLayer->pMMBDXP->pField[nIField]
1522
462
                                            .BytesPerField] = '\0';
1523
1524
462
                MM_RemoveWhitespacesFromEndOfString(
1525
462
                    phMiraMonLayer->szStringToOperate);
1526
462
                if (!MMIsEmptyString(phMiraMonLayer->szStringToOperate))
1527
293
                {
1528
293
                    char pszDate_5[5];
1529
293
                    char pszDate_3[3];
1530
293
                    int Year, Month, Day;
1531
1532
293
                    CPLStrlcpy(pszDate_5, phMiraMonLayer->szStringToOperate, 5);
1533
293
                    pszDate_5[4] = '\0';
1534
293
                    Year = atoi(pszDate_5);
1535
1536
293
                    CPLStrlcpy(pszDate_3, phMiraMonLayer->szStringToOperate + 4,
1537
293
                               3);
1538
293
                    (pszDate_3)[2] = '\0';
1539
293
                    Month = atoi(pszDate_3);
1540
1541
293
                    CPLStrlcpy(pszDate_3, phMiraMonLayer->szStringToOperate + 6,
1542
293
                               3);
1543
293
                    (pszDate_3)[2] = '\0';
1544
293
                    Day = atoi(pszDate_3);
1545
1546
293
                    poFeature->SetField(nIField, Year, Month, Day);
1547
293
                }
1548
169
                else
1549
169
                    poFeature->SetField(nIField,
1550
169
                                        phMiraMonLayer->szStringToOperate);
1551
462
            }
1552
306k
        }
1553
12.8k
    }
1554
1555
    // Even in case of polygons, where the first feature is jumped
1556
    // the ID of the first feature has to be 0, the second, 1,...
1557
18.4k
    poFeature->SetFID(nFeatureId);
1558
1559
18.4k
    m_nFeaturesRead++;
1560
18.4k
    return poFeature.release();
1561
18.4k
}
1562
1563
/****************************************************************************/
1564
/*                         GetFeatureCount()                                */
1565
/****************************************************************************/
1566
GIntBig OGRMiraMonLayer::GetFeatureCount(int bForce)
1567
0
{
1568
0
    if (!phMiraMonLayer || m_poFilterGeom != nullptr ||
1569
0
        m_poAttrQuery != nullptr)
1570
0
        return OGRLayer::GetFeatureCount(bForce);
1571
1572
0
    if (phMiraMonLayer->bIsPolygon)
1573
0
    {
1574
0
        return std::max((GIntBig)0,
1575
0
                        (GIntBig)(phMiraMonLayer->TopHeader.nElemCount - 1));
1576
0
    }
1577
0
    return (GIntBig)phMiraMonLayer->TopHeader.nElemCount;
1578
0
}
1579
1580
/****************************************************************************/
1581
/*                      MMProcessMultiGeometry()                            */
1582
/****************************************************************************/
1583
OGRErr OGRMiraMonLayer::MMProcessMultiGeometry(OGRGeometryH hGeom,
1584
                                               OGRFeature *poFeature)
1585
1586
1.14k
{
1587
1.14k
    OGRErr eErr = OGRERR_NONE;
1588
1.14k
    OGRGeometry *poGeom = OGRGeometry::FromHandle(hGeom);
1589
1590
1.14k
    if (poGeom == nullptr)
1591
0
    {
1592
0
        CPLError(CE_Failure, CPLE_AppDefined,
1593
0
                 "Features without geometry not supported by MiraMon writer.");
1594
0
        return OGRERR_FAILURE;
1595
0
    }
1596
1597
    // Multigeometry field processing (just in case of a MG inside a MG)
1598
1.14k
    if (wkbFlatten(poGeom->getGeometryType()) == wkbGeometryCollection)
1599
0
    {
1600
0
        int nGeom = OGR_G_GetGeometryCount(OGRGeometry::ToHandle(poGeom));
1601
0
        for (int iGeom = 0; iGeom < nGeom; iGeom++)
1602
0
        {
1603
0
            OGRGeometryH poSubGeometry =
1604
0
                OGR_G_GetGeometryRef(OGRGeometry::ToHandle(poGeom), iGeom);
1605
0
            eErr = MMProcessMultiGeometry(poSubGeometry, poFeature);
1606
0
            if (eErr != OGRERR_NONE)
1607
0
                return eErr;
1608
0
        }
1609
0
        return eErr;
1610
0
    }
1611
    // Converting multilines and multi points to simple ones
1612
1.14k
    if (wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString ||
1613
1.14k
        wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint)
1614
262
    {
1615
262
        int nGeom = OGR_G_GetGeometryCount(OGRGeometry::ToHandle(poGeom));
1616
286
        for (int iGeom = 0; iGeom < nGeom; iGeom++)
1617
24
        {
1618
24
            OGRGeometryH poSubGeometry =
1619
24
                OGR_G_GetGeometryRef(OGRGeometry::ToHandle(poGeom), iGeom);
1620
24
            eErr = MMProcessGeometry(poSubGeometry, poFeature, (iGeom == 0));
1621
24
            if (eErr != OGRERR_NONE)
1622
0
                return eErr;
1623
24
        }
1624
262
        return eErr;
1625
262
    }
1626
1627
    // Processing a simple geometry
1628
884
    return MMProcessGeometry(OGRGeometry::ToHandle(poGeom), poFeature, TRUE);
1629
1.14k
}
1630
1631
/****************************************************************************/
1632
/*                           MMProcessGeometry()                            */
1633
/****************************************************************************/
1634
OGRErr OGRMiraMonLayer::MMProcessGeometry(OGRGeometryH hGeom,
1635
                                          OGRFeature *poFeature,
1636
                                          MM_BOOLEAN bcalculateRecord)
1637
1638
345k
{
1639
345k
    OGRErr eErr = OGRERR_NONE;
1640
345k
    OGRGeometry *poGeom = nullptr;
1641
345k
    if (hGeom)
1642
908
    {
1643
908
        poGeom = OGRGeometry::FromHandle(hGeom);
1644
1645
        // Translating types from GDAL to MiraMon
1646
908
        int eLT = poGeom->getGeometryType();
1647
908
        switch (wkbFlatten(eLT))
1648
908
        {
1649
296
            case wkbPoint:
1650
296
                phMiraMonLayer = &hMiraMonLayerPNT;
1651
296
                if (OGR_G_Is3D(hGeom))
1652
29
                    phMiraMonLayer->eLT = MM_LayerType_Point3d;
1653
267
                else
1654
267
                    phMiraMonLayer->eLT = MM_LayerType_Point;
1655
296
                break;
1656
273
            case wkbLineString:
1657
273
                phMiraMonLayer = &hMiraMonLayerARC;
1658
273
                if (OGR_G_Is3D(hGeom))
1659
41
                    phMiraMonLayer->eLT = MM_LayerType_Arc3d;
1660
232
                else
1661
232
                    phMiraMonLayer->eLT = MM_LayerType_Arc;
1662
273
                break;
1663
242
            case wkbPolygon:
1664
291
            case wkbMultiPolygon:
1665
298
            case wkbPolyhedralSurface:
1666
305
            case wkbTIN:
1667
309
            case wkbTriangle:
1668
309
                phMiraMonLayer = &hMiraMonLayerPOL;
1669
309
                if (OGR_G_Is3D(hGeom))
1670
38
                    phMiraMonLayer->eLT = MM_LayerType_Pol3d;
1671
271
                else
1672
271
                    phMiraMonLayer->eLT = MM_LayerType_Pol;
1673
309
                break;
1674
0
            case wkbUnknown:
1675
30
            default:
1676
30
            {
1677
30
                CPLError(CE_Warning, CPLE_NotSupported,
1678
30
                         "MiraMon "
1679
30
                         "does not support geometry type '%d'",
1680
30
                         eLT);
1681
30
                return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
1682
0
            }
1683
908
        }
1684
908
    }
1685
344k
    else
1686
344k
    {
1687
        // Processing only the table. A DBF will be generated
1688
344k
        phMiraMonLayer = &hMiraMonLayerReadOrNonGeom;
1689
344k
        phMiraMonLayer->eLT = MM_LayerType_Unknown;
1690
344k
    }
1691
1692
    /* -------------------------------------------------------------------- */
1693
    /*      Field translation from GDAL to MiraMon                          */
1694
    /* -------------------------------------------------------------------- */
1695
    // Reset the object where read coordinates are going to be stored
1696
345k
    MMResetFeatureGeometry(&hMMFeature);
1697
345k
    if (bcalculateRecord)
1698
345k
    {
1699
345k
        MMResetFeatureRecord(&hMMFeature);
1700
345k
        if (!phMiraMonLayer->pLayerDB)
1701
822
        {
1702
822
            eErr = TranslateFieldsToMM();
1703
822
            if (eErr != OGRERR_NONE)
1704
0
                return eErr;
1705
822
        }
1706
        // Content field translation from GDAL to MiraMon
1707
345k
        eErr = TranslateFieldsValuesToMM(poFeature);
1708
345k
        if (eErr != OGRERR_NONE)
1709
0
        {
1710
0
            CPLDebugOnly("MiraMon", "Error in MMProcessGeometry()");
1711
0
            return eErr;
1712
0
        }
1713
345k
    }
1714
1715
    /* -------------------------------------------------------------------- */
1716
    /*      Write Geometry                                                  */
1717
    /* -------------------------------------------------------------------- */
1718
1719
    // Reads objects with coordinates and transform them to MiraMon
1720
345k
    if (poGeom)
1721
878
    {
1722
878
        eErr = MMLoadGeometry(OGRGeometry::ToHandle(poGeom));
1723
878
    }
1724
344k
    else
1725
344k
    {
1726
344k
        if (!phMiraMonLayer->bIsBeenInit)
1727
750
        {
1728
750
            phMiraMonLayer->bIsDBF = TRUE;
1729
750
            if (MMInitLayerByType(phMiraMonLayer))
1730
0
                eErr = OGRERR_FAILURE;
1731
1732
750
            phMiraMonLayer->bIsBeenInit = 1;
1733
750
        }
1734
344k
    }
1735
1736
    // Writes coordinates to the disk
1737
345k
    if (eErr == OGRERR_NONE)
1738
345k
        return MMWriteGeometry();
1739
0
    CPLDebugOnly("MiraMon", "Error in MMProcessGeometry()");
1740
0
    return eErr;
1741
345k
}
1742
1743
/****************************************************************************/
1744
/*                           ICreateFeature()                               */
1745
/****************************************************************************/
1746
1747
OGRErr OGRMiraMonLayer::ICreateFeature(OGRFeature *poFeature)
1748
1749
345k
{
1750
345k
    OGRErr eErr = OGRERR_NONE;
1751
1752
345k
    if (!m_bUpdate)
1753
0
    {
1754
0
        CPLError(CE_Failure, CPLE_NoWriteAccess,
1755
0
                 "Cannot create features on a read-only dataset.");
1756
0
        return OGRERR_FAILURE;
1757
0
    }
1758
1759
    /* -------------------------------------------------------------------- */
1760
    /*      Write out the feature                                           */
1761
    /* -------------------------------------------------------------------- */
1762
345k
    OGRGeometry *poGeom = poFeature->GetGeometryRef();
1763
1764
    // Processing a feature without geometry.
1765
345k
    if (poGeom == nullptr)
1766
344k
    {
1767
344k
        eErr = MMProcessGeometry(nullptr, poFeature, TRUE);
1768
344k
        if (phMiraMonLayer->bIsDBF && phMiraMonLayer->TopHeader.nElemCount > 0)
1769
142k
            poFeature->SetFID((GIntBig)phMiraMonLayer->TopHeader.nElemCount -
1770
142k
                              1);
1771
344k
        return eErr;
1772
344k
    }
1773
1774
    // Converting to simple geometries
1775
1.12k
    if (wkbFlatten(poGeom->getGeometryType()) == wkbGeometryCollection)
1776
97
    {
1777
97
        int nGeom = OGR_G_GetGeometryCount(OGRGeometry::ToHandle(poGeom));
1778
174
        for (int iGeom = 0; iGeom < nGeom; iGeom++)
1779
119
        {
1780
119
            OGRGeometryH poSubGeometry =
1781
119
                OGR_G_GetGeometryRef(OGRGeometry::ToHandle(poGeom), iGeom);
1782
119
            eErr = MMProcessMultiGeometry(poSubGeometry, poFeature);
1783
119
            if (eErr != OGRERR_NONE)
1784
42
                return eErr;
1785
119
        }
1786
1787
55
        return eErr;
1788
97
    }
1789
1790
    // Processing the geometry
1791
1.02k
    eErr = MMProcessMultiGeometry(OGRGeometry::ToHandle(poGeom), poFeature);
1792
1793
    // Set the FID from 0 index
1794
1.02k
    if (phMiraMonLayer)
1795
1.02k
    {
1796
1.02k
        if (phMiraMonLayer->bIsPolygon &&
1797
1.02k
            phMiraMonLayer->TopHeader.nElemCount > 1)
1798
278
            poFeature->SetFID((GIntBig)phMiraMonLayer->TopHeader.nElemCount -
1799
278
                              2);
1800
749
        else if (phMiraMonLayer->TopHeader.nElemCount > 0)
1801
632
            poFeature->SetFID((GIntBig)phMiraMonLayer->TopHeader.nElemCount -
1802
632
                              1);
1803
1.02k
    }
1804
1.02k
    return eErr;
1805
1.12k
}
1806
1807
/****************************************************************************/
1808
/*                          MMDumpVertices()                                */
1809
/****************************************************************************/
1810
1811
OGRErr OGRMiraMonLayer::MMDumpVertices(OGRGeometryH hGeom,
1812
                                       MM_BOOLEAN bExternalRing,
1813
                                       MM_BOOLEAN bUseVFG)
1814
929
{
1815
    // If the MiraMonLayer structure has not been init,
1816
    // here is the moment to do that.
1817
929
    if (!phMiraMonLayer)
1818
0
        return OGRERR_FAILURE;
1819
1820
929
    if (!phMiraMonLayer->bIsBeenInit)
1821
42
    {
1822
42
        if (MMInitLayerByType(phMiraMonLayer))
1823
0
            return OGRERR_FAILURE;
1824
42
        phMiraMonLayer->bIsBeenInit = 1;
1825
42
    }
1826
929
    if (MMResize_MM_N_VERTICES_TYPE_Pointer(
1827
929
            &hMMFeature.pNCoordRing, &hMMFeature.nMaxpNCoordRing,
1828
929
            (MM_N_VERTICES_TYPE)hMMFeature.nNRings + 1, MM_MEAN_NUMBER_OF_RINGS,
1829
929
            0))
1830
0
        return OGRERR_FAILURE;
1831
1832
929
    if (bUseVFG)
1833
360
    {
1834
360
        if (MMResizeVFGPointer(&hMMFeature.flag_VFG, &hMMFeature.nMaxVFG,
1835
360
                               (MM_INTERNAL_FID)hMMFeature.nNRings + 1,
1836
360
                               MM_MEAN_NUMBER_OF_RINGS, 0))
1837
0
            return OGRERR_FAILURE;
1838
1839
360
        hMMFeature.flag_VFG[hMMFeature.nIRing] = MM_END_ARC_IN_RING;
1840
360
        if (bExternalRing)
1841
220
            hMMFeature.flag_VFG[hMMFeature.nIRing] |= MM_EXTERIOR_ARC_SIDE;
1842
        // In MiraMon the external ring is clockwise and the internals are
1843
        // coounterclockwise.
1844
360
        OGRGeometry *poGeom = OGRGeometry::FromHandle(hGeom);
1845
360
        if ((bExternalRing && !poGeom->toLinearRing()->isClockwise()) ||
1846
360
            (!bExternalRing && poGeom->toLinearRing()->isClockwise()))
1847
113
            hMMFeature.flag_VFG[hMMFeature.nIRing] |= MM_ROTATE_ARC;
1848
360
    }
1849
1850
929
    hMMFeature.pNCoordRing[hMMFeature.nIRing] = OGR_G_GetPointCount(hGeom);
1851
1852
929
    if (MMResizeMM_POINT2DPointer(&hMMFeature.pCoord, &hMMFeature.nMaxpCoord,
1853
929
                                  hMMFeature.nICoord +
1854
929
                                      hMMFeature.pNCoordRing[hMMFeature.nIRing],
1855
929
                                  MM_MEAN_NUMBER_OF_NCOORDS, 0))
1856
0
        return OGRERR_FAILURE;
1857
929
    if (MMResizeDoublePointer(&hMMFeature.pZCoord, &hMMFeature.nMaxpZCoord,
1858
929
                              hMMFeature.nICoord +
1859
929
                                  hMMFeature.pNCoordRing[hMMFeature.nIRing],
1860
929
                              MM_MEAN_NUMBER_OF_NCOORDS, 0))
1861
0
        return OGRERR_FAILURE;
1862
1863
929
    hMMFeature.bAllZHaveSameValue = TRUE;
1864
929
    for (int iPoint = 0;
1865
1.54k
         (MM_N_VERTICES_TYPE)iPoint < hMMFeature.pNCoordRing[hMMFeature.nIRing];
1866
929
         iPoint++)
1867
619
    {
1868
619
        hMMFeature.pCoord[hMMFeature.nICoord].dfX = OGR_G_GetX(hGeom, iPoint);
1869
619
        hMMFeature.pCoord[hMMFeature.nICoord].dfY = OGR_G_GetY(hGeom, iPoint);
1870
619
        if (OGR_G_GetCoordinateDimension(hGeom) == 2)
1871
542
            hMMFeature.pZCoord[hMMFeature.nICoord] =
1872
542
                MM_NODATA_COORD_Z;  // Possible rare case
1873
77
        else
1874
77
        {
1875
77
            hMMFeature.pZCoord[hMMFeature.nICoord] = OGR_G_GetZ(hGeom, iPoint);
1876
77
            phMiraMonLayer->bIsReal3d = 1;
1877
77
        }
1878
1879
        // Asking if last Z-coordinate is the same than this one.
1880
        // If all Z-coordinates are the same, following MiraMon specification
1881
        // only the hMMFeature.pZCoord[0] value will be used and the number of
1882
        // vertices will be saved as a negative number on disk
1883
619
        if (iPoint > 0 &&
1884
619
            !CPLIsEqual(hMMFeature.pZCoord[hMMFeature.nICoord],
1885
619
                        hMMFeature.pZCoord[hMMFeature.nICoord - 1]))
1886
4
            hMMFeature.bAllZHaveSameValue = FALSE;
1887
1888
619
        hMMFeature.nICoord++;
1889
619
    }
1890
929
    hMMFeature.nIRing++;
1891
929
    hMMFeature.nNRings++;
1892
929
    return OGRERR_NONE;
1893
929
}
1894
1895
/****************************************************************************/
1896
/*                           MMLoadGeometry()                               */
1897
/*                                                                          */
1898
/*      Loads on a MiraMon object Feature all coordinates from feature      */
1899
/*                                                                          */
1900
/****************************************************************************/
1901
OGRErr OGRMiraMonLayer::MMLoadGeometry(OGRGeometryH hGeom)
1902
1903
909
{
1904
909
    OGRErr eErr = OGRERR_NONE;
1905
909
    MM_BOOLEAN bExternalRing;
1906
1907
    /* -------------------------------------------------------------------- */
1908
    /*      This is a geometry with sub-geometries.                         */
1909
    /* -------------------------------------------------------------------- */
1910
909
    int nGeom = OGR_G_GetGeometryCount(hGeom);
1911
1912
909
    int eLT = wkbFlatten(OGR_G_GetGeometryType(hGeom));
1913
1914
909
    if (eLT == wkbMultiPolygon || eLT == wkbPolyhedralSurface || eLT == wkbTIN)
1915
63
    {
1916
94
        for (int iGeom = 0; iGeom < nGeom && eErr == OGRERR_NONE; iGeom++)
1917
31
        {
1918
31
            OGRGeometryH poSubGeometry = OGR_G_GetGeometryRef(hGeom, iGeom);
1919
1920
            // Reads all coordinates
1921
31
            eErr = MMLoadGeometry(poSubGeometry);
1922
31
            if (eErr != OGRERR_NONE)
1923
0
                return eErr;
1924
31
        }
1925
63
    }
1926
909
    if (eLT == wkbTriangle)
1927
4
    {
1928
4
        for (int iGeom = 0; iGeom < nGeom && eErr == OGRERR_NONE; iGeom++)
1929
0
        {
1930
0
            OGRGeometryH poSubGeometry = OGR_G_GetGeometryRef(hGeom, iGeom);
1931
1932
            // Reads all coordinates
1933
0
            eErr = MMDumpVertices(poSubGeometry, TRUE, TRUE);
1934
0
            if (eErr != OGRERR_NONE)
1935
0
                return eErr;
1936
0
        }
1937
4
    }
1938
905
    else if (eLT == wkbPolygon)
1939
273
    {
1940
633
        for (int iGeom = 0; iGeom < nGeom && eErr == OGRERR_NONE; iGeom++)
1941
360
        {
1942
360
            OGRGeometryH poSubGeometry = OGR_G_GetGeometryRef(hGeom, iGeom);
1943
1944
360
            if (iGeom == 0)
1945
220
                bExternalRing = true;
1946
140
            else
1947
140
                bExternalRing = false;
1948
1949
360
            eErr = MMDumpVertices(poSubGeometry, bExternalRing, TRUE);
1950
360
            if (eErr != OGRERR_NONE)
1951
0
                return eErr;
1952
360
        }
1953
273
    }
1954
632
    else if (eLT == wkbPoint || eLT == wkbLineString)
1955
569
    {
1956
        // Reads all coordinates
1957
569
        eErr = MMDumpVertices(hGeom, true, FALSE);
1958
1959
569
        if (eErr != OGRERR_NONE)
1960
0
            return eErr;
1961
569
    }
1962
63
    else if (eLT == wkbGeometryCollection)
1963
0
    {
1964
0
        CPLError(
1965
0
            CE_Failure, CPLE_NotSupported,
1966
0
            "MiraMon: wkbGeometryCollection inside a wkbGeometryCollection?");
1967
0
        return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
1968
0
    }
1969
1970
909
    return OGRERR_NONE;
1971
909
}
1972
1973
/****************************************************************************/
1974
/*                           WriteGeometry()                                */
1975
/*                                                                          */
1976
/*                    Writes a geometry to the file.                        */
1977
/****************************************************************************/
1978
1979
OGRErr OGRMiraMonLayer::MMWriteGeometry()
1980
1981
345k
{
1982
345k
    OGRErr eErr = MMAddFeature(phMiraMonLayer, &hMMFeature);
1983
1984
345k
    if (eErr == MM_FATAL_ERROR_WRITING_FEATURES)
1985
202k
    {
1986
202k
        CPLDebugOnly("MiraMon", "Error in MMAddFeature() "
1987
202k
                                "MM_FATAL_ERROR_WRITING_FEATURES");
1988
202k
        CPLError(CE_Failure, CPLE_FileIO, "MiraMon write failure: %s",
1989
202k
                 VSIStrerror(errno));
1990
202k
        return OGRERR_FAILURE;
1991
202k
    }
1992
142k
    if (eErr == MM_STOP_WRITING_FEATURES)
1993
0
    {
1994
0
        CPLDebugOnly("MiraMon", "Error in MMAddFeature() "
1995
0
                                "MM_STOP_WRITING_FEATURES");
1996
0
        CPLError(CE_Failure, CPLE_FileIO,
1997
0
                 "MiraMon format limitations. Try V2.0 option (-lco "
1998
0
                 "Version=V2.0). " sprintf_UINT64
1999
0
                 " elements have been written correctly.",
2000
0
                 phMiraMonLayer->TopHeader.nElemCount);
2001
0
        return OGRERR_FAILURE;
2002
0
    }
2003
2004
142k
    return OGRERR_NONE;
2005
142k
}
2006
2007
/****************************************************************************/
2008
/*                       TranslateFieldsToMM()                              */
2009
/*                                                                          */
2010
/*      Translase ogr Fields to a structure that MiraMon can understand     */
2011
/****************************************************************************/
2012
2013
OGRErr OGRMiraMonLayer::TranslateFieldsToMM()
2014
2015
822
{
2016
822
    if (m_poFeatureDefn->GetFieldCount() == 0)
2017
22
        return OGRERR_NONE;
2018
2019
800
    CPLDebugOnly("MiraMon", "Translating fields to MiraMon...");
2020
    // If the structure is filled we do anything
2021
800
    if (phMiraMonLayer->pLayerDB)
2022
0
        return OGRERR_NONE;
2023
2024
800
    phMiraMonLayer->pLayerDB = static_cast<struct MiraMonDataBase *>(
2025
800
        VSICalloc(sizeof(*phMiraMonLayer->pLayerDB), 1));
2026
800
    if (!phMiraMonLayer->pLayerDB)
2027
0
        return OGRERR_NOT_ENOUGH_MEMORY;
2028
2029
800
    phMiraMonLayer->pLayerDB->pFields =
2030
800
        static_cast<struct MiraMonDataBaseField *>(
2031
800
            VSICalloc(m_poFeatureDefn->GetFieldCount(),
2032
800
                      sizeof(*(phMiraMonLayer->pLayerDB->pFields))));
2033
800
    if (!phMiraMonLayer->pLayerDB->pFields)
2034
0
        return OGRERR_NOT_ENOUGH_MEMORY;
2035
2036
800
    phMiraMonLayer->pLayerDB->nNFields = 0;
2037
800
    if (phMiraMonLayer->pLayerDB->pFields)
2038
800
    {
2039
800
        memset(phMiraMonLayer->pLayerDB->pFields, 0,
2040
800
               m_poFeatureDefn->GetFieldCount() *
2041
800
                   sizeof(*phMiraMonLayer->pLayerDB->pFields));
2042
800
        for (MM_EXT_DBF_N_FIELDS iField = 0;
2043
9.55k
             iField < (MM_EXT_DBF_N_FIELDS)m_poFeatureDefn->GetFieldCount();
2044
8.75k
             iField++)
2045
8.75k
        {
2046
8.75k
            switch (m_poFeatureDefn->GetFieldDefn(iField)->GetType())
2047
8.75k
            {
2048
52
                case OFTInteger:
2049
52
                case OFTIntegerList:
2050
52
                    if (m_poFeatureDefn->GetFieldDefn(iField)->GetSubType() ==
2051
52
                        OFSTBoolean)
2052
0
                    {
2053
0
                        phMiraMonLayer->pLayerDB->pFields[iField].eFieldType =
2054
0
                            MM_Logic;
2055
0
                    }
2056
52
                    else
2057
52
                    {
2058
52
                        phMiraMonLayer->pLayerDB->pFields[iField].eFieldType =
2059
52
                            MM_Numeric;
2060
52
                    }
2061
2062
52
                    phMiraMonLayer->pLayerDB->pFields[iField]
2063
52
                        .nNumberOfDecimals = 0;
2064
52
                    break;
2065
2066
2
                case OFTInteger64:
2067
2
                case OFTInteger64List:
2068
2
                    phMiraMonLayer->pLayerDB->pFields[iField].bIs64BitInteger =
2069
2
                        TRUE;
2070
2
                    phMiraMonLayer->pLayerDB->pFields[iField].eFieldType =
2071
2
                        MM_Numeric;
2072
2
                    phMiraMonLayer->pLayerDB->pFields[iField]
2073
2
                        .nNumberOfDecimals = 0;
2074
2
                    break;
2075
2076
19
                case OFTReal:
2077
19
                case OFTRealList:
2078
19
                    phMiraMonLayer->pLayerDB->pFields[iField].eFieldType =
2079
19
                        MM_Numeric;
2080
19
                    phMiraMonLayer->pLayerDB->pFields[iField]
2081
19
                        .nNumberOfDecimals =
2082
19
                        m_poFeatureDefn->GetFieldDefn(iField)->GetPrecision();
2083
19
                    break;
2084
2085
0
                case OFTBinary:
2086
0
                    phMiraMonLayer->pLayerDB->pFields[iField].eFieldType =
2087
0
                        MM_Character;
2088
0
                    break;
2089
2090
0
                case OFTDate:
2091
0
                    phMiraMonLayer->pLayerDB->pFields[iField].eFieldType =
2092
0
                        MM_Data;
2093
0
                    break;
2094
2095
0
                case OFTTime:
2096
0
                case OFTDateTime:
2097
0
                    phMiraMonLayer->pLayerDB->pFields[iField].eFieldType =
2098
0
                        MM_Character;
2099
0
                    break;
2100
2101
8.67k
                case OFTString:
2102
8.67k
                case OFTStringList:
2103
8.67k
                default:
2104
8.67k
                    phMiraMonLayer->pLayerDB->pFields[iField].eFieldType =
2105
8.67k
                        MM_Character;
2106
8.67k
                    break;
2107
8.75k
            }
2108
8.75k
            if (m_poFeatureDefn->GetFieldDefn(iField)->GetType() == OFTDate)
2109
0
                phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize = 8;
2110
8.75k
            else if ((m_poFeatureDefn->GetFieldDefn(iField)->GetType() ==
2111
8.75k
                          OFTInteger ||
2112
8.75k
                      m_poFeatureDefn->GetFieldDefn(iField)->GetType() ==
2113
8.69k
                          OFTIntegerList) &&
2114
8.75k
                     m_poFeatureDefn->GetFieldDefn(iField)->GetSubType() ==
2115
52
                         OFSTBoolean)
2116
0
            {
2117
0
                phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize = 1;
2118
0
            }
2119
8.75k
            else
2120
8.75k
            {
2121
                // NOTE_3812_20250527:
2122
                // As https://gdal.org/api/ogrfeature_cpp.html indicates that
2123
                // precision (number of digits after decimal point) is optional,
2124
                // and a 0 is probably the default value, in that case we prefer
2125
                // to save all the guaranteed significant figures in a double
2126
                // (needed if a field contains, for instance, coordinates in
2127
                // geodetic degrees and a 1:1000 map precision applies).
2128
8.75k
                if (m_poFeatureDefn->GetFieldDefn(iField)->GetPrecision() == 0)
2129
8.75k
                {
2130
8.75k
                    if (m_poFeatureDefn->GetFieldDefn(iField)->GetType() ==
2131
8.75k
                            OFTReal ||
2132
8.75k
                        m_poFeatureDefn->GetFieldDefn(iField)->GetType() ==
2133
8.73k
                            OFTRealList)
2134
19
                    {
2135
19
                        phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize =
2136
19
                            20;
2137
19
                        phMiraMonLayer->pLayerDB->pFields[iField]
2138
19
                            .nNumberOfDecimals = MAX_RELIABLE_SF_DOUBLE;
2139
19
                    }
2140
8.73k
                    else
2141
8.73k
                    {
2142
8.73k
                        phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize =
2143
8.73k
                            m_poFeatureDefn->GetFieldDefn(iField)->GetWidth();
2144
8.73k
                        if (phMiraMonLayer->pLayerDB->pFields[iField]
2145
8.73k
                                .nFieldSize == 0)
2146
8.72k
                            phMiraMonLayer->pLayerDB->pFields[iField]
2147
8.72k
                                .nFieldSize = 3;
2148
8.73k
                    }
2149
2150
                    // Some exceptions for some fields:
2151
8.75k
                    if (EQUAL(
2152
8.75k
                            m_poFeatureDefn->GetFieldDefn(iField)->GetNameRef(),
2153
8.75k
                            "fontsize"))
2154
0
                    {
2155
0
                        phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize =
2156
0
                            11;
2157
0
                        phMiraMonLayer->pLayerDB->pFields[iField]
2158
0
                            .nNumberOfDecimals = 3;
2159
0
                    }
2160
8.75k
                    else if (EQUAL(m_poFeatureDefn->GetFieldDefn(iField)
2161
8.75k
                                       ->GetNameRef(),
2162
8.75k
                                   "leading") ||
2163
8.75k
                             EQUAL(m_poFeatureDefn->GetFieldDefn(iField)
2164
8.75k
                                       ->GetNameRef(),
2165
8.75k
                                   "chrwidth") ||
2166
8.75k
                             EQUAL(m_poFeatureDefn->GetFieldDefn(iField)
2167
8.75k
                                       ->GetNameRef(),
2168
8.75k
                                   "chrspacing"))
2169
0
                    {
2170
0
                        phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize =
2171
0
                            8;
2172
0
                        phMiraMonLayer->pLayerDB->pFields[iField]
2173
0
                            .nNumberOfDecimals = 3;
2174
0
                    }
2175
8.75k
                    else if (EQUAL(m_poFeatureDefn->GetFieldDefn(iField)
2176
8.75k
                                       ->GetNameRef(),
2177
8.75k
                                   "orientacio"))
2178
0
                    {
2179
0
                        phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize =
2180
0
                            7;
2181
0
                        phMiraMonLayer->pLayerDB->pFields[iField]
2182
0
                            .nNumberOfDecimals = 2;
2183
0
                    }
2184
8.75k
                }
2185
0
                else
2186
0
                {
2187
                    // One more space for the "."
2188
0
                    phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize =
2189
0
                        (unsigned int)(m_poFeatureDefn->GetFieldDefn(iField)
2190
0
                                           ->GetWidth() +
2191
0
                                       1);
2192
0
                }
2193
8.75k
            }
2194
2195
            // Recode from UTF-8 if necessary
2196
8.75k
            if (phMiraMonLayer->nCharSet != MM_JOC_CARAC_UTF8_DBF)
2197
8.75k
            {
2198
8.75k
                char *pszString = CPLRecode(
2199
8.75k
                    m_poFeatureDefn->GetFieldDefn(iField)->GetNameRef(),
2200
8.75k
                    CPL_ENC_UTF8, CPL_ENC_ISO8859_1);
2201
8.75k
                CPLStrlcpy(
2202
8.75k
                    phMiraMonLayer->pLayerDB->pFields[iField].pszFieldName,
2203
8.75k
                    pszString, MM_MAX_LON_FIELD_NAME_DBF);
2204
8.75k
                CPLFree(pszString);
2205
8.75k
            }
2206
0
            else
2207
0
            {
2208
0
                CPLStrlcpy(
2209
0
                    phMiraMonLayer->pLayerDB->pFields[iField].pszFieldName,
2210
0
                    m_poFeatureDefn->GetFieldDefn(iField)->GetNameRef(),
2211
0
                    MM_MAX_LON_FIELD_NAME_DBF);
2212
0
            }
2213
2214
8.75k
            if (m_poFeatureDefn->GetFieldDefn(iField)->GetAlternativeNameRef())
2215
8.75k
            {
2216
8.75k
                if (phMiraMonLayer->nCharSet != MM_JOC_CARAC_UTF8_DBF)
2217
8.75k
                {
2218
8.75k
                    char *pszString =
2219
8.75k
                        CPLRecode(m_poFeatureDefn->GetFieldDefn(iField)
2220
8.75k
                                      ->GetAlternativeNameRef(),
2221
8.75k
                                  CPL_ENC_UTF8, CPL_ENC_ISO8859_1);
2222
8.75k
                    CPLStrlcpy(phMiraMonLayer->pLayerDB->pFields[iField]
2223
8.75k
                                   .pszFieldDescription,
2224
8.75k
                               pszString, MM_MAX_BYTES_FIELD_DESC);
2225
8.75k
                    CPLFree(pszString);
2226
8.75k
                }
2227
0
                else
2228
0
                {
2229
0
                    CPLStrlcpy(phMiraMonLayer->pLayerDB->pFields[iField]
2230
0
                                   .pszFieldDescription,
2231
0
                               m_poFeatureDefn->GetFieldDefn(iField)
2232
0
                                   ->GetAlternativeNameRef(),
2233
0
                               MM_MAX_BYTES_FIELD_DESC);
2234
0
                }
2235
8.75k
            }
2236
8.75k
            phMiraMonLayer->pLayerDB->nNFields++;
2237
8.75k
        }
2238
800
    }
2239
2240
800
    CPLDebugOnly("MiraMon", "Fields to MiraMon translated.");
2241
800
    return OGRERR_NONE;
2242
800
}
2243
2244
/****************************************************************************/
2245
/*                       TranslateFieldsValuesToMM()                        */
2246
/*                                                                          */
2247
/*      Translate ogr Fields to a structure that MiraMon can understand     */
2248
/****************************************************************************/
2249
2250
OGRErr OGRMiraMonLayer::TranslateFieldsValuesToMM(OGRFeature *poFeature)
2251
2252
345k
{
2253
345k
    if (m_poFeatureDefn->GetFieldCount() == 0)
2254
22
    {
2255
        // MiraMon have private DataBase records
2256
22
        hMMFeature.nNumMRecords = 1;
2257
22
        return OGRERR_NONE;
2258
22
    }
2259
2260
345k
    MM_EXT_DBF_N_MULTIPLE_RECORDS nIRecord;
2261
345k
    MM_EXT_DBF_N_FIELDS nNumFields = m_poFeatureDefn->GetFieldCount();
2262
345k
    MM_EXT_DBF_N_MULTIPLE_RECORDS nNumRecords, nRealNumRecords;
2263
345k
    hMMFeature.nNumMRecords = 0;
2264
345k
#define MAX_SIZE_OF_FIELD_NUMBER_WITH_MINUS 22
2265
2266
1.39M
    for (MM_EXT_DBF_N_FIELDS iField = 0; iField < nNumFields; iField++)
2267
1.04M
    {
2268
1.04M
        OGRFieldType eFType = m_poFeatureDefn->GetFieldDefn(iField)->GetType();
2269
1.04M
        OGRFieldSubType eFSType =
2270
1.04M
            m_poFeatureDefn->GetFieldDefn(iField)->GetSubType();
2271
1.04M
        const char *pszRawValue = poFeature->GetFieldAsString(iField);
2272
2273
1.04M
        if (eFType == OFTStringList)
2274
0
        {
2275
0
            char **papszValues = poFeature->GetFieldAsStringList(iField);
2276
0
            nRealNumRecords = nNumRecords = CSLCount(papszValues);
2277
0
            if (nNumRecords == 0)
2278
0
                nNumRecords++;
2279
0
            hMMFeature.nNumMRecords = MAX(hMMFeature.nNumMRecords, nNumRecords);
2280
0
            if (MMResizeMiraMonRecord(
2281
0
                    &hMMFeature.pRecords, &hMMFeature.nMaxMRecords,
2282
0
                    hMMFeature.nNumMRecords, MM_INC_NUMBER_OF_RECORDS,
2283
0
                    hMMFeature.nNumMRecords))
2284
0
                return OGRERR_NOT_ENOUGH_MEMORY;
2285
2286
0
            for (nIRecord = 0; nIRecord < nRealNumRecords; nIRecord++)
2287
0
            {
2288
0
                hMMFeature.pRecords[nIRecord].nNumField =
2289
0
                    m_poFeatureDefn->GetFieldCount();
2290
2291
0
                if (MMResizeMiraMonFieldValue(
2292
0
                        &(hMMFeature.pRecords[nIRecord].pField),
2293
0
                        &hMMFeature.pRecords[nIRecord].nMaxField,
2294
0
                        hMMFeature.pRecords[nIRecord].nNumField,
2295
0
                        (nIRecord == 0)
2296
0
                            ? MM_INC_NUMBER_OF_FIELDS
2297
0
                            : hMMFeature.pRecords[nIRecord - 1].nMaxField,
2298
0
                        hMMFeature.pRecords[nIRecord].nNumField))
2299
0
                    return OGRERR_NOT_ENOUGH_MEMORY;
2300
2301
0
                if (nIRecord > 0)
2302
0
                {
2303
                    // The number of fields of this new record is the same as the
2304
                    // last one
2305
0
                    hMMFeature.pRecords[nIRecord].nNumField =
2306
0
                        hMMFeature.pRecords[nIRecord - 1].nNumField;
2307
0
                }
2308
2309
0
                if (phMiraMonLayer->nCharSet != MM_JOC_CARAC_UTF8_DBF)
2310
0
                {
2311
                    // MiraMon encoding is ISO 8859-1 (Latin1) -> Recode from UTF-8
2312
0
                    char *pszString = CPLRecode(
2313
0
                        papszValues[nIRecord], CPL_ENC_UTF8, CPL_ENC_ISO8859_1);
2314
0
                    if (MM_SecureCopyStringFieldValue(
2315
0
                            &hMMFeature.pRecords[nIRecord]
2316
0
                                 .pField[iField]
2317
0
                                 .pDinValue,
2318
0
                            pszString,
2319
0
                            &hMMFeature.pRecords[nIRecord]
2320
0
                                 .pField[iField]
2321
0
                                 .nNumDinValue))
2322
0
                    {
2323
0
                        CPLFree(pszString);
2324
0
                        return OGRERR_NOT_ENOUGH_MEMORY;
2325
0
                    }
2326
0
                    CPLFree(pszString);
2327
0
                }
2328
0
                else
2329
0
                {
2330
0
                    if (MM_SecureCopyStringFieldValue(
2331
0
                            &hMMFeature.pRecords[nIRecord]
2332
0
                                 .pField[iField]
2333
0
                                 .pDinValue,
2334
0
                            papszValues[nIRecord],
2335
0
                            &hMMFeature.pRecords[nIRecord]
2336
0
                                 .pField[iField]
2337
0
                                 .nNumDinValue))
2338
0
                        return OGRERR_NOT_ENOUGH_MEMORY;
2339
0
                }
2340
0
                hMMFeature.pRecords[nIRecord].pField[iField].bIsValid = 1;
2341
0
            }
2342
0
        }
2343
1.04M
        else if (eFType == OFTIntegerList)
2344
0
        {
2345
0
            int nCount = 0;
2346
0
            const int *panValues =
2347
0
                poFeature->GetFieldAsIntegerList(iField, &nCount);
2348
2349
0
            nRealNumRecords = nNumRecords = nCount;
2350
0
            if (nNumRecords == 0)
2351
0
                nNumRecords++;
2352
0
            hMMFeature.nNumMRecords = MAX(hMMFeature.nNumMRecords, nNumRecords);
2353
0
            if (MMResizeMiraMonRecord(
2354
0
                    &hMMFeature.pRecords, &hMMFeature.nMaxMRecords,
2355
0
                    hMMFeature.nNumMRecords, MM_INC_NUMBER_OF_RECORDS,
2356
0
                    hMMFeature.nNumMRecords))
2357
0
                return OGRERR_NOT_ENOUGH_MEMORY;
2358
2359
            // It will contains the i-th element of the list.
2360
0
            for (nIRecord = 0; nIRecord < nRealNumRecords; nIRecord++)
2361
0
            {
2362
0
                if (MMResizeMiraMonFieldValue(
2363
0
                        &(hMMFeature.pRecords[nIRecord].pField),
2364
0
                        &hMMFeature.pRecords[nIRecord].nMaxField,
2365
0
                        hMMFeature.pRecords[nIRecord].nNumField,
2366
0
                        (nIRecord == 0)
2367
0
                            ? MM_INC_NUMBER_OF_FIELDS
2368
0
                            : hMMFeature.pRecords[nIRecord - 1].nMaxField,
2369
0
                        hMMFeature.pRecords[nIRecord].nNumField))
2370
0
                    return OGRERR_NOT_ENOUGH_MEMORY;
2371
2372
0
                if (nIRecord > 0)
2373
0
                {
2374
                    // The number of fields of this new record is the same as the
2375
                    // last one
2376
0
                    hMMFeature.pRecords[nIRecord].nNumField =
2377
0
                        hMMFeature.pRecords[nIRecord - 1].nNumField;
2378
0
                }
2379
2380
0
                if (eFSType == OFSTBoolean)
2381
0
                {
2382
0
                    if (panValues[nIRecord] == 1)
2383
0
                    {
2384
0
                        if (MM_SecureCopyStringFieldValue(
2385
0
                                &hMMFeature.pRecords[nIRecord]
2386
0
                                     .pField[iField]
2387
0
                                     .pDinValue,
2388
0
                                "T",
2389
0
                                &hMMFeature.pRecords[nIRecord]
2390
0
                                     .pField[iField]
2391
0
                                     .nNumDinValue))
2392
0
                            return OGRERR_NOT_ENOUGH_MEMORY;
2393
0
                    }
2394
0
                    else
2395
0
                    {
2396
0
                        if (MM_SecureCopyStringFieldValue(
2397
0
                                &hMMFeature.pRecords[nIRecord]
2398
0
                                     .pField[iField]
2399
0
                                     .pDinValue,
2400
0
                                "F",
2401
0
                                &hMMFeature.pRecords[nIRecord]
2402
0
                                     .pField[iField]
2403
0
                                     .nNumDinValue))
2404
0
                            return OGRERR_NOT_ENOUGH_MEMORY;
2405
0
                    }
2406
0
                }
2407
0
                else
2408
0
                {
2409
0
                    if (MM_SecureCopyStringFieldValue(
2410
0
                            &hMMFeature.pRecords[nIRecord]
2411
0
                                 .pField[iField]
2412
0
                                 .pDinValue,
2413
0
                            CPLSPrintf("%d", panValues[nIRecord]),
2414
0
                            &hMMFeature.pRecords[nIRecord]
2415
0
                                 .pField[iField]
2416
0
                                 .nNumDinValue))
2417
0
                        return OGRERR_NOT_ENOUGH_MEMORY;
2418
0
                }
2419
2420
0
                hMMFeature.pRecords[nIRecord].pField[iField].bIsValid = 1;
2421
0
            }
2422
0
        }
2423
1.04M
        else if (eFType == OFTInteger64List)
2424
0
        {
2425
0
            int nCount = 0;
2426
0
            const GIntBig *panValues =
2427
0
                poFeature->GetFieldAsInteger64List(iField, &nCount);
2428
2429
0
            nRealNumRecords = nNumRecords = nCount;
2430
0
            if (nNumRecords == 0)
2431
0
                nNumRecords++;
2432
0
            hMMFeature.nNumMRecords = MAX(hMMFeature.nNumMRecords, nNumRecords);
2433
0
            if (MMResizeMiraMonRecord(
2434
0
                    &hMMFeature.pRecords, &hMMFeature.nMaxMRecords,
2435
0
                    hMMFeature.nNumMRecords, MM_INC_NUMBER_OF_RECORDS,
2436
0
                    hMMFeature.nNumMRecords))
2437
0
                return OGRERR_NOT_ENOUGH_MEMORY;
2438
2439
            // It will contains the i-th element of the list.
2440
0
            for (nIRecord = 0; nIRecord < nRealNumRecords; nIRecord++)
2441
0
            {
2442
0
                if (MMResizeMiraMonFieldValue(
2443
0
                        &(hMMFeature.pRecords[nIRecord].pField),
2444
0
                        &hMMFeature.pRecords[nIRecord].nMaxField,
2445
0
                        hMMFeature.pRecords[nIRecord].nNumField,
2446
0
                        (nIRecord == 0)
2447
0
                            ? MM_INC_NUMBER_OF_FIELDS
2448
0
                            : hMMFeature.pRecords[nIRecord - 1].nMaxField,
2449
0
                        hMMFeature.pRecords[nIRecord].nNumField))
2450
0
                    return OGRERR_NOT_ENOUGH_MEMORY;
2451
2452
0
                if (nIRecord > 0)
2453
0
                {
2454
                    // The number of fields of this new record is the same as the
2455
                    // last one
2456
0
                    hMMFeature.pRecords[nIRecord].nNumField =
2457
0
                        hMMFeature.pRecords[nIRecord - 1].nNumField;
2458
0
                }
2459
2460
0
                hMMFeature.pRecords[nIRecord].pField[iField].iValue =
2461
0
                    panValues[nIRecord];
2462
2463
0
                if (MM_SecureCopyStringFieldValue(
2464
0
                        &hMMFeature.pRecords[nIRecord].pField[iField].pDinValue,
2465
0
                        CPLSPrintf("%" CPL_FRMT_GB_WITHOUT_PREFIX "d",
2466
0
                                   panValues[nIRecord]),
2467
0
                        &hMMFeature.pRecords[nIRecord]
2468
0
                             .pField[iField]
2469
0
                             .nNumDinValue))
2470
0
                    return OGRERR_NOT_ENOUGH_MEMORY;
2471
0
                hMMFeature.pRecords[nIRecord].pField[iField].bIsValid = 1;
2472
0
            }
2473
0
        }
2474
1.04M
        else if (eFType == OFTRealList)
2475
0
        {
2476
0
            int nCount = 0;
2477
0
            const double *padfRLValues =
2478
0
                poFeature->GetFieldAsDoubleList(iField, &nCount);
2479
            //char format[23];
2480
2481
0
            nRealNumRecords = nNumRecords = nCount;
2482
0
            if (nNumRecords == 0)
2483
0
                nNumRecords++;
2484
0
            hMMFeature.nNumMRecords = MAX(hMMFeature.nNumMRecords, nNumRecords);
2485
0
            if (MMResizeMiraMonRecord(
2486
0
                    &hMMFeature.pRecords, &hMMFeature.nMaxMRecords,
2487
0
                    hMMFeature.nNumMRecords, MM_INC_NUMBER_OF_RECORDS,
2488
0
                    hMMFeature.nNumMRecords))
2489
0
                return OGRERR_NOT_ENOUGH_MEMORY;
2490
2491
            // It will contains the i-th element of the list.
2492
0
            for (nIRecord = 0; nIRecord < nRealNumRecords; nIRecord++)
2493
0
            {
2494
0
                if (MMResizeMiraMonFieldValue(
2495
0
                        &(hMMFeature.pRecords[nIRecord].pField),
2496
0
                        &hMMFeature.pRecords[nIRecord].nMaxField,
2497
0
                        hMMFeature.pRecords[nIRecord].nNumField,
2498
0
                        (nIRecord == 0)
2499
0
                            ? MM_INC_NUMBER_OF_FIELDS
2500
0
                            : hMMFeature.pRecords[nIRecord - 1].nMaxField,
2501
0
                        hMMFeature.pRecords[nIRecord].nNumField))
2502
0
                    return OGRERR_NOT_ENOUGH_MEMORY;
2503
2504
0
                if (nIRecord > 0)
2505
0
                {
2506
                    // The number of fields of this new record is the same as the
2507
                    // last one
2508
0
                    hMMFeature.pRecords[nIRecord].nNumField =
2509
0
                        hMMFeature.pRecords[nIRecord - 1].nNumField;
2510
0
                }
2511
2512
0
                char szChain[MAX_SIZE_OF_FIELD_NUMBER_WITH_MINUS];
2513
0
                if (phMiraMonLayer->pLayerDB->pFields[iField]
2514
0
                            .nNumberOfDecimals > 0 &&
2515
0
                    phMiraMonLayer->pLayerDB->pFields[iField]
2516
0
                            .nNumberOfDecimals < MAX_RELIABLE_SF_DOUBLE)
2517
0
                {
2518
0
                    CPLsnprintf(szChain, sizeof(szChain), "%.*f",
2519
0
                                phMiraMonLayer->pLayerDB->pFields[iField]
2520
0
                                    .nNumberOfDecimals,
2521
0
                                padfRLValues[nIRecord]);
2522
0
                }
2523
0
                else
2524
0
                {
2525
0
                    MM_SprintfDoubleSignifFigures(
2526
0
                        szChain, sizeof(szChain),
2527
0
                        phMiraMonLayer->pLayerDB->pFields[iField]
2528
0
                            .nNumberOfDecimals,
2529
0
                        padfRLValues[nIRecord]);
2530
0
                }
2531
2532
0
                if (MM_SecureCopyStringFieldValue(
2533
0
                        &hMMFeature.pRecords[nIRecord].pField[iField].pDinValue,
2534
0
                        szChain,
2535
0
                        &hMMFeature.pRecords[nIRecord]
2536
0
                             .pField[iField]
2537
0
                             .nNumDinValue))
2538
0
                    return OGRERR_NOT_ENOUGH_MEMORY;
2539
0
                hMMFeature.pRecords[nIRecord].pField[iField].bIsValid = 1;
2540
0
            }
2541
0
        }
2542
1.04M
        else if (eFType == OFTString)
2543
979k
        {
2544
979k
            hMMFeature.nNumMRecords = MAX(hMMFeature.nNumMRecords, 1);
2545
979k
            hMMFeature.pRecords[0].nNumField = nNumFields;
2546
979k
            if (MMResizeMiraMonFieldValue(&(hMMFeature.pRecords[0].pField),
2547
979k
                                          &hMMFeature.pRecords[0].nMaxField,
2548
979k
                                          hMMFeature.pRecords[0].nNumField,
2549
979k
                                          MM_INC_NUMBER_OF_FIELDS,
2550
979k
                                          hMMFeature.pRecords[0].nNumField))
2551
0
                return OGRERR_NOT_ENOUGH_MEMORY;
2552
2553
979k
            if (MMIsEmptyString(pszRawValue))
2554
653k
                hMMFeature.pRecords[0].pField[iField].bIsValid = 0;
2555
979k
            {
2556
979k
                if (phMiraMonLayer->nCharSet != MM_JOC_CARAC_UTF8_DBF)
2557
979k
                {
2558
                    // MiraMon encoding is ISO 8859-1 (Latin1) -> Recode from UTF-8
2559
979k
                    char *pszString =
2560
979k
                        CPLRecode(pszRawValue, CPL_ENC_UTF8, CPL_ENC_ISO8859_1);
2561
979k
                    if (MM_SecureCopyStringFieldValue(
2562
979k
                            &hMMFeature.pRecords[0].pField[iField].pDinValue,
2563
979k
                            pszString,
2564
979k
                            &hMMFeature.pRecords[0]
2565
979k
                                 .pField[iField]
2566
979k
                                 .nNumDinValue))
2567
0
                    {
2568
0
                        CPLFree(pszString);
2569
0
                        return OGRERR_NOT_ENOUGH_MEMORY;
2570
0
                    }
2571
979k
                    CPLFree(pszString);
2572
979k
                }
2573
0
                else
2574
0
                {
2575
0
                    if (MM_SecureCopyStringFieldValue(
2576
0
                            &hMMFeature.pRecords[0].pField[iField].pDinValue,
2577
0
                            pszRawValue,
2578
0
                            &hMMFeature.pRecords[0]
2579
0
                                 .pField[iField]
2580
0
                                 .nNumDinValue))
2581
0
                    {
2582
0
                        return OGRERR_NOT_ENOUGH_MEMORY;
2583
0
                    }
2584
0
                }
2585
979k
            }
2586
979k
            hMMFeature.pRecords[0].pField[iField].bIsValid = 1;
2587
979k
        }
2588
66.1k
        else if (eFType == OFTDate)
2589
0
        {
2590
0
            char szDate[15];
2591
2592
0
            hMMFeature.nNumMRecords = MAX(hMMFeature.nNumMRecords, 1);
2593
0
            hMMFeature.pRecords[0].nNumField = nNumFields;
2594
0
            if (MMResizeMiraMonFieldValue(&(hMMFeature.pRecords[0].pField),
2595
0
                                          &hMMFeature.pRecords[0].nMaxField,
2596
0
                                          hMMFeature.pRecords[0].nNumField,
2597
0
                                          MM_INC_NUMBER_OF_FIELDS,
2598
0
                                          hMMFeature.pRecords[0].nNumField))
2599
0
                return OGRERR_NOT_ENOUGH_MEMORY;
2600
2601
0
            if (MMIsEmptyString(pszRawValue))
2602
0
                hMMFeature.pRecords[0].pField[iField].bIsValid = 0;
2603
0
            else
2604
0
            {
2605
0
                const OGRField *poField = poFeature->GetRawFieldRef(iField);
2606
0
                if (poField->Date.Year >= 0)
2607
0
                    snprintf(szDate, sizeof(szDate), "%04d%02d%02d",
2608
0
                             poField->Date.Year, poField->Date.Month,
2609
0
                             poField->Date.Day);
2610
0
                else
2611
0
                    snprintf(szDate, sizeof(szDate), "%04d%02d%02d", 0, 0, 0);
2612
2613
0
                if (MM_SecureCopyStringFieldValue(
2614
0
                        &hMMFeature.pRecords[0].pField[iField].pDinValue,
2615
0
                        szDate,
2616
0
                        &hMMFeature.pRecords[0].pField[iField].nNumDinValue))
2617
0
                    return OGRERR_NOT_ENOUGH_MEMORY;
2618
0
                hMMFeature.pRecords[0].pField[iField].bIsValid = 1;
2619
0
            }
2620
0
        }
2621
66.1k
        else if (eFType == OFTTime || eFType == OFTDateTime)
2622
0
        {
2623
0
            hMMFeature.nNumMRecords = MAX(hMMFeature.nNumMRecords, 1);
2624
0
            hMMFeature.pRecords[0].nNumField = nNumFields;
2625
0
            if (MMResizeMiraMonFieldValue(&(hMMFeature.pRecords[0].pField),
2626
0
                                          &hMMFeature.pRecords[0].nMaxField,
2627
0
                                          hMMFeature.pRecords[0].nNumField,
2628
0
                                          MM_INC_NUMBER_OF_FIELDS,
2629
0
                                          hMMFeature.pRecords[0].nNumField))
2630
0
                return OGRERR_NOT_ENOUGH_MEMORY;
2631
2632
0
            if (MMIsEmptyString(pszRawValue))
2633
0
                hMMFeature.pRecords[0].pField[iField].bIsValid = 0;
2634
0
            else
2635
0
            {
2636
                // MiraMon encoding is ISO 8859-1 (Latin1) -> Recode from UTF-8
2637
0
                if (MM_SecureCopyStringFieldValue(
2638
0
                        &hMMFeature.pRecords[0].pField[iField].pDinValue,
2639
0
                        pszRawValue,
2640
0
                        &hMMFeature.pRecords[0].pField[iField].nNumDinValue))
2641
0
                    return OGRERR_NOT_ENOUGH_MEMORY;
2642
2643
0
                hMMFeature.pRecords[0].pField[iField].bIsValid = 1;
2644
0
            }
2645
0
        }
2646
66.1k
        else if (eFType == OFTInteger)
2647
46.4k
        {
2648
46.4k
            hMMFeature.nNumMRecords = MAX(hMMFeature.nNumMRecords, 1);
2649
46.4k
            hMMFeature.pRecords[0].nNumField = nNumFields;
2650
46.4k
            if (MMResizeMiraMonFieldValue(&(hMMFeature.pRecords[0].pField),
2651
46.4k
                                          &hMMFeature.pRecords[0].nMaxField,
2652
46.4k
                                          hMMFeature.pRecords[0].nNumField,
2653
46.4k
                                          MM_INC_NUMBER_OF_FIELDS,
2654
46.4k
                                          hMMFeature.pRecords[0].nNumField))
2655
0
                return OGRERR_NOT_ENOUGH_MEMORY;
2656
2657
46.4k
            if (MMIsEmptyString(pszRawValue))
2658
45.6k
                hMMFeature.pRecords[0].pField[iField].bIsValid = 0;
2659
852
            else
2660
852
            {
2661
852
                if (eFSType == OFSTBoolean)
2662
0
                {
2663
0
                    if (!strcmp(pszRawValue, "1"))
2664
0
                    {
2665
0
                        if (MM_SecureCopyStringFieldValue(
2666
0
                                &hMMFeature.pRecords[0]
2667
0
                                     .pField[iField]
2668
0
                                     .pDinValue,
2669
0
                                "T",
2670
0
                                &hMMFeature.pRecords[0]
2671
0
                                     .pField[iField]
2672
0
                                     .nNumDinValue))
2673
0
                            return OGRERR_NOT_ENOUGH_MEMORY;
2674
0
                    }
2675
0
                    else
2676
0
                    {
2677
0
                        if (MM_SecureCopyStringFieldValue(
2678
0
                                &hMMFeature.pRecords[0]
2679
0
                                     .pField[iField]
2680
0
                                     .pDinValue,
2681
0
                                "F",
2682
0
                                &hMMFeature.pRecords[0]
2683
0
                                     .pField[iField]
2684
0
                                     .nNumDinValue))
2685
0
                            return OGRERR_NOT_ENOUGH_MEMORY;
2686
0
                    }
2687
0
                }
2688
852
                else
2689
852
                {
2690
852
                    if (MM_SecureCopyStringFieldValue(
2691
852
                            &hMMFeature.pRecords[0].pField[iField].pDinValue,
2692
852
                            pszRawValue,
2693
852
                            &hMMFeature.pRecords[0]
2694
852
                                 .pField[iField]
2695
852
                                 .nNumDinValue))
2696
0
                        return OGRERR_NOT_ENOUGH_MEMORY;
2697
852
                }
2698
852
                hMMFeature.pRecords[0].pField[iField].bIsValid = 1;
2699
852
            }
2700
46.4k
        }
2701
19.6k
        else if (eFType == OFTInteger64)
2702
4
        {
2703
4
            hMMFeature.nNumMRecords = MAX(hMMFeature.nNumMRecords, 1);
2704
4
            hMMFeature.pRecords[0].nNumField = nNumFields;
2705
4
            if (MMResizeMiraMonFieldValue(&(hMMFeature.pRecords[0].pField),
2706
4
                                          &hMMFeature.pRecords[0].nMaxField,
2707
4
                                          hMMFeature.pRecords[0].nNumField,
2708
4
                                          MM_INC_NUMBER_OF_FIELDS,
2709
4
                                          hMMFeature.pRecords[0].nNumField))
2710
0
                return OGRERR_NOT_ENOUGH_MEMORY;
2711
2712
4
            if (MMIsEmptyString(pszRawValue))
2713
3
                hMMFeature.pRecords[0].pField[iField].bIsValid = 0;
2714
1
            else
2715
1
            {
2716
1
                hMMFeature.pRecords[0].pField[iField].iValue =
2717
1
                    poFeature->GetFieldAsInteger64(iField);
2718
2719
1
                if (MM_SecureCopyStringFieldValue(
2720
1
                        &hMMFeature.pRecords[0].pField[iField].pDinValue,
2721
1
                        pszRawValue,
2722
1
                        &hMMFeature.pRecords[0].pField[iField].nNumDinValue))
2723
0
                    return OGRERR_NOT_ENOUGH_MEMORY;
2724
1
                hMMFeature.pRecords[0].pField[iField].bIsValid = 1;
2725
1
            }
2726
4
        }
2727
19.6k
        else if (eFType == OFTReal)
2728
19.6k
        {
2729
19.6k
            hMMFeature.nNumMRecords = MAX(hMMFeature.nNumMRecords, 1);
2730
19.6k
            hMMFeature.pRecords[0].nNumField = nNumFields;
2731
19.6k
            if (MMResizeMiraMonFieldValue(&(hMMFeature.pRecords[0].pField),
2732
19.6k
                                          &hMMFeature.pRecords[0].nMaxField,
2733
19.6k
                                          hMMFeature.pRecords[0].nNumField,
2734
19.6k
                                          MM_INC_NUMBER_OF_FIELDS,
2735
19.6k
                                          hMMFeature.pRecords[0].nNumField))
2736
0
                return OGRERR_NOT_ENOUGH_MEMORY;
2737
2738
19.6k
            if (MMIsEmptyString(pszRawValue))
2739
19.5k
                hMMFeature.pRecords[0].pField[iField].bIsValid = 0;
2740
55
            else
2741
55
            {
2742
55
                char szChain[MAX_SIZE_OF_FIELD_NUMBER_WITH_MINUS];
2743
                // According to NOTE_3812_20250527
2744
55
                if (phMiraMonLayer->pLayerDB->pFields[iField]
2745
55
                            .nNumberOfDecimals > 0 &&
2746
55
                    phMiraMonLayer->pLayerDB->pFields[iField]
2747
55
                            .nNumberOfDecimals < MAX_RELIABLE_SF_DOUBLE)
2748
0
                {
2749
0
                    CPLsnprintf(szChain, sizeof(szChain), "%.*f",
2750
0
                                phMiraMonLayer->pLayerDB->pFields[iField]
2751
0
                                    .nNumberOfDecimals,
2752
0
                                poFeature->GetFieldAsDouble(iField));
2753
0
                }
2754
55
                else
2755
55
                {
2756
55
                    MM_SprintfDoubleSignifFigures(
2757
55
                        szChain, sizeof(szChain),
2758
55
                        phMiraMonLayer->pLayerDB->pFields[iField]
2759
55
                            .nNumberOfDecimals,
2760
55
                        poFeature->GetFieldAsDouble(iField));
2761
55
                }
2762
2763
55
                if (MM_SecureCopyStringFieldValue(
2764
55
                        &hMMFeature.pRecords[0].pField[iField].pDinValue,
2765
55
                        szChain,
2766
55
                        &hMMFeature.pRecords[0].pField[iField].nNumDinValue))
2767
0
                    return OGRERR_NOT_ENOUGH_MEMORY;
2768
55
                hMMFeature.pRecords[0].pField[iField].bIsValid = 1;
2769
55
            }
2770
19.6k
        }
2771
0
        else
2772
0
        {
2773
0
            CPLError(CE_Warning, CPLE_NotSupported,
2774
0
                     "MiraMon: Field type %d not processed by MiraMon\n",
2775
0
                     eFType);
2776
0
            hMMFeature.pRecords[0].pField[iField].bIsValid = 0;
2777
0
        }
2778
1.04M
    }
2779
2780
345k
    return OGRERR_NONE;
2781
345k
}
2782
2783
/****************************************************************************/
2784
/*                             GetLayerDefn()                               */
2785
/*                                                                          */
2786
/****************************************************************************/
2787
OGRFeatureDefn *OGRMiraMonLayer::GetLayerDefn()
2788
392k
{
2789
392k
    return m_poFeatureDefn;
2790
392k
}
2791
2792
/****************************************************************************/
2793
/*                            IGetExtent()                                  */
2794
/*                                                                          */
2795
/*      Fetch extent of the data currently stored in the dataset.           */
2796
/*      The bForce flag has no effect on SHO files since that value         */
2797
/*      is always in the header.                                            */
2798
/****************************************************************************/
2799
2800
OGRErr OGRMiraMonLayer::IGetExtent(int /* iGeomField*/, OGREnvelope *psExtent,
2801
                                   bool bForce)
2802
2803
0
{
2804
0
    if (phMiraMonLayer)
2805
0
    {
2806
0
        if (phMiraMonLayer->bIsDBF)
2807
0
            return OGRERR_FAILURE;
2808
2809
        // For polygons we need another polygon apart from the universal one
2810
        // to have a valid extension
2811
0
        if (phMiraMonLayer->bIsPolygon &&
2812
0
            phMiraMonLayer->TopHeader.nElemCount < 1)
2813
0
            return OGRERR_FAILURE;
2814
2815
0
        if (phMiraMonLayer->TopHeader.nElemCount < 1)
2816
0
            return OGRERR_FAILURE;
2817
2818
0
        psExtent->MinX = phMiraMonLayer->TopHeader.hBB.dfMinX;
2819
0
        psExtent->MaxX = phMiraMonLayer->TopHeader.hBB.dfMaxX;
2820
0
        psExtent->MinY = phMiraMonLayer->TopHeader.hBB.dfMinY;
2821
0
        psExtent->MaxY = phMiraMonLayer->TopHeader.hBB.dfMaxY;
2822
0
    }
2823
0
    else
2824
0
    {
2825
0
        if (!bForce)
2826
0
            return OGRERR_FAILURE;
2827
0
    }
2828
2829
0
    return OGRERR_NONE;
2830
0
}
2831
2832
/****************************************************************************/
2833
/*                           TestCapability()                               */
2834
/****************************************************************************/
2835
2836
int OGRMiraMonLayer::TestCapability(const char *pszCap)
2837
2838
2.39k
{
2839
2.39k
    if (EQUAL(pszCap, OLCRandomRead))
2840
0
        return TRUE;
2841
2842
2.39k
    if (EQUAL(pszCap, OLCSequentialWrite))
2843
0
        return m_bUpdate;
2844
2845
2.39k
    if (EQUAL(pszCap, OLCFastFeatureCount))
2846
0
        return !m_poFilterGeom && !m_poAttrQuery;
2847
2848
2.39k
    if (EQUAL(pszCap, OLCFastGetExtent))
2849
0
        return TRUE;
2850
2851
2.39k
    if (EQUAL(pszCap, OLCCreateField))
2852
0
        return m_bUpdate;
2853
2854
2.39k
    if (EQUAL(pszCap, OLCZGeometries))
2855
0
        return TRUE;
2856
2857
2.39k
    if (EQUAL(pszCap, OLCStringsAsUTF8))
2858
0
        return TRUE;
2859
2860
2.39k
    return FALSE;
2861
2.39k
}
2862
2863
/****************************************************************************/
2864
/*                            CreateField()                                 */
2865
/****************************************************************************/
2866
2867
OGRErr OGRMiraMonLayer::CreateField(const OGRFieldDefn *poField, int bApproxOK)
2868
2869
9.99k
{
2870
9.99k
    if (!m_bUpdate)
2871
0
    {
2872
0
        CPLError(CE_Failure, CPLE_NoWriteAccess,
2873
0
                 "Cannot create fields on a read-only dataset.");
2874
0
        return OGRERR_FAILURE;
2875
0
    }
2876
2877
9.99k
    if (phMiraMonLayer && phMiraMonLayer->TopHeader.nElemCount > 0)
2878
0
    {
2879
0
        CPLError(CE_Failure, CPLE_NoWriteAccess,
2880
0
                 "Cannot create fields to a layer with "
2881
0
                 "already existing features in it.");
2882
0
        return OGRERR_FAILURE;
2883
0
    }
2884
2885
9.99k
    switch (poField->GetType())
2886
9.99k
    {
2887
51
        case OFTInteger:
2888
51
        case OFTIntegerList:
2889
53
        case OFTInteger64:
2890
53
        case OFTInteger64List:
2891
71
        case OFTReal:
2892
71
        case OFTRealList:
2893
9.99k
        case OFTString:
2894
9.99k
        case OFTStringList:
2895
9.99k
        case OFTDate:
2896
9.99k
            m_poFeatureDefn->AddFieldDefn(poField);
2897
9.99k
            return OGRERR_NONE;
2898
0
        default:
2899
0
            if (!bApproxOK)
2900
0
            {
2901
0
                CPLError(CE_Failure, CPLE_AppDefined,
2902
0
                         "Field %s is of an unsupported type: %s.",
2903
0
                         poField->GetNameRef(),
2904
0
                         poField->GetFieldTypeName(poField->GetType()));
2905
0
                return OGRERR_FAILURE;
2906
0
            }
2907
0
            else
2908
0
            {
2909
0
                OGRFieldDefn oModDef(poField);
2910
0
                oModDef.SetType(OFTString);
2911
0
                m_poFeatureDefn->AddFieldDefn(poField);
2912
0
                return OGRERR_NONE;
2913
0
            }
2914
9.99k
    }
2915
9.99k
}
2916
2917
/************************************************************************/
2918
/*                            AddToFileList()                           */
2919
/************************************************************************/
2920
2921
void OGRMiraMonLayer::AddToFileList(CPLStringList &oFileList)
2922
0
{
2923
0
    if (!phMiraMonLayer)
2924
0
        return;
2925
2926
0
    char szAuxFile[MM_CPL_PATH_BUF_SIZE];
2927
2928
0
    oFileList.AddStringDirectly(
2929
0
        VSIGetCanonicalFilename(phMiraMonLayer->pszSrcLayerName));
2930
0
    char *pszMMExt =
2931
0
        CPLStrdup(CPLGetExtensionSafe(phMiraMonLayer->pszSrcLayerName).c_str());
2932
2933
0
    if (phMiraMonLayer->bIsPoint)
2934
0
    {
2935
        // As it's explicit on documentation a point has also two more files:
2936
2937
        // FILE_NAME_WITHOUT_EXTENSION.pnt --> FILE_NAME_WITHOUT_EXTENSION + T.rel
2938
0
        CPLStrlcpy(szAuxFile,
2939
0
                   CPLGetBasenameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
2940
0
                   MM_CPL_PATH_BUF_SIZE);
2941
0
        CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "T.rel" : "T.REL",
2942
0
                   MM_CPL_PATH_BUF_SIZE);
2943
0
        oFileList.AddStringDirectly(VSIGetCanonicalFilename(
2944
0
            CPLFormFilenameSafe(
2945
0
                CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
2946
0
                szAuxFile, nullptr)
2947
0
                .c_str()));
2948
2949
        // FILE_NAME_WITHOUT_EXTENSION.pnt --> FILE_NAME_WITHOUT_EXTENSION + T.dbf
2950
0
        CPLStrlcpy(szAuxFile,
2951
0
                   CPLGetBasenameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
2952
0
                   MM_CPL_PATH_BUF_SIZE);
2953
0
        CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "T.dbf" : "T.DBF",
2954
0
                   MM_CPL_PATH_BUF_SIZE);
2955
0
        oFileList.AddStringDirectly(VSIGetCanonicalFilename(
2956
0
            CPLFormFilenameSafe(
2957
0
                CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
2958
0
                szAuxFile, nullptr)
2959
0
                .c_str()));
2960
0
    }
2961
0
    else if (phMiraMonLayer->bIsArc && !phMiraMonLayer->bIsPolygon)
2962
0
    {
2963
        // As it's explicit on documentation a point has also five more files:
2964
2965
        // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + A.rel
2966
0
        CPLStrlcpy(szAuxFile,
2967
0
                   CPLGetBasenameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
2968
0
                   MM_CPL_PATH_BUF_SIZE);
2969
0
        CPLStrlcat(szAuxFile, (pszMMExt[0] == 'a') ? "A.rel" : "A.REL",
2970
0
                   MM_CPL_PATH_BUF_SIZE);
2971
0
        oFileList.AddStringDirectly(VSIGetCanonicalFilename(
2972
0
            CPLFormFilenameSafe(
2973
0
                CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
2974
0
                szAuxFile, nullptr)
2975
0
                .c_str()));
2976
2977
        // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + A.dbf
2978
0
        CPLStrlcpy(szAuxFile,
2979
0
                   CPLGetBasenameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
2980
0
                   MM_CPL_PATH_BUF_SIZE);
2981
0
        CPLStrlcat(szAuxFile, (pszMMExt[0] == 'a') ? "A.dbf" : "A.DBF",
2982
0
                   MM_CPL_PATH_BUF_SIZE);
2983
0
        oFileList.AddStringDirectly(VSIGetCanonicalFilename(
2984
0
            CPLFormFilenameSafe(
2985
0
                CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
2986
0
                szAuxFile, nullptr)
2987
0
                .c_str()));
2988
2989
        // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + .nod
2990
0
        CPLStrlcpy(szAuxFile,
2991
0
                   CPLGetBasenameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
2992
0
                   MM_CPL_PATH_BUF_SIZE);
2993
0
        CPLStrlcat(szAuxFile, (pszMMExt[0] == 'a') ? ".nod" : ".NOD",
2994
0
                   MM_CPL_PATH_BUF_SIZE);
2995
0
        oFileList.AddStringDirectly(VSIGetCanonicalFilename(
2996
0
            CPLFormFilenameSafe(
2997
0
                CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
2998
0
                szAuxFile, nullptr)
2999
0
                .c_str()));
3000
3001
        // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + N.rel
3002
0
        CPLStrlcpy(szAuxFile,
3003
0
                   CPLGetBasenameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
3004
0
                   MM_CPL_PATH_BUF_SIZE);
3005
0
        CPLStrlcat(szAuxFile, (pszMMExt[0] == 'a') ? "N.rel" : "N.REL",
3006
0
                   MM_CPL_PATH_BUF_SIZE);
3007
0
        oFileList.AddStringDirectly(VSIGetCanonicalFilename(
3008
0
            CPLFormFilenameSafe(
3009
0
                CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
3010
0
                szAuxFile, nullptr)
3011
0
                .c_str()));
3012
3013
        // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + N.dbf
3014
0
        CPLStrlcpy(szAuxFile,
3015
0
                   CPLGetBasenameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
3016
0
                   MM_CPL_PATH_BUF_SIZE);
3017
0
        CPLStrlcat(szAuxFile, (pszMMExt[0] == 'a') ? "N.dbf" : "N.DBF",
3018
0
                   MM_CPL_PATH_BUF_SIZE);
3019
0
        oFileList.AddStringDirectly(VSIGetCanonicalFilename(
3020
0
            CPLFormFilenameSafe(
3021
0
                CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
3022
0
                szAuxFile, nullptr)
3023
0
                .c_str()));
3024
0
    }
3025
0
    else if (phMiraMonLayer->bIsPolygon)
3026
0
    {
3027
        // As it's explicit on documentation a point has also eight more files:
3028
0
        char szArcFileName[MM_CPL_PATH_BUF_SIZE];
3029
3030
        // FILE_NAME_WITHOUT_EXTENSION.pol --> FILE_NAME_WITHOUT_EXTENSION + P.rel
3031
0
        CPLStrlcpy(szAuxFile,
3032
0
                   CPLGetBasenameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
3033
0
                   MM_CPL_PATH_BUF_SIZE);
3034
0
        CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "P.rel" : "P.REL",
3035
0
                   MM_CPL_PATH_BUF_SIZE);
3036
0
        oFileList.AddStringDirectly(VSIGetCanonicalFilename(
3037
0
            CPLFormFilenameSafe(
3038
0
                CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
3039
0
                szAuxFile, nullptr)
3040
0
                .c_str()));
3041
3042
        // The name of the arc is in THIS metadata file
3043
0
        char *pszArcLayerName = MMReturnValueFromSectionINIFile(
3044
0
            CPLFormFilenameSafe(
3045
0
                CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
3046
0
                szAuxFile, nullptr)
3047
0
                .c_str(),
3048
0
            SECTION_OVVW_ASPECTES_TECNICS, KEY_ArcSource);
3049
0
        if (!pszArcLayerName)
3050
0
        {
3051
0
            CPLFree(pszMMExt);
3052
0
            return;  //Some files are missing
3053
0
        }
3054
0
        CPLStrlcpy(szArcFileName, pszArcLayerName, MM_CPL_PATH_BUF_SIZE);
3055
3056
0
        MM_RemoveInitial_and_FinalQuotationMarks(szArcFileName);
3057
3058
        // If extension is not specified ".arc" will be used
3059
0
        if (MMIsEmptyString(CPLGetExtensionSafe(pszArcLayerName).c_str()))
3060
0
            CPLStrlcat(szArcFileName, (pszMMExt[0] == 'p') ? ".arc" : ".ARC",
3061
0
                       MM_CPL_PATH_BUF_SIZE);
3062
3063
0
        CPLFree(pszArcLayerName);
3064
3065
0
        const std::string osCompleteArcFileName = CPLFormFilenameSafe(
3066
0
            CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
3067
0
            szArcFileName, nullptr);
3068
3069
        // The arc that has the coordinates of the polygon
3070
0
        oFileList.AddStringDirectly(
3071
0
            VSIGetCanonicalFilename(osCompleteArcFileName.c_str()));
3072
3073
        // FILE_NAME_WITHOUT_EXTENSION.pol --> FILE_NAME_WITHOUT_EXTENSION + P.dbf
3074
0
        CPLStrlcpy(szAuxFile,
3075
0
                   CPLGetBasenameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
3076
0
                   MM_CPL_PATH_BUF_SIZE);
3077
0
        CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "P.dbf" : "P.DBF",
3078
0
                   MM_CPL_PATH_BUF_SIZE);
3079
0
        oFileList.AddStringDirectly(VSIGetCanonicalFilename(
3080
0
            CPLFormFilenameSafe(
3081
0
                CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
3082
0
                szAuxFile, nullptr)
3083
0
                .c_str()));
3084
3085
        // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + A.rel
3086
0
        const std::string osBaseArcName =
3087
0
            CPLGetBasenameSafe(osCompleteArcFileName.c_str());
3088
0
        CPLStrlcpy(szAuxFile, osBaseArcName.c_str(), MM_CPL_PATH_BUF_SIZE);
3089
0
        CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "A.rel" : "A.REL",
3090
0
                   MM_CPL_PATH_BUF_SIZE);
3091
0
        oFileList.AddStringDirectly(VSIGetCanonicalFilename(
3092
0
            CPLFormFilenameSafe(
3093
0
                CPLGetDirnameSafe(osCompleteArcFileName.c_str()).c_str(),
3094
0
                szAuxFile, nullptr)
3095
0
                .c_str()));
3096
3097
        // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + A.dbf
3098
0
        CPLStrlcpy(szAuxFile, osBaseArcName.c_str(), MM_CPL_PATH_BUF_SIZE);
3099
0
        CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "A.dbf" : "A.DBF",
3100
0
                   MM_CPL_PATH_BUF_SIZE);
3101
0
        oFileList.AddStringDirectly(VSIGetCanonicalFilename(
3102
0
            CPLFormFilenameSafe(
3103
0
                CPLGetDirnameSafe(osCompleteArcFileName.c_str()).c_str(),
3104
0
                szAuxFile, nullptr)
3105
0
                .c_str()));
3106
3107
        // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + .nod
3108
0
        CPLStrlcpy(szAuxFile, osBaseArcName.c_str(), MM_CPL_PATH_BUF_SIZE);
3109
0
        CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? ".nod" : ".NOD",
3110
0
                   MM_CPL_PATH_BUF_SIZE);
3111
0
        oFileList.AddStringDirectly(VSIGetCanonicalFilename(
3112
0
            CPLFormFilenameSafe(
3113
0
                CPLGetDirnameSafe(osCompleteArcFileName.c_str()).c_str(),
3114
0
                szAuxFile, nullptr)
3115
0
                .c_str()));
3116
3117
        // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + N.rel
3118
0
        CPLStrlcpy(szAuxFile, osBaseArcName.c_str(), MM_CPL_PATH_BUF_SIZE);
3119
0
        CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "N.rel" : "N.REL",
3120
0
                   MM_CPL_PATH_BUF_SIZE);
3121
0
        oFileList.AddStringDirectly(VSIGetCanonicalFilename(
3122
0
            CPLFormFilenameSafe(
3123
0
                CPLGetDirnameSafe(osCompleteArcFileName.c_str()).c_str(),
3124
0
                szAuxFile, nullptr)
3125
0
                .c_str()));
3126
3127
        // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + N.dbf
3128
0
        CPLStrlcpy(szAuxFile, osBaseArcName.c_str(), MM_CPL_PATH_BUF_SIZE);
3129
0
        CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "N.dbf" : "N.DBF",
3130
0
                   MM_CPL_PATH_BUF_SIZE);
3131
0
        oFileList.AddStringDirectly(VSIGetCanonicalFilename(
3132
0
            CPLFormFilenameSafe(
3133
0
                CPLGetDirnameSafe(osCompleteArcFileName.c_str()).c_str(),
3134
0
                szAuxFile, nullptr)
3135
0
                .c_str()));
3136
0
    }
3137
0
    CPLFree(pszMMExt);
3138
0
}