Coverage Report

Created: 2026-08-14 09:29

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