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