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