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 201 : OGRMiraMonLayer::OGRMiraMonLayer(GDALDataset *poDS, const char *pszFilename,
23 : VSILFILE *fp, const OGRSpatialReference *poSRS,
24 : int bUpdateIn, CSLConstList papszOpenOptions,
25 201 : 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 201 : m_bUpdate(CPL_TO_BOOL(bUpdateIn)),
30 201 : m_fp(fp ? fp : VSIFOpenL(pszFilename, (bUpdateIn ? "r+" : "r"))),
31 201 : padfValues(nullptr), pnInt64Values(nullptr), bValidFile(false)
32 : {
33 :
34 201 : CPLDebugOnly("MiraMon", "Creating/Opening MiraMon layer...");
35 : /* -------------------------------------------------------------------- */
36 : /* Create the feature definition */
37 : /* -------------------------------------------------------------------- */
38 201 : m_poFeatureDefn =
39 201 : new OGRFeatureDefn(CPLGetBasenameSafe(pszFilename).c_str());
40 201 : SetDescription(m_poFeatureDefn->GetName());
41 201 : m_poFeatureDefn->Reference();
42 :
43 201 : if (m_bUpdate)
44 : {
45 : /* ---------------------------------------------------------------- */
46 : /* Establish the version to use */
47 : /* ---------------------------------------------------------------- */
48 82 : const char *pszVersion = CSLFetchNameValue(papszOpenOptions, "Version");
49 : int nMMVersion;
50 :
51 82 : 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 72 : nMMVersion = MM_32BITS_VERSION; // Default
63 :
64 : /* ---------------------------------------------------------------- */
65 : /* Establish the charset of the .dbf files */
66 : /* ---------------------------------------------------------------- */
67 : const char *pszdbfEncoding =
68 82 : CSLFetchNameValue(papszOpenOptions, "DBFEncoding");
69 : char nMMRecode;
70 :
71 82 : 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 80 : nMMRecode = MM_RECODE_ANSI; // Default
80 :
81 : /* ----------------------------------------------------------------- */
82 : /* Establish the descriptors language when */
83 : /* creating .rel files */
84 : /* ----------------------------------------------------------------- */
85 : const char *pszLanguage =
86 82 : CSLFetchNameValue(papszOpenOptions, "CreationLanguage");
87 : char nMMLanguage;
88 :
89 82 : 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 79 : nMMLanguage = MM_DEF_LANGUAGE; // Default
100 :
101 : /* ---------------------------------------------------------------- */
102 : /* Preparing to write the layer */
103 : /* ---------------------------------------------------------------- */
104 : // Init the feature (memory, num,...)
105 82 : 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 82 : CPLDebugOnly("MiraMon", "Initializing MiraMon points layer...");
114 82 : if (MMInitLayer(&hMiraMonLayerPNT, pszFilename, nMMVersion, nMMRecode,
115 82 : nMMLanguage, nullptr, MM_WRITING_MODE, MMMap))
116 : {
117 0 : bValidFile = false;
118 0 : return;
119 : }
120 82 : hMiraMonLayerPNT.bIsBeenInit = 0;
121 :
122 82 : CPLDebugOnly("MiraMon", "Initializing MiraMon arcs layer...");
123 82 : if (MMInitLayer(&hMiraMonLayerARC, pszFilename, nMMVersion, nMMRecode,
124 82 : nMMLanguage, nullptr, MM_WRITING_MODE, MMMap))
125 : {
126 0 : bValidFile = false;
127 0 : return;
128 : }
129 82 : hMiraMonLayerARC.bIsBeenInit = 0;
130 :
131 82 : CPLDebugOnly("MiraMon", "Initializing MiraMon polygons layer...");
132 82 : if (MMInitLayer(&hMiraMonLayerPOL, pszFilename, nMMVersion, nMMRecode,
133 82 : nMMLanguage, nullptr, MM_WRITING_MODE, MMMap))
134 : {
135 0 : bValidFile = false;
136 0 : return;
137 : }
138 82 : 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 82 : CPLDebugOnly("MiraMon", "Initializing MiraMon only-ext-DBF layer...");
143 82 : if (MMInitLayer(&hMiraMonLayerReadOrNonGeom, pszFilename, nMMVersion,
144 : nMMRecode, nMMLanguage, nullptr, MM_WRITING_MODE,
145 82 : nullptr))
146 : {
147 0 : bValidFile = false;
148 0 : return;
149 : }
150 82 : hMiraMonLayerPOL.bIsBeenInit = 0;
151 :
152 : // This helps the map to be created
153 : //GetLayerDefn()->SetName(hMiraMonLayerPNT.pszSrcLayerName);
154 82 : m_poFeatureDefn->SetName(hMiraMonLayerPNT.pszSrcLayerName);
155 :
156 : // Saving the HRS in the layer structure
157 82 : if (poSRS)
158 : {
159 18 : const char *pszTargetKey = nullptr;
160 18 : const char *pszAuthorityName = nullptr;
161 18 : const char *pszAuthorityCode = nullptr;
162 :
163 : // Reading Z units (in case of 3D vector file)
164 18 : 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 18 : if (poSRS->IsProjected())
190 15 : 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 18 : if (!poSRS->IsLocal())
199 : {
200 18 : pszAuthorityName = poSRS->GetAuthorityName(pszTargetKey);
201 18 : pszAuthorityCode = poSRS->GetAuthorityCode(pszTargetKey);
202 : }
203 :
204 18 : if (pszAuthorityName && pszAuthorityCode &&
205 18 : EQUAL(pszAuthorityName, "EPSG"))
206 : {
207 18 : CPLDebugOnly("MiraMon", "Setting EPSG code %s",
208 : pszAuthorityCode);
209 18 : hMiraMonLayerPNT.pSRS = CPLStrdup(pszAuthorityCode);
210 18 : hMiraMonLayerARC.pSRS = CPLStrdup(pszAuthorityCode);
211 18 : 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 18 : 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 15 : hMiraMonLayerPNT.nSRSType = hMiraMonLayerARC.nSRSType =
224 15 : 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 119 : 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 119 : if (MMInitLayerToRead(&hMiraMonLayerReadOrNonGeom, m_fp, pszFilename))
247 : {
248 8 : phMiraMonLayer = &hMiraMonLayerReadOrNonGeom;
249 8 : bValidFile = false;
250 8 : return;
251 : }
252 111 : phMiraMonLayer = &hMiraMonLayerReadOrNonGeom;
253 :
254 111 : nMMLayerVersion = MMGetVectorVersion(&phMiraMonLayer->TopHeader);
255 111 : 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 111 : if (phMiraMonLayer->bIsPoint)
263 : {
264 39 : if (phMiraMonLayer->TopHeader.bIs3d)
265 12 : m_poFeatureDefn->SetGeomType(wkbPoint25D);
266 : else
267 27 : 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 111 : 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 111 : CSLFetchNameValue(papszOpenOptions, "OpenLanguage");
325 :
326 111 : 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 105 : phMiraMonLayer->nMMLanguage = MM_DEF_LANGUAGE; // Default
337 :
338 111 : if (phMiraMonLayer->nSRS_EPSG != 0)
339 : {
340 60 : m_poSRS = new OGRSpatialReference();
341 60 : m_poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
342 60 : 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 60 : m_poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(m_poSRS);
350 : }
351 :
352 : // If there is associated information
353 111 : if (phMiraMonLayer->pMMBDXP)
354 : {
355 111 : if (!phMiraMonLayer->pMMBDXP->pfDataBase)
356 : {
357 111 : if ((phMiraMonLayer->pMMBDXP->pfDataBase = fopen_function(
358 111 : 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 111 : 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 222 : phMiraMonLayer->pMultRecordIndex = MMCreateExtendedDBFIndex(
380 111 : phMiraMonLayer->pMMBDXP->pfDataBase,
381 111 : phMiraMonLayer->pMMBDXP->nRecords,
382 111 : phMiraMonLayer->pMMBDXP->FirstRecordOffset,
383 111 : phMiraMonLayer->pMMBDXP->BytesPerRecord,
384 111 : phMiraMonLayer->pMMBDXP
385 111 : ->pField[phMiraMonLayer->pMMBDXP->IdGraficField]
386 : .AccumulatedBytes,
387 111 : phMiraMonLayer->pMMBDXP
388 111 : ->pField[phMiraMonLayer->pMMBDXP->IdGraficField]
389 : .BytesPerField,
390 111 : &phMiraMonLayer->isListField, &phMiraMonLayer->nMaxN);
391 :
392 : // Creation of maximum number needed for processing
393 : // multiple records
394 111 : if (phMiraMonLayer->pMultRecordIndex)
395 : {
396 204 : padfValues = static_cast<double *>(CPLCalloc(
397 102 : (size_t)phMiraMonLayer->nMaxN, sizeof(*padfValues)));
398 :
399 102 : pnInt64Values = static_cast<GInt64 *>(CPLCalloc(
400 102 : (size_t)phMiraMonLayer->nMaxN, sizeof(*pnInt64Values)));
401 : }
402 :
403 111 : phMiraMonLayer->iMultiRecord =
404 : MM_MULTIRECORD_NO_MULTIRECORD; // No option iMultiRecord
405 : const char *szMultiRecord =
406 111 : CSLFetchNameValue(papszOpenOptions, "MultiRecordIndex");
407 111 : 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 1161 : for (MM_EXT_DBF_N_FIELDS nIField = 0;
419 1161 : nIField < phMiraMonLayer->pMMBDXP->nFields; nIField++)
420 : {
421 2100 : OGRFieldDefn oField("", OFTString);
422 1050 : oField.SetName(
423 1050 : phMiraMonLayer->pMMBDXP->pField[nIField].FieldName);
424 :
425 1050 : oField.SetAlternativeName(
426 1050 : phMiraMonLayer->pMMBDXP->pField[nIField]
427 1050 : .FieldDescription[phMiraMonLayer->nMMLanguage <
428 : MM_NUM_IDIOMES_MD_MULTIDIOMA
429 1050 : ? phMiraMonLayer->nMMLanguage
430 1050 : : 0]);
431 :
432 1050 : if (phMiraMonLayer->pMMBDXP->pField[nIField].FieldType == 'C' ||
433 880 : 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 796 : else if (phMiraMonLayer->pMMBDXP->pField[nIField].FieldType ==
468 : 'N')
469 : {
470 : // It's a list?
471 756 : if (phMiraMonLayer->iMultiRecord ==
472 : MM_MULTIRECORD_NO_MULTIRECORD)
473 : {
474 624 : if (phMiraMonLayer->pMMBDXP->pField[nIField]
475 624 : .DecimalsIfFloat)
476 182 : oField.SetType(phMiraMonLayer->isListField
477 : ? OFTRealList
478 : : OFTReal);
479 : else
480 : {
481 442 : if (phMiraMonLayer->pMMBDXP->pField[nIField]
482 442 : .BytesPerField < 10)
483 : {
484 202 : 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 1050 : oField.SetWidth(
525 1050 : phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField);
526 1050 : oField.SetPrecision(
527 1050 : phMiraMonLayer->pMMBDXP->pField[nIField].DecimalsIfFloat);
528 :
529 1050 : m_poFeatureDefn->AddFieldDefn(&oField);
530 : }
531 : }
532 : }
533 :
534 193 : bValidFile = true;
535 : }
536 :
537 : /****************************************************************************/
538 : /* ~OGRMiraMonLayer() */
539 : /****************************************************************************/
540 :
541 402 : OGRMiraMonLayer::~OGRMiraMonLayer()
542 :
543 : {
544 201 : if (m_nFeaturesRead > 0 && m_poFeatureDefn != nullptr)
545 : {
546 82 : CPLDebugOnly("MiraMon", "%d features read on layer '%s'.",
547 : static_cast<int>(m_nFeaturesRead),
548 : m_poFeatureDefn->GetName());
549 : }
550 :
551 201 : 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 174 : else if (hMiraMonLayerPOL.ReadOrWrite == MM_WRITING_MODE)
571 : {
572 55 : CPLDebugOnly("MiraMon", "No MiraMon polygons layer created.");
573 : }
574 :
575 201 : 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 171 : else if (hMiraMonLayerARC.ReadOrWrite == MM_WRITING_MODE)
596 : {
597 52 : CPLDebugOnly("MiraMon", "No MiraMon arcs layer created.");
598 : }
599 :
600 201 : if (hMiraMonLayerPNT.bIsPoint)
601 : {
602 33 : CPLDebugOnly("MiraMon", "Closing MiraMon points layer...");
603 33 : 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 33 : if (hMiraMonLayerPNT.TopHeader.nElemCount)
611 : {
612 33 : CPLDebugOnly("MiraMon",
613 : sprintf_UINT64 " point(s) written in file %s.pnt",
614 : hMiraMonLayerPNT.TopHeader.nElemCount,
615 : hMiraMonLayerPNT.pszSrcLayerName);
616 : }
617 33 : CPLDebugOnly("MiraMon", "MiraMon points layer closed");
618 : }
619 168 : else if (hMiraMonLayerPNT.ReadOrWrite == MM_WRITING_MODE)
620 : {
621 49 : CPLDebugOnly("MiraMon", "No MiraMon points layer created.");
622 : }
623 :
624 201 : if (hMiraMonLayerARC.ReadOrWrite == MM_WRITING_MODE)
625 : {
626 82 : 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 65 : else if (hMiraMonLayerReadOrNonGeom.ReadOrWrite == MM_WRITING_MODE)
643 : {
644 65 : CPLDebugOnly("MiraMon", "No MiraMon DBF table created.");
645 : }
646 : }
647 : else
648 : {
649 119 : if (hMiraMonLayerReadOrNonGeom.ReadOrWrite == MM_WRITING_MODE)
650 : {
651 0 : CPLDebugOnly("MiraMon", "Closing MiraMon layer ...");
652 : }
653 119 : if (MMCloseLayer(&hMiraMonLayerReadOrNonGeom))
654 : {
655 : // In case of closing we need to destroy memory
656 0 : MMDestroyLayer(&hMiraMonLayerReadOrNonGeom);
657 : }
658 119 : if (hMiraMonLayerReadOrNonGeom.ReadOrWrite == MM_WRITING_MODE)
659 : {
660 0 : CPLDebugOnly("MiraMon", "MiraMon layer closed");
661 : }
662 : }
663 :
664 201 : if (hMiraMonLayerPOL.ReadOrWrite == MM_WRITING_MODE)
665 : {
666 82 : MMCPLDebug("MiraMon", "Destroying MiraMon polygons layer memory");
667 : }
668 201 : MMDestroyLayer(&hMiraMonLayerPOL);
669 201 : if (hMiraMonLayerPOL.ReadOrWrite == MM_WRITING_MODE)
670 : {
671 82 : MMCPLDebug("MiraMon", "MiraMon polygons layer memory destroyed");
672 : }
673 :
674 201 : if (hMiraMonLayerARC.ReadOrWrite == MM_WRITING_MODE)
675 : {
676 82 : MMCPLDebug("MiraMon", "Destroying MiraMon arcs layer memory");
677 : }
678 201 : MMDestroyLayer(&hMiraMonLayerARC);
679 201 : if (hMiraMonLayerARC.ReadOrWrite == MM_WRITING_MODE)
680 : {
681 82 : MMCPLDebug("MiraMon", "MiraMon arcs layer memory destroyed");
682 : }
683 :
684 201 : if (hMiraMonLayerPNT.ReadOrWrite == MM_WRITING_MODE)
685 : {
686 82 : MMCPLDebug("MiraMon", "Destroying MiraMon points layer memory");
687 : }
688 201 : MMDestroyLayer(&hMiraMonLayerPNT);
689 201 : if (hMiraMonLayerPNT.ReadOrWrite == MM_WRITING_MODE)
690 : {
691 82 : MMCPLDebug("MiraMon", "MiraMon points layer memory destroyed");
692 : }
693 :
694 201 : if (hMiraMonLayerReadOrNonGeom.ReadOrWrite == MM_WRITING_MODE)
695 : {
696 82 : MMCPLDebug("MiraMon", "Destroying MiraMon DBF table layer memory");
697 : }
698 : else
699 : {
700 119 : MMCPLDebug("MiraMon", "Destroying MiraMon layer memory");
701 : }
702 :
703 201 : MMDestroyLayer(&hMiraMonLayerReadOrNonGeom);
704 201 : if (hMiraMonLayerReadOrNonGeom.ReadOrWrite == MM_WRITING_MODE)
705 : {
706 82 : MMCPLDebug("MiraMon", "MiraMon DBF table layer memory destroyed");
707 : }
708 : else
709 : {
710 119 : MMCPLDebug("MiraMon", "MiraMon layer memory destroyed");
711 : }
712 :
713 201 : memset(&hMiraMonLayerReadOrNonGeom, 0, sizeof(hMiraMonLayerReadOrNonGeom));
714 201 : memset(&hMiraMonLayerPNT, 0, sizeof(hMiraMonLayerPNT));
715 201 : memset(&hMiraMonLayerARC, 0, sizeof(hMiraMonLayerARC));
716 201 : memset(&hMiraMonLayerPOL, 0, sizeof(hMiraMonLayerPOL));
717 :
718 201 : MMCPLDebug("MiraMon", "Destroying MiraMon temporary feature memory");
719 201 : MMDestroyFeature(&hMMFeature);
720 201 : MMCPLDebug("MiraMon", "MiraMon temporary feature memory");
721 201 : memset(&hMMFeature, 0, sizeof(hMMFeature));
722 :
723 : /* -------------------------------------------------------------------- */
724 : /* Clean up. */
725 : /* -------------------------------------------------------------------- */
726 :
727 201 : if (m_poFeatureDefn)
728 201 : m_poFeatureDefn->Release();
729 :
730 201 : if (m_poSRS)
731 60 : m_poSRS->Release();
732 :
733 201 : if (m_fp != nullptr)
734 119 : VSIFCloseL(m_fp);
735 :
736 201 : if (padfValues != nullptr)
737 102 : CPLFree(padfValues);
738 :
739 201 : if (pnInt64Values != nullptr)
740 102 : CPLFree(pnInt64Values);
741 402 : }
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 16542 : 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 16542 : if (!phMiraMonLayer->pMultRecordIndex)
788 0 : return;
789 :
790 16542 : fseek_function(
791 : phMiraMonLayer->pMMBDXP->pfDataBase,
792 : phMiraMonLayer->pMultRecordIndex[iFID].offset +
793 : (MM_FILE_OFFSET)nIRecord * phMiraMonLayer->pMMBDXP->BytesPerRecord +
794 : phMiraMonLayer->pMMBDXP->pField[nIField].AccumulatedBytes,
795 : SEEK_SET);
796 : }
797 :
798 : /****************************************************************************/
799 : /* GetNextRawFeature() */
800 : /****************************************************************************/
801 :
802 1923 : OGRFeature *OGRMiraMonLayer::GetNextRawFeature()
803 : {
804 1923 : if (!phMiraMonLayer)
805 0 : return nullptr;
806 :
807 1923 : if (m_iNextFID >= (GUInt64)phMiraMonLayer->TopHeader.nElemCount)
808 154 : return nullptr;
809 :
810 1769 : OGRFeature *poFeature = GetFeature(m_iNextFID);
811 :
812 1769 : if (!poFeature)
813 115 : return nullptr;
814 :
815 1654 : m_iNextFID++;
816 1654 : return poFeature;
817 : }
818 :
819 : /****************************************************************************/
820 : /* GetFeature() */
821 : /****************************************************************************/
822 :
823 1834 : OGRFeature *OGRMiraMonLayer::GetFeature(GIntBig nFeatureId)
824 :
825 : {
826 1834 : OGRGeometry *poGeom = nullptr;
827 1834 : OGRPoint *poPoint = nullptr;
828 1834 : OGRLineString *poLS = nullptr;
829 : MM_INTERNAL_FID nIElem;
830 1834 : MM_EXT_DBF_N_MULTIPLE_RECORDS nIRecord = 0;
831 :
832 1834 : if (!phMiraMonLayer)
833 0 : return nullptr;
834 :
835 1834 : if (nFeatureId < 0)
836 10 : return nullptr;
837 :
838 1824 : 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 1381 : nIElem = (MM_INTERNAL_FID)nFeatureId;
847 :
848 1824 : if (nIElem >= phMiraMonLayer->TopHeader.nElemCount)
849 115 : return nullptr;
850 :
851 : /* -------------------------------------------------------------------- */
852 : /* Read nFeatureId feature directly from the file. */
853 : /* -------------------------------------------------------------------- */
854 1709 : switch (phMiraMonLayer->eLT)
855 : {
856 1015 : case MM_LayerType_Point:
857 : case MM_LayerType_Point3d:
858 : // Read point
859 1015 : poGeom = new OGRPoint();
860 1015 : poPoint = poGeom->toPoint();
861 :
862 : // Get X,Y (z). MiraMon has no multipoints
863 1015 : 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 1010 : poPoint->setX(phMiraMonLayer->ReadFeature.pCoord[0].dfX);
871 1010 : poPoint->setY(phMiraMonLayer->ReadFeature.pCoord[0].dfY);
872 1010 : if (phMiraMonLayer->TopHeader.bIs3d)
873 874 : poPoint->setZ(phMiraMonLayer->ReadFeature.pZCoord[0]);
874 1689 : 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 1689 : if (poGeom == nullptr)
1051 0 : return nullptr;
1052 :
1053 : /* -------------------------------------------------------------------- */
1054 : /* Create feature. */
1055 : /* -------------------------------------------------------------------- */
1056 3378 : auto poFeature = std::make_unique<OGRFeature>(m_poFeatureDefn);
1057 1689 : poGeom->assignSpatialReference(m_poSRS);
1058 1689 : poFeature->SetGeometryDirectly(poGeom);
1059 :
1060 : /* -------------------------------------------------------------------- */
1061 : /* Process field values if its possible. */
1062 : /* -------------------------------------------------------------------- */
1063 1689 : if (phMiraMonLayer->pMMBDXP &&
1064 1689 : (MM_EXT_DBF_N_RECORDS)nIElem < phMiraMonLayer->pMMBDXP->nRecords)
1065 : {
1066 : MM_EXT_DBF_N_FIELDS nIField;
1067 :
1068 17461 : for (nIField = 0; nIField < phMiraMonLayer->pMMBDXP->nFields; nIField++)
1069 : {
1070 31544 : if (MMResizeStringToOperateIfNeeded(
1071 : phMiraMonLayer,
1072 15772 : phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField + 1))
1073 : {
1074 0 : return nullptr;
1075 : }
1076 :
1077 15772 : if (poFeature->GetDefnRef()->GetFieldDefn(nIField)->GetType() ==
1078 34062 : OFTStringList ||
1079 15698 : (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 : fread_function(phMiraMonLayer->szStringToOperate,
1114 : phMiraMonLayer->pMMBDXP->pField[nIField]
1115 : .BytesPerField,
1116 : 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 : fread_function(phMiraMonLayer->szStringToOperate,
1177 : phMiraMonLayer->pMMBDXP->pField[nIField]
1178 : .BytesPerField,
1179 : 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 15656 : else if (poFeature->GetDefnRef()
1216 15656 : ->GetFieldDefn(nIField)
1217 15656 : ->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 : fread_function(
1257 : phMiraMonLayer->szStringToOperate,
1258 : phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField, 1,
1259 : 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 13106 : else if (poFeature->GetDefnRef()
1285 13106 : ->GetFieldDefn(nIField)
1286 26034 : ->GetType() == OFTIntegerList ||
1287 12928 : poFeature->GetDefnRef()
1288 12928 : ->GetFieldDefn(nIField)
1289 12928 : ->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 : fread_function(
1309 : phMiraMonLayer->szStringToOperate,
1310 : phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField,
1311 : 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 12713 : else if (poFeature->GetDefnRef()
1345 12713 : ->GetFieldDefn(nIField)
1346 12713 : ->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 : fread_function(
1366 : phMiraMonLayer->szStringToOperate,
1367 : phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField,
1368 : 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 12520 : else if (poFeature->GetDefnRef()
1385 12520 : ->GetFieldDefn(nIField)
1386 17811 : ->GetType() == OFTInteger ||
1387 5291 : poFeature->GetDefnRef()
1388 5291 : ->GetFieldDefn(nIField)
1389 23102 : ->GetType() == OFTInteger64 ||
1390 3330 : poFeature->GetDefnRef()
1391 3330 : ->GetFieldDefn(nIField)
1392 3330 : ->GetType() == OFTReal)
1393 : {
1394 11589 : if (!phMiraMonLayer->pMultRecordIndex ||
1395 11589 : 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 11589 : 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 11490 : GoToFieldOfMultipleRecord(nIElem, 0, nIField);
1432 :
1433 11589 : memset(phMiraMonLayer->szStringToOperate, 0,
1434 11589 : phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField);
1435 11589 : fread_function(
1436 : phMiraMonLayer->szStringToOperate,
1437 : phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField, 1,
1438 : phMiraMonLayer->pMMBDXP->pfDataBase);
1439 11589 : phMiraMonLayer
1440 11589 : ->szStringToOperate[phMiraMonLayer->pMMBDXP->pField[nIField]
1441 11589 : .BytesPerField] = '\0';
1442 11589 : MM_RemoveWhitespacesFromEndOfString(
1443 11589 : phMiraMonLayer->szStringToOperate);
1444 :
1445 11589 : 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 9628 : if (poFeature->GetDefnRef()
1455 9628 : ->GetFieldDefn(nIField)
1456 16857 : ->GetType() == OFTInteger &&
1457 7229 : poFeature->GetDefnRef()
1458 7229 : ->GetFieldDefn(nIField)
1459 7229 : ->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 8498 : poFeature->SetField(
1471 8498 : 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 : fread_function(
1517 : phMiraMonLayer->szStringToOperate,
1518 : phMiraMonLayer->pMMBDXP->pField[nIField].BytesPerField, 1,
1519 : 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 1689 : poFeature->SetFID(nFeatureId);
1558 :
1559 1689 : m_nFeaturesRead++;
1560 1689 : return poFeature.release();
1561 : }
1562 :
1563 : /****************************************************************************/
1564 : /* GetFeatureCount() */
1565 : /****************************************************************************/
1566 164 : GIntBig OGRMiraMonLayer::GetFeatureCount(int bForce)
1567 : {
1568 164 : if (!phMiraMonLayer || m_poFilterGeom != nullptr ||
1569 136 : m_poAttrQuery != nullptr)
1570 40 : return OGRLayer::GetFeatureCount(bForce);
1571 :
1572 124 : if (phMiraMonLayer->bIsPolygon)
1573 : {
1574 112 : return std::max((GIntBig)0,
1575 56 : (GIntBig)(phMiraMonLayer->TopHeader.nElemCount - 1));
1576 : }
1577 68 : return (GIntBig)phMiraMonLayer->TopHeader.nElemCount;
1578 : }
1579 :
1580 : /****************************************************************************/
1581 : /* MMProcessMultiGeometry() */
1582 : /****************************************************************************/
1583 173 : OGRErr OGRMiraMonLayer::MMProcessMultiGeometry(OGRGeometryH hGeom,
1584 : OGRFeature *poFeature)
1585 :
1586 : {
1587 173 : OGRErr eErr = OGRERR_NONE;
1588 173 : OGRGeometry *poGeom = OGRGeometry::FromHandle(hGeom);
1589 :
1590 173 : 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 173 : 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 339 : if (wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString ||
1613 166 : 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 158 : return MMProcessGeometry(OGRGeometry::ToHandle(poGeom), poFeature, TRUE);
1629 : }
1630 :
1631 : /****************************************************************************/
1632 : /* MMProcessGeometry() */
1633 : /****************************************************************************/
1634 210 : OGRErr OGRMiraMonLayer::MMProcessGeometry(OGRGeometryH hGeom,
1635 : OGRFeature *poFeature,
1636 : MM_BOOLEAN bcalculateRecord)
1637 :
1638 : {
1639 210 : OGRErr eErr = OGRERR_NONE;
1640 210 : OGRGeometry *poGeom = nullptr;
1641 210 : if (hGeom)
1642 : {
1643 176 : poGeom = OGRGeometry::FromHandle(hGeom);
1644 :
1645 : // Translating types from GDAL to MiraMon
1646 176 : int eLT = poGeom->getGeometryType();
1647 176 : switch (wkbFlatten(eLT))
1648 : {
1649 87 : case wkbPoint:
1650 87 : phMiraMonLayer = &hMiraMonLayerPNT;
1651 87 : if (OGR_G_Is3D(hGeom))
1652 43 : phMiraMonLayer->eLT = MM_LayerType_Point3d;
1653 : else
1654 44 : phMiraMonLayer->eLT = MM_LayerType_Point;
1655 87 : 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 210 : MMResetFeatureGeometry(&hMMFeature);
1697 210 : if (bcalculateRecord)
1698 : {
1699 207 : MMResetFeatureRecord(&hMMFeature);
1700 207 : if (!phMiraMonLayer->pLayerDB)
1701 : {
1702 107 : eErr = TranslateFieldsToMM();
1703 107 : if (eErr != OGRERR_NONE)
1704 0 : return eErr;
1705 : }
1706 : // Content field translation from GDAL to MiraMon
1707 207 : eErr = TranslateFieldsValuesToMM(poFeature);
1708 207 : 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 210 : if (poGeom)
1721 : {
1722 176 : 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 210 : if (eErr == OGRERR_NONE)
1738 210 : return MMWriteGeometry();
1739 0 : CPLDebugOnly("MiraMon", "Error in MMProcessGeometry()");
1740 0 : return eErr;
1741 : }
1742 :
1743 : /****************************************************************************/
1744 : /* ICreateFeature() */
1745 : /****************************************************************************/
1746 :
1747 195 : OGRErr OGRMiraMonLayer::ICreateFeature(OGRFeature *poFeature)
1748 :
1749 : {
1750 195 : OGRErr eErr = OGRERR_NONE;
1751 :
1752 195 : 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 195 : OGRGeometry *poGeom = poFeature->GetGeometryRef();
1763 :
1764 : // Processing a feature without geometry.
1765 195 : 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 161 : 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 155 : eErr = MMProcessMultiGeometry(OGRGeometry::ToHandle(poGeom), poFeature);
1792 :
1793 : // Set the FID from 0 index
1794 155 : if (phMiraMonLayer)
1795 : {
1796 155 : if (phMiraMonLayer->bIsPolygon &&
1797 35 : phMiraMonLayer->TopHeader.nElemCount > 1)
1798 35 : poFeature->SetFID((GIntBig)phMiraMonLayer->TopHeader.nElemCount -
1799 35 : 2);
1800 120 : else if (phMiraMonLayer->TopHeader.nElemCount > 0)
1801 120 : poFeature->SetFID((GIntBig)phMiraMonLayer->TopHeader.nElemCount -
1802 120 : 1);
1803 : }
1804 155 : return eErr;
1805 : }
1806 :
1807 : /****************************************************************************/
1808 : /* MMDumpVertices() */
1809 : /****************************************************************************/
1810 :
1811 188 : 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 188 : if (!phMiraMonLayer)
1818 0 : return OGRERR_FAILURE;
1819 :
1820 188 : if (!phMiraMonLayer->bIsBeenInit)
1821 : {
1822 90 : if (MMInitLayerByType(phMiraMonLayer))
1823 0 : return OGRERR_FAILURE;
1824 90 : phMiraMonLayer->bIsBeenInit = 1;
1825 : }
1826 376 : if (MMResize_MM_N_VERTICES_TYPE_Pointer(
1827 : &hMMFeature.pNCoordRing, &hMMFeature.nMaxpNCoordRing,
1828 188 : (MM_N_VERTICES_TYPE)hMMFeature.nNRings + 1, MM_MEAN_NUMBER_OF_RINGS,
1829 188 : 0))
1830 0 : return OGRERR_FAILURE;
1831 :
1832 188 : 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 188 : hMMFeature.pNCoordRing[hMMFeature.nIRing] = OGR_G_GetPointCount(hGeom);
1851 :
1852 376 : if (MMResizeMM_POINT2DPointer(&hMMFeature.pCoord, &hMMFeature.nMaxpCoord,
1853 188 : hMMFeature.nICoord +
1854 188 : hMMFeature.pNCoordRing[hMMFeature.nIRing],
1855 188 : MM_MEAN_NUMBER_OF_NCOORDS, 0))
1856 0 : return OGRERR_FAILURE;
1857 376 : if (MMResizeDoublePointer(&hMMFeature.pZCoord, &hMMFeature.nMaxpZCoord,
1858 188 : hMMFeature.nICoord +
1859 188 : hMMFeature.pNCoordRing[hMMFeature.nIRing],
1860 188 : MM_MEAN_NUMBER_OF_NCOORDS, 0))
1861 0 : return OGRERR_FAILURE;
1862 :
1863 188 : hMMFeature.bAllZHaveSameValue = TRUE;
1864 188 : for (int iPoint = 0;
1865 743 : (MM_N_VERTICES_TYPE)iPoint < hMMFeature.pNCoordRing[hMMFeature.nIRing];
1866 : iPoint++)
1867 : {
1868 555 : hMMFeature.pCoord[hMMFeature.nICoord].dfX = OGR_G_GetX(hGeom, iPoint);
1869 555 : hMMFeature.pCoord[hMMFeature.nICoord].dfY = OGR_G_GetY(hGeom, iPoint);
1870 555 : if (OGR_G_GetCoordinateDimension(hGeom) == 2)
1871 387 : 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 555 : if (iPoint > 0 &&
1884 367 : !CPLIsEqual(hMMFeature.pZCoord[hMMFeature.nICoord],
1885 : hMMFeature.pZCoord[hMMFeature.nICoord - 1]))
1886 40 : hMMFeature.bAllZHaveSameValue = FALSE;
1887 :
1888 555 : hMMFeature.nICoord++;
1889 : }
1890 188 : hMMFeature.nIRing++;
1891 188 : hMMFeature.nNRings++;
1892 188 : return OGRERR_NONE;
1893 : }
1894 :
1895 : /****************************************************************************/
1896 : /* MMLoadGeometry() */
1897 : /* */
1898 : /* Loads on a MiraMon object Feature all coordinates from feature */
1899 : /* */
1900 : /****************************************************************************/
1901 190 : OGRErr OGRMiraMonLayer::MMLoadGeometry(OGRGeometryH hGeom)
1902 :
1903 : {
1904 190 : OGRErr eErr = OGRERR_NONE;
1905 : MM_BOOLEAN bExternalRing;
1906 :
1907 : /* -------------------------------------------------------------------- */
1908 : /* This is a geometry with sub-geometries. */
1909 : /* -------------------------------------------------------------------- */
1910 190 : int nGeom = OGR_G_GetGeometryCount(hGeom);
1911 :
1912 190 : int eLT = wkbFlatten(OGR_G_GetGeometryType(hGeom));
1913 :
1914 190 : 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 190 : 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 190 : 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 145 : else if (eLT == wkbPoint || eLT == wkbLineString)
1955 : {
1956 : // Reads all coordinates
1957 135 : eErr = MMDumpVertices(hGeom, true, FALSE);
1958 :
1959 135 : 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 190 : return OGRERR_NONE;
1971 : }
1972 :
1973 : /****************************************************************************/
1974 : /* WriteGeometry() */
1975 : /* */
1976 : /* Writes a geometry to the file. */
1977 : /****************************************************************************/
1978 :
1979 210 : OGRErr OGRMiraMonLayer::MMWriteGeometry()
1980 :
1981 : {
1982 210 : OGRErr eErr = MMAddFeature(phMiraMonLayer, &hMMFeature);
1983 :
1984 210 : 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 210 : 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 210 : return OGRERR_NONE;
2005 : }
2006 :
2007 : /****************************************************************************/
2008 : /* TranslateFieldsToMM() */
2009 : /* */
2010 : /* Translase ogr Fields to a structure that MiraMon can understand */
2011 : /****************************************************************************/
2012 :
2013 107 : OGRErr OGRMiraMonLayer::TranslateFieldsToMM()
2014 :
2015 : {
2016 107 : if (m_poFeatureDefn->GetFieldCount() == 0)
2017 0 : return OGRERR_NONE;
2018 :
2019 107 : CPLDebugOnly("MiraMon", "Translating fields to MiraMon...");
2020 : // If the structure is filled we do anything
2021 107 : if (phMiraMonLayer->pLayerDB)
2022 0 : return OGRERR_NONE;
2023 :
2024 214 : phMiraMonLayer->pLayerDB = static_cast<struct MiraMonDataBase *>(
2025 107 : VSICalloc(sizeof(*phMiraMonLayer->pLayerDB), 1));
2026 107 : if (!phMiraMonLayer->pLayerDB)
2027 0 : return OGRERR_NOT_ENOUGH_MEMORY;
2028 :
2029 214 : phMiraMonLayer->pLayerDB->pFields =
2030 : static_cast<struct MiraMonDataBaseField *>(
2031 107 : VSICalloc(m_poFeatureDefn->GetFieldCount(),
2032 : sizeof(*(phMiraMonLayer->pLayerDB->pFields))));
2033 107 : if (!phMiraMonLayer->pLayerDB->pFields)
2034 0 : return OGRERR_NOT_ENOUGH_MEMORY;
2035 :
2036 107 : phMiraMonLayer->pLayerDB->nNFields = 0;
2037 107 : if (phMiraMonLayer->pLayerDB->pFields)
2038 : {
2039 107 : memset(phMiraMonLayer->pLayerDB->pFields, 0,
2040 107 : m_poFeatureDefn->GetFieldCount() *
2041 : sizeof(*phMiraMonLayer->pLayerDB->pFields));
2042 107 : for (MM_EXT_DBF_N_FIELDS iField = 0;
2043 682 : iField < (MM_EXT_DBF_N_FIELDS)m_poFeatureDefn->GetFieldCount();
2044 : iField++)
2045 : {
2046 575 : 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 109 : case OFTReal:
2077 : case OFTRealList:
2078 109 : phMiraMonLayer->pLayerDB->pFields[iField].eFieldType =
2079 : MM_Numeric;
2080 109 : phMiraMonLayer->pLayerDB->pFields[iField]
2081 109 : .nNumberOfDecimals =
2082 109 : m_poFeatureDefn->GetFieldDefn(iField)->GetPrecision();
2083 109 : 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 575 : if (m_poFeatureDefn->GetFieldDefn(iField)->GetType() == OFTDate)
2109 68 : phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize = 8;
2110 507 : else if ((m_poFeatureDefn->GetFieldDefn(iField)->GetType() ==
2111 398 : OFTInteger ||
2112 398 : m_poFeatureDefn->GetFieldDefn(iField)->GetType() ==
2113 1014 : OFTIntegerList) &&
2114 127 : m_poFeatureDefn->GetFieldDefn(iField)->GetSubType() ==
2115 : OFSTBoolean)
2116 : {
2117 33 : phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize = 1;
2118 : }
2119 : else
2120 : {
2121 : // As https://gdal.org/api/ogrfeature_cpp.html indicates that
2122 : // precision (number of digits after decimal point) is optional,
2123 : // and a 0 is probably the default value, in that case we prefer
2124 : // to save all the guaranteed significant figures in a double
2125 : // (needed if a field contains, for instance, coordinates in
2126 : // geodetic degrees and a 1:1000 map precision applies).
2127 474 : if (m_poFeatureDefn->GetFieldDefn(iField)->GetPrecision() == 0)
2128 : {
2129 450 : if (m_poFeatureDefn->GetFieldDefn(iField)->GetType() ==
2130 831 : OFTReal ||
2131 381 : m_poFeatureDefn->GetFieldDefn(iField)->GetType() ==
2132 : OFTRealList)
2133 : {
2134 85 : phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize =
2135 : 20;
2136 85 : phMiraMonLayer->pLayerDB->pFields[iField]
2137 85 : .nNumberOfDecimals = MAX_RELIABLE_SF_DOUBLE;
2138 : }
2139 : else
2140 : {
2141 365 : phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize =
2142 365 : m_poFeatureDefn->GetFieldDefn(iField)->GetWidth();
2143 365 : if (phMiraMonLayer->pLayerDB->pFields[iField]
2144 365 : .nFieldSize == 0)
2145 270 : phMiraMonLayer->pLayerDB->pFields[iField]
2146 270 : .nFieldSize = 3;
2147 : }
2148 :
2149 : // Some exceptions for some fields:
2150 450 : if (EQUAL(
2151 : m_poFeatureDefn->GetFieldDefn(iField)->GetNameRef(),
2152 : "fontsize"))
2153 : {
2154 0 : phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize =
2155 : 11;
2156 0 : phMiraMonLayer->pLayerDB->pFields[iField]
2157 0 : .nNumberOfDecimals = 3;
2158 : }
2159 450 : else if (EQUAL(m_poFeatureDefn->GetFieldDefn(iField)
2160 : ->GetNameRef(),
2161 450 : "leading") ||
2162 450 : EQUAL(m_poFeatureDefn->GetFieldDefn(iField)
2163 : ->GetNameRef(),
2164 900 : "chrwidth") ||
2165 450 : EQUAL(m_poFeatureDefn->GetFieldDefn(iField)
2166 : ->GetNameRef(),
2167 : "chrspacing"))
2168 : {
2169 0 : phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize =
2170 : 8;
2171 0 : phMiraMonLayer->pLayerDB->pFields[iField]
2172 0 : .nNumberOfDecimals = 3;
2173 : }
2174 450 : else if (EQUAL(m_poFeatureDefn->GetFieldDefn(iField)
2175 : ->GetNameRef(),
2176 : "orientacio"))
2177 : {
2178 0 : phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize =
2179 : 7;
2180 0 : phMiraMonLayer->pLayerDB->pFields[iField]
2181 0 : .nNumberOfDecimals = 2;
2182 : }
2183 : }
2184 : else
2185 : {
2186 : // One more space for the "."
2187 24 : phMiraMonLayer->pLayerDB->pFields[iField].nFieldSize =
2188 48 : (unsigned int)(m_poFeatureDefn->GetFieldDefn(iField)
2189 24 : ->GetWidth() +
2190 : 1);
2191 : }
2192 : }
2193 :
2194 : // Recode from UTF-8 if necessary
2195 575 : if (phMiraMonLayer->nCharSet != MM_JOC_CARAC_UTF8_DBF)
2196 : {
2197 565 : char *pszString = CPLRecode(
2198 565 : m_poFeatureDefn->GetFieldDefn(iField)->GetNameRef(),
2199 : CPL_ENC_UTF8, CPL_ENC_ISO8859_1);
2200 565 : CPLStrlcpy(
2201 565 : phMiraMonLayer->pLayerDB->pFields[iField].pszFieldName,
2202 : pszString, MM_MAX_LON_FIELD_NAME_DBF);
2203 565 : CPLFree(pszString);
2204 : }
2205 : else
2206 : {
2207 10 : CPLStrlcpy(
2208 10 : phMiraMonLayer->pLayerDB->pFields[iField].pszFieldName,
2209 10 : m_poFeatureDefn->GetFieldDefn(iField)->GetNameRef(),
2210 : MM_MAX_LON_FIELD_NAME_DBF);
2211 : }
2212 :
2213 575 : if (m_poFeatureDefn->GetFieldDefn(iField)->GetAlternativeNameRef())
2214 : {
2215 575 : if (phMiraMonLayer->nCharSet != MM_JOC_CARAC_UTF8_DBF)
2216 : {
2217 : char *pszString =
2218 565 : CPLRecode(m_poFeatureDefn->GetFieldDefn(iField)
2219 : ->GetAlternativeNameRef(),
2220 : CPL_ENC_UTF8, CPL_ENC_ISO8859_1);
2221 565 : CPLStrlcpy(phMiraMonLayer->pLayerDB->pFields[iField]
2222 565 : .pszFieldDescription,
2223 : pszString, MM_MAX_BYTES_FIELD_DESC);
2224 565 : CPLFree(pszString);
2225 : }
2226 : else
2227 : {
2228 10 : CPLStrlcpy(phMiraMonLayer->pLayerDB->pFields[iField]
2229 10 : .pszFieldDescription,
2230 10 : m_poFeatureDefn->GetFieldDefn(iField)
2231 : ->GetAlternativeNameRef(),
2232 : MM_MAX_BYTES_FIELD_DESC);
2233 : }
2234 : }
2235 575 : phMiraMonLayer->pLayerDB->nNFields++;
2236 : }
2237 : }
2238 :
2239 107 : CPLDebugOnly("MiraMon", "Fields to MiraMon translated.");
2240 107 : return OGRERR_NONE;
2241 : }
2242 :
2243 : /****************************************************************************/
2244 : /* TranslateFieldsValuesToMM() */
2245 : /* */
2246 : /* Translate ogr Fields to a structure that MiraMon can understand */
2247 : /****************************************************************************/
2248 :
2249 207 : OGRErr OGRMiraMonLayer::TranslateFieldsValuesToMM(OGRFeature *poFeature)
2250 :
2251 : {
2252 207 : if (m_poFeatureDefn->GetFieldCount() == 0)
2253 : {
2254 : // MiraMon have private DataBase records
2255 0 : hMMFeature.nNumMRecords = 1;
2256 0 : return OGRERR_NONE;
2257 : }
2258 :
2259 : MM_EXT_DBF_N_MULTIPLE_RECORDS nIRecord;
2260 207 : MM_EXT_DBF_N_FIELDS nNumFields = m_poFeatureDefn->GetFieldCount();
2261 : MM_EXT_DBF_N_MULTIPLE_RECORDS nNumRecords, nRealNumRecords;
2262 207 : hMMFeature.nNumMRecords = 0;
2263 : #define MAX_SIZE_OF_FIELD_NUMBER_WITH_MINUS 22
2264 :
2265 1548 : for (MM_EXT_DBF_N_FIELDS iField = 0; iField < nNumFields; iField++)
2266 : {
2267 1341 : OGRFieldType eFType = m_poFeatureDefn->GetFieldDefn(iField)->GetType();
2268 : OGRFieldSubType eFSType =
2269 1341 : m_poFeatureDefn->GetFieldDefn(iField)->GetSubType();
2270 1341 : const char *pszRawValue = poFeature->GetFieldAsString(iField);
2271 :
2272 1341 : if (eFType == OFTStringList)
2273 : {
2274 20 : char **papszValues = poFeature->GetFieldAsStringList(iField);
2275 20 : nRealNumRecords = nNumRecords = CSLCount(papszValues);
2276 20 : if (nNumRecords == 0)
2277 0 : nNumRecords++;
2278 20 : hMMFeature.nNumMRecords =
2279 20 : max_function(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 1321 : 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 =
2353 21 : max_function(hMMFeature.nNumMRecords, nNumRecords);
2354 21 : if (MMResizeMiraMonRecord(
2355 : &hMMFeature.pRecords, &hMMFeature.nMaxMRecords,
2356 : hMMFeature.nNumMRecords, MM_INC_NUMBER_OF_RECORDS,
2357 21 : hMMFeature.nNumMRecords))
2358 0 : return OGRERR_NOT_ENOUGH_MEMORY;
2359 :
2360 : // It will contains the i-th element of the list.
2361 45 : for (nIRecord = 0; nIRecord < nRealNumRecords; nIRecord++)
2362 : {
2363 21 : if (MMResizeMiraMonFieldValue(
2364 24 : &(hMMFeature.pRecords[nIRecord].pField),
2365 24 : &hMMFeature.pRecords[nIRecord].nMaxField,
2366 24 : hMMFeature.pRecords[nIRecord].nNumField,
2367 : (nIRecord == 0)
2368 : ? MM_INC_NUMBER_OF_FIELDS
2369 3 : : hMMFeature.pRecords[nIRecord - 1].nMaxField,
2370 48 : hMMFeature.pRecords[nIRecord].nNumField))
2371 0 : return OGRERR_NOT_ENOUGH_MEMORY;
2372 :
2373 24 : if (nIRecord > 0)
2374 : {
2375 : // The number of fields of this new record is the same as the
2376 : // last one
2377 3 : hMMFeature.pRecords[nIRecord].nNumField =
2378 3 : hMMFeature.pRecords[nIRecord - 1].nNumField;
2379 : }
2380 :
2381 24 : if (eFSType == OFSTBoolean)
2382 : {
2383 2 : if (panValues[nIRecord] == 1)
2384 : {
2385 4 : if (MM_SecureCopyStringFieldValue(
2386 2 : &hMMFeature.pRecords[nIRecord]
2387 2 : .pField[iField]
2388 : .pDinValue,
2389 : "T",
2390 2 : &hMMFeature.pRecords[nIRecord]
2391 2 : .pField[iField]
2392 2 : .nNumDinValue))
2393 0 : return OGRERR_NOT_ENOUGH_MEMORY;
2394 : }
2395 : else
2396 : {
2397 0 : if (MM_SecureCopyStringFieldValue(
2398 0 : &hMMFeature.pRecords[nIRecord]
2399 0 : .pField[iField]
2400 : .pDinValue,
2401 : "F",
2402 0 : &hMMFeature.pRecords[nIRecord]
2403 0 : .pField[iField]
2404 0 : .nNumDinValue))
2405 0 : return OGRERR_NOT_ENOUGH_MEMORY;
2406 : }
2407 : }
2408 : else
2409 : {
2410 66 : if (MM_SecureCopyStringFieldValue(
2411 22 : &hMMFeature.pRecords[nIRecord]
2412 22 : .pField[iField]
2413 : .pDinValue,
2414 22 : CPLSPrintf("%d", panValues[nIRecord]),
2415 22 : &hMMFeature.pRecords[nIRecord]
2416 22 : .pField[iField]
2417 22 : .nNumDinValue))
2418 0 : return OGRERR_NOT_ENOUGH_MEMORY;
2419 : }
2420 :
2421 24 : hMMFeature.pRecords[nIRecord].pField[iField].bIsValid = 1;
2422 : }
2423 : }
2424 1300 : else if (eFType == OFTInteger64List)
2425 : {
2426 23 : int nCount = 0;
2427 : const GIntBig *panValues =
2428 23 : poFeature->GetFieldAsInteger64List(iField, &nCount);
2429 :
2430 23 : nRealNumRecords = nNumRecords = nCount;
2431 23 : if (nNumRecords == 0)
2432 0 : nNumRecords++;
2433 23 : hMMFeature.nNumMRecords =
2434 23 : max_function(hMMFeature.nNumMRecords, nNumRecords);
2435 23 : if (MMResizeMiraMonRecord(
2436 : &hMMFeature.pRecords, &hMMFeature.nMaxMRecords,
2437 : hMMFeature.nNumMRecords, MM_INC_NUMBER_OF_RECORDS,
2438 23 : hMMFeature.nNumMRecords))
2439 0 : return OGRERR_NOT_ENOUGH_MEMORY;
2440 :
2441 : // It will contains the i-th element of the list.
2442 51 : for (nIRecord = 0; nIRecord < nRealNumRecords; nIRecord++)
2443 : {
2444 23 : if (MMResizeMiraMonFieldValue(
2445 28 : &(hMMFeature.pRecords[nIRecord].pField),
2446 28 : &hMMFeature.pRecords[nIRecord].nMaxField,
2447 28 : hMMFeature.pRecords[nIRecord].nNumField,
2448 : (nIRecord == 0)
2449 : ? MM_INC_NUMBER_OF_FIELDS
2450 5 : : hMMFeature.pRecords[nIRecord - 1].nMaxField,
2451 56 : hMMFeature.pRecords[nIRecord].nNumField))
2452 0 : return OGRERR_NOT_ENOUGH_MEMORY;
2453 :
2454 28 : if (nIRecord > 0)
2455 : {
2456 : // The number of fields of this new record is the same as the
2457 : // last one
2458 5 : hMMFeature.pRecords[nIRecord].nNumField =
2459 5 : hMMFeature.pRecords[nIRecord - 1].nNumField;
2460 : }
2461 :
2462 28 : hMMFeature.pRecords[nIRecord].pField[iField].iValue =
2463 28 : panValues[nIRecord];
2464 :
2465 84 : if (MM_SecureCopyStringFieldValue(
2466 28 : &hMMFeature.pRecords[nIRecord].pField[iField].pDinValue,
2467 : CPLSPrintf("%" CPL_FRMT_GB_WITHOUT_PREFIX "d",
2468 28 : panValues[nIRecord]),
2469 28 : &hMMFeature.pRecords[nIRecord]
2470 28 : .pField[iField]
2471 28 : .nNumDinValue))
2472 0 : return OGRERR_NOT_ENOUGH_MEMORY;
2473 28 : hMMFeature.pRecords[nIRecord].pField[iField].bIsValid = 1;
2474 : }
2475 : }
2476 1277 : else if (eFType == OFTRealList)
2477 : {
2478 24 : int nCount = 0;
2479 : const double *padfRLValues =
2480 24 : poFeature->GetFieldAsDoubleList(iField, &nCount);
2481 : //char format[23];
2482 :
2483 24 : nRealNumRecords = nNumRecords = nCount;
2484 24 : if (nNumRecords == 0)
2485 0 : nNumRecords++;
2486 24 : hMMFeature.nNumMRecords =
2487 24 : max_function(hMMFeature.nNumMRecords, nNumRecords);
2488 24 : if (MMResizeMiraMonRecord(
2489 : &hMMFeature.pRecords, &hMMFeature.nMaxMRecords,
2490 : hMMFeature.nNumMRecords, MM_INC_NUMBER_OF_RECORDS,
2491 24 : hMMFeature.nNumMRecords))
2492 0 : return OGRERR_NOT_ENOUGH_MEMORY;
2493 :
2494 : // It will contains the i-th element of the list.
2495 76 : for (nIRecord = 0; nIRecord < nRealNumRecords; nIRecord++)
2496 : {
2497 24 : if (MMResizeMiraMonFieldValue(
2498 52 : &(hMMFeature.pRecords[nIRecord].pField),
2499 52 : &hMMFeature.pRecords[nIRecord].nMaxField,
2500 52 : hMMFeature.pRecords[nIRecord].nNumField,
2501 : (nIRecord == 0)
2502 : ? MM_INC_NUMBER_OF_FIELDS
2503 28 : : hMMFeature.pRecords[nIRecord - 1].nMaxField,
2504 104 : hMMFeature.pRecords[nIRecord].nNumField))
2505 0 : return OGRERR_NOT_ENOUGH_MEMORY;
2506 :
2507 52 : if (nIRecord > 0)
2508 : {
2509 : // The number of fields of this new record is the same as the
2510 : // last one
2511 28 : hMMFeature.pRecords[nIRecord].nNumField =
2512 28 : hMMFeature.pRecords[nIRecord - 1].nNumField;
2513 : }
2514 :
2515 : char szChain[MAX_SIZE_OF_FIELD_NUMBER_WITH_MINUS];
2516 52 : MM_SprintfDoubleSignifFigures(
2517 : szChain, sizeof(szChain),
2518 52 : phMiraMonLayer->pLayerDB->pFields[iField].nNumberOfDecimals,
2519 52 : padfRLValues[nIRecord]);
2520 :
2521 104 : if (MM_SecureCopyStringFieldValue(
2522 52 : &hMMFeature.pRecords[nIRecord].pField[iField].pDinValue,
2523 : szChain,
2524 52 : &hMMFeature.pRecords[nIRecord]
2525 52 : .pField[iField]
2526 52 : .nNumDinValue))
2527 0 : return OGRERR_NOT_ENOUGH_MEMORY;
2528 52 : hMMFeature.pRecords[nIRecord].pField[iField].bIsValid = 1;
2529 : }
2530 : }
2531 1253 : else if (eFType == OFTString)
2532 : {
2533 281 : hMMFeature.nNumMRecords = max_function(hMMFeature.nNumMRecords, 1);
2534 281 : hMMFeature.pRecords[0].nNumField = nNumFields;
2535 562 : if (MMResizeMiraMonFieldValue(&(hMMFeature.pRecords[0].pField),
2536 281 : &hMMFeature.pRecords[0].nMaxField,
2537 281 : hMMFeature.pRecords[0].nNumField,
2538 : MM_INC_NUMBER_OF_FIELDS,
2539 281 : hMMFeature.pRecords[0].nNumField))
2540 0 : return OGRERR_NOT_ENOUGH_MEMORY;
2541 :
2542 281 : if (MMIsEmptyString(pszRawValue))
2543 54 : hMMFeature.pRecords[0].pField[iField].bIsValid = 0;
2544 : {
2545 281 : if (phMiraMonLayer->nCharSet != MM_JOC_CARAC_UTF8_DBF)
2546 : {
2547 : // MiraMon encoding is ISO 8859-1 (Latin1) -> Recode from UTF-8
2548 : char *pszString =
2549 279 : CPLRecode(pszRawValue, CPL_ENC_UTF8, CPL_ENC_ISO8859_1);
2550 558 : if (MM_SecureCopyStringFieldValue(
2551 279 : &hMMFeature.pRecords[0].pField[iField].pDinValue,
2552 : pszString,
2553 279 : &hMMFeature.pRecords[0]
2554 279 : .pField[iField]
2555 279 : .nNumDinValue))
2556 : {
2557 0 : CPLFree(pszString);
2558 0 : return OGRERR_NOT_ENOUGH_MEMORY;
2559 : }
2560 279 : CPLFree(pszString);
2561 : }
2562 : else
2563 : {
2564 4 : if (MM_SecureCopyStringFieldValue(
2565 2 : &hMMFeature.pRecords[0].pField[iField].pDinValue,
2566 : pszRawValue,
2567 2 : &hMMFeature.pRecords[0]
2568 2 : .pField[iField]
2569 2 : .nNumDinValue))
2570 : {
2571 0 : return OGRERR_NOT_ENOUGH_MEMORY;
2572 : }
2573 : }
2574 : }
2575 281 : hMMFeature.pRecords[0].pField[iField].bIsValid = 1;
2576 : }
2577 972 : else if (eFType == OFTDate)
2578 : {
2579 : char szDate[15];
2580 :
2581 123 : hMMFeature.nNumMRecords = max_function(hMMFeature.nNumMRecords, 1);
2582 123 : hMMFeature.pRecords[0].nNumField = nNumFields;
2583 246 : if (MMResizeMiraMonFieldValue(&(hMMFeature.pRecords[0].pField),
2584 123 : &hMMFeature.pRecords[0].nMaxField,
2585 123 : hMMFeature.pRecords[0].nNumField,
2586 : MM_INC_NUMBER_OF_FIELDS,
2587 123 : hMMFeature.pRecords[0].nNumField))
2588 0 : return OGRERR_NOT_ENOUGH_MEMORY;
2589 :
2590 123 : if (MMIsEmptyString(pszRawValue))
2591 17 : hMMFeature.pRecords[0].pField[iField].bIsValid = 0;
2592 : else
2593 : {
2594 106 : const OGRField *poField = poFeature->GetRawFieldRef(iField);
2595 106 : if (poField->Date.Year >= 0)
2596 106 : snprintf(szDate, sizeof(szDate), "%04d%02d%02d",
2597 106 : poField->Date.Year, poField->Date.Month,
2598 106 : poField->Date.Day);
2599 : else
2600 0 : snprintf(szDate, sizeof(szDate), "%04d%02d%02d", 0, 0, 0);
2601 :
2602 212 : if (MM_SecureCopyStringFieldValue(
2603 106 : &hMMFeature.pRecords[0].pField[iField].pDinValue,
2604 : szDate,
2605 106 : &hMMFeature.pRecords[0].pField[iField].nNumDinValue))
2606 0 : return OGRERR_NOT_ENOUGH_MEMORY;
2607 106 : hMMFeature.pRecords[0].pField[iField].bIsValid = 1;
2608 : }
2609 : }
2610 849 : else if (eFType == OFTTime || eFType == OFTDateTime)
2611 : {
2612 73 : hMMFeature.nNumMRecords = max_function(hMMFeature.nNumMRecords, 1);
2613 73 : hMMFeature.pRecords[0].nNumField = nNumFields;
2614 146 : if (MMResizeMiraMonFieldValue(&(hMMFeature.pRecords[0].pField),
2615 73 : &hMMFeature.pRecords[0].nMaxField,
2616 73 : hMMFeature.pRecords[0].nNumField,
2617 : MM_INC_NUMBER_OF_FIELDS,
2618 73 : hMMFeature.pRecords[0].nNumField))
2619 0 : return OGRERR_NOT_ENOUGH_MEMORY;
2620 :
2621 73 : if (MMIsEmptyString(pszRawValue))
2622 16 : hMMFeature.pRecords[0].pField[iField].bIsValid = 0;
2623 : else
2624 : {
2625 : // MiraMon encoding is ISO 8859-1 (Latin1) -> Recode from UTF-8
2626 114 : if (MM_SecureCopyStringFieldValue(
2627 57 : &hMMFeature.pRecords[0].pField[iField].pDinValue,
2628 : pszRawValue,
2629 57 : &hMMFeature.pRecords[0].pField[iField].nNumDinValue))
2630 0 : return OGRERR_NOT_ENOUGH_MEMORY;
2631 :
2632 57 : hMMFeature.pRecords[0].pField[iField].bIsValid = 1;
2633 : }
2634 : }
2635 776 : else if (eFType == OFTInteger)
2636 : {
2637 401 : hMMFeature.nNumMRecords = max_function(hMMFeature.nNumMRecords, 1);
2638 401 : hMMFeature.pRecords[0].nNumField = nNumFields;
2639 802 : if (MMResizeMiraMonFieldValue(&(hMMFeature.pRecords[0].pField),
2640 401 : &hMMFeature.pRecords[0].nMaxField,
2641 401 : hMMFeature.pRecords[0].nNumField,
2642 : MM_INC_NUMBER_OF_FIELDS,
2643 401 : hMMFeature.pRecords[0].nNumField))
2644 0 : return OGRERR_NOT_ENOUGH_MEMORY;
2645 :
2646 401 : if (MMIsEmptyString(pszRawValue))
2647 16 : hMMFeature.pRecords[0].pField[iField].bIsValid = 0;
2648 : else
2649 : {
2650 385 : if (eFSType == OFSTBoolean)
2651 : {
2652 98 : if (!strcmp(pszRawValue, "1"))
2653 : {
2654 84 : if (MM_SecureCopyStringFieldValue(
2655 42 : &hMMFeature.pRecords[0]
2656 42 : .pField[iField]
2657 : .pDinValue,
2658 : "T",
2659 42 : &hMMFeature.pRecords[0]
2660 42 : .pField[iField]
2661 42 : .nNumDinValue))
2662 0 : return OGRERR_NOT_ENOUGH_MEMORY;
2663 : }
2664 : else
2665 : {
2666 112 : if (MM_SecureCopyStringFieldValue(
2667 56 : &hMMFeature.pRecords[0]
2668 56 : .pField[iField]
2669 : .pDinValue,
2670 : "F",
2671 56 : &hMMFeature.pRecords[0]
2672 56 : .pField[iField]
2673 56 : .nNumDinValue))
2674 0 : return OGRERR_NOT_ENOUGH_MEMORY;
2675 : }
2676 : }
2677 : else
2678 : {
2679 574 : if (MM_SecureCopyStringFieldValue(
2680 287 : &hMMFeature.pRecords[0].pField[iField].pDinValue,
2681 : pszRawValue,
2682 287 : &hMMFeature.pRecords[0]
2683 287 : .pField[iField]
2684 287 : .nNumDinValue))
2685 0 : return OGRERR_NOT_ENOUGH_MEMORY;
2686 : }
2687 385 : hMMFeature.pRecords[0].pField[iField].bIsValid = 1;
2688 : }
2689 : }
2690 375 : else if (eFType == OFTInteger64)
2691 : {
2692 178 : hMMFeature.nNumMRecords = max_function(hMMFeature.nNumMRecords, 1);
2693 178 : hMMFeature.pRecords[0].nNumField = nNumFields;
2694 356 : if (MMResizeMiraMonFieldValue(&(hMMFeature.pRecords[0].pField),
2695 178 : &hMMFeature.pRecords[0].nMaxField,
2696 178 : hMMFeature.pRecords[0].nNumField,
2697 : MM_INC_NUMBER_OF_FIELDS,
2698 178 : hMMFeature.pRecords[0].nNumField))
2699 0 : return OGRERR_NOT_ENOUGH_MEMORY;
2700 :
2701 178 : if (MMIsEmptyString(pszRawValue))
2702 0 : hMMFeature.pRecords[0].pField[iField].bIsValid = 0;
2703 : else
2704 : {
2705 356 : hMMFeature.pRecords[0].pField[iField].iValue =
2706 178 : poFeature->GetFieldAsInteger64(iField);
2707 :
2708 356 : if (MM_SecureCopyStringFieldValue(
2709 178 : &hMMFeature.pRecords[0].pField[iField].pDinValue,
2710 : pszRawValue,
2711 178 : &hMMFeature.pRecords[0].pField[iField].nNumDinValue))
2712 0 : return OGRERR_NOT_ENOUGH_MEMORY;
2713 178 : hMMFeature.pRecords[0].pField[iField].bIsValid = 1;
2714 : }
2715 : }
2716 197 : else if (eFType == OFTReal)
2717 : {
2718 197 : hMMFeature.nNumMRecords = max_function(hMMFeature.nNumMRecords, 1);
2719 197 : hMMFeature.pRecords[0].nNumField = nNumFields;
2720 394 : if (MMResizeMiraMonFieldValue(&(hMMFeature.pRecords[0].pField),
2721 197 : &hMMFeature.pRecords[0].nMaxField,
2722 197 : hMMFeature.pRecords[0].nNumField,
2723 : MM_INC_NUMBER_OF_FIELDS,
2724 197 : hMMFeature.pRecords[0].nNumField))
2725 0 : return OGRERR_NOT_ENOUGH_MEMORY;
2726 :
2727 197 : if (MMIsEmptyString(pszRawValue))
2728 16 : hMMFeature.pRecords[0].pField[iField].bIsValid = 0;
2729 : else
2730 : {
2731 : char szChain[MAX_SIZE_OF_FIELD_NUMBER_WITH_MINUS];
2732 181 : MM_SprintfDoubleSignifFigures(
2733 : szChain, sizeof(szChain),
2734 181 : phMiraMonLayer->pLayerDB->pFields[iField].nNumberOfDecimals,
2735 : poFeature->GetFieldAsDouble(iField));
2736 :
2737 362 : if (MM_SecureCopyStringFieldValue(
2738 181 : &hMMFeature.pRecords[0].pField[iField].pDinValue,
2739 : szChain,
2740 181 : &hMMFeature.pRecords[0].pField[iField].nNumDinValue))
2741 0 : return OGRERR_NOT_ENOUGH_MEMORY;
2742 181 : hMMFeature.pRecords[0].pField[iField].bIsValid = 1;
2743 : }
2744 : }
2745 : else
2746 : {
2747 0 : CPLError(CE_Warning, CPLE_NotSupported,
2748 : "MiraMon: Field type %d not processed by MiraMon\n",
2749 : eFType);
2750 0 : hMMFeature.pRecords[0].pField[iField].bIsValid = 0;
2751 : }
2752 : }
2753 :
2754 207 : return OGRERR_NONE;
2755 : }
2756 :
2757 : /****************************************************************************/
2758 : /* GetLayerDefn() */
2759 : /* */
2760 : /****************************************************************************/
2761 3783 : OGRFeatureDefn *OGRMiraMonLayer::GetLayerDefn()
2762 : {
2763 3783 : return m_poFeatureDefn;
2764 : }
2765 :
2766 : /****************************************************************************/
2767 : /* IGetExtent() */
2768 : /* */
2769 : /* Fetch extent of the data currently stored in the dataset. */
2770 : /* The bForce flag has no effect on SHO files since that value */
2771 : /* is always in the header. */
2772 : /****************************************************************************/
2773 :
2774 33 : OGRErr OGRMiraMonLayer::IGetExtent(int /* iGeomField*/, OGREnvelope *psExtent,
2775 : bool bForce)
2776 :
2777 : {
2778 33 : if (phMiraMonLayer)
2779 : {
2780 33 : if (phMiraMonLayer->bIsDBF)
2781 0 : return OGRERR_FAILURE;
2782 :
2783 : // For polygons we need another polygon apart from the universal one
2784 : // to have a valid extension
2785 33 : if (phMiraMonLayer->bIsPolygon &&
2786 13 : phMiraMonLayer->TopHeader.nElemCount < 1)
2787 0 : return OGRERR_FAILURE;
2788 :
2789 33 : if (phMiraMonLayer->TopHeader.nElemCount < 1)
2790 4 : return OGRERR_FAILURE;
2791 :
2792 29 : psExtent->MinX = phMiraMonLayer->TopHeader.hBB.dfMinX;
2793 29 : psExtent->MaxX = phMiraMonLayer->TopHeader.hBB.dfMaxX;
2794 29 : psExtent->MinY = phMiraMonLayer->TopHeader.hBB.dfMinY;
2795 29 : psExtent->MaxY = phMiraMonLayer->TopHeader.hBB.dfMaxY;
2796 : }
2797 : else
2798 : {
2799 0 : if (!bForce)
2800 0 : return OGRERR_FAILURE;
2801 : }
2802 :
2803 29 : return OGRERR_NONE;
2804 : }
2805 :
2806 : /****************************************************************************/
2807 : /* TestCapability() */
2808 : /****************************************************************************/
2809 :
2810 520 : int OGRMiraMonLayer::TestCapability(const char *pszCap)
2811 :
2812 : {
2813 520 : if (EQUAL(pszCap, OLCRandomRead))
2814 0 : return TRUE;
2815 :
2816 520 : if (EQUAL(pszCap, OLCSequentialWrite))
2817 26 : return m_bUpdate;
2818 :
2819 494 : if (EQUAL(pszCap, OLCFastFeatureCount))
2820 0 : return !m_poFilterGeom && !m_poAttrQuery;
2821 :
2822 494 : if (EQUAL(pszCap, OLCFastGetExtent))
2823 13 : return TRUE;
2824 :
2825 481 : if (EQUAL(pszCap, OLCCreateField))
2826 36 : return m_bUpdate;
2827 :
2828 445 : if (EQUAL(pszCap, OLCZGeometries))
2829 30 : return TRUE;
2830 :
2831 415 : if (EQUAL(pszCap, OLCStringsAsUTF8))
2832 98 : return TRUE;
2833 :
2834 317 : return FALSE;
2835 : }
2836 :
2837 : /****************************************************************************/
2838 : /* CreateField() */
2839 : /****************************************************************************/
2840 :
2841 377 : OGRErr OGRMiraMonLayer::CreateField(const OGRFieldDefn *poField, int bApproxOK)
2842 :
2843 : {
2844 377 : if (!m_bUpdate)
2845 : {
2846 0 : CPLError(CE_Failure, CPLE_NoWriteAccess,
2847 : "Cannot create fields on a read-only dataset.");
2848 0 : return OGRERR_FAILURE;
2849 : }
2850 :
2851 377 : if (phMiraMonLayer && phMiraMonLayer->TopHeader.nElemCount > 0)
2852 : {
2853 1 : CPLError(CE_Failure, CPLE_NoWriteAccess,
2854 : "Cannot create fields to a layer with "
2855 : "already existing features in it.");
2856 1 : return OGRERR_FAILURE;
2857 : }
2858 :
2859 376 : switch (poField->GetType())
2860 : {
2861 359 : case OFTInteger:
2862 : case OFTIntegerList:
2863 : case OFTInteger64:
2864 : case OFTInteger64List:
2865 : case OFTReal:
2866 : case OFTRealList:
2867 : case OFTString:
2868 : case OFTStringList:
2869 : case OFTDate:
2870 359 : m_poFeatureDefn->AddFieldDefn(poField);
2871 359 : return OGRERR_NONE;
2872 17 : default:
2873 17 : if (!bApproxOK)
2874 : {
2875 0 : CPLError(CE_Failure, CPLE_AppDefined,
2876 : "Field %s is of an unsupported type: %s.",
2877 : poField->GetNameRef(),
2878 : poField->GetFieldTypeName(poField->GetType()));
2879 0 : return OGRERR_FAILURE;
2880 : }
2881 : else
2882 : {
2883 17 : OGRFieldDefn oModDef(poField);
2884 17 : oModDef.SetType(OFTString);
2885 17 : m_poFeatureDefn->AddFieldDefn(poField);
2886 17 : return OGRERR_NONE;
2887 : }
2888 : }
2889 : }
2890 :
2891 : /************************************************************************/
2892 : /* AddToFileList() */
2893 : /************************************************************************/
2894 :
2895 10 : void OGRMiraMonLayer::AddToFileList(CPLStringList &oFileList)
2896 : {
2897 10 : if (!phMiraMonLayer)
2898 0 : return;
2899 :
2900 : char szAuxFile[MM_CPL_PATH_BUF_SIZE];
2901 :
2902 : oFileList.AddStringDirectly(
2903 10 : VSIGetCanonicalFilename(phMiraMonLayer->pszSrcLayerName));
2904 : char *pszMMExt =
2905 10 : CPLStrdup(CPLGetExtensionSafe(phMiraMonLayer->pszSrcLayerName).c_str());
2906 :
2907 10 : if (phMiraMonLayer->bIsPoint)
2908 : {
2909 : // As it's explicit on documentation a point has also two more files:
2910 :
2911 : // FILE_NAME_WITHOUT_EXTENSION.pnt --> FILE_NAME_WITHOUT_EXTENSION + T.rel
2912 3 : CPLStrlcpy(szAuxFile,
2913 6 : CPLGetBasenameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
2914 : MM_CPL_PATH_BUF_SIZE);
2915 3 : CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "T.rel" : "T.REL",
2916 : MM_CPL_PATH_BUF_SIZE);
2917 : oFileList.AddStringDirectly(VSIGetCanonicalFilename(
2918 6 : CPLFormFilenameSafe(
2919 6 : CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
2920 : szAuxFile, nullptr)
2921 3 : .c_str()));
2922 :
2923 : // FILE_NAME_WITHOUT_EXTENSION.pnt --> FILE_NAME_WITHOUT_EXTENSION + T.dbf
2924 3 : CPLStrlcpy(szAuxFile,
2925 6 : CPLGetBasenameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
2926 : MM_CPL_PATH_BUF_SIZE);
2927 3 : CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "T.dbf" : "T.DBF",
2928 : MM_CPL_PATH_BUF_SIZE);
2929 : oFileList.AddStringDirectly(VSIGetCanonicalFilename(
2930 6 : CPLFormFilenameSafe(
2931 6 : CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
2932 : szAuxFile, nullptr)
2933 3 : .c_str()));
2934 : }
2935 7 : else if (phMiraMonLayer->bIsArc && !phMiraMonLayer->bIsPolygon)
2936 : {
2937 : // As it's explicit on documentation a point has also five more files:
2938 :
2939 : // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + A.rel
2940 3 : CPLStrlcpy(szAuxFile,
2941 6 : CPLGetBasenameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
2942 : MM_CPL_PATH_BUF_SIZE);
2943 3 : CPLStrlcat(szAuxFile, (pszMMExt[0] == 'a') ? "A.rel" : "A.REL",
2944 : MM_CPL_PATH_BUF_SIZE);
2945 : oFileList.AddStringDirectly(VSIGetCanonicalFilename(
2946 6 : CPLFormFilenameSafe(
2947 6 : CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
2948 : szAuxFile, nullptr)
2949 3 : .c_str()));
2950 :
2951 : // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + A.dbf
2952 3 : CPLStrlcpy(szAuxFile,
2953 6 : CPLGetBasenameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
2954 : MM_CPL_PATH_BUF_SIZE);
2955 3 : CPLStrlcat(szAuxFile, (pszMMExt[0] == 'a') ? "A.dbf" : "A.DBF",
2956 : MM_CPL_PATH_BUF_SIZE);
2957 : oFileList.AddStringDirectly(VSIGetCanonicalFilename(
2958 6 : CPLFormFilenameSafe(
2959 6 : CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
2960 : szAuxFile, nullptr)
2961 3 : .c_str()));
2962 :
2963 : // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + .nod
2964 3 : CPLStrlcpy(szAuxFile,
2965 6 : CPLGetBasenameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
2966 : MM_CPL_PATH_BUF_SIZE);
2967 3 : CPLStrlcat(szAuxFile, (pszMMExt[0] == 'a') ? ".nod" : ".NOD",
2968 : MM_CPL_PATH_BUF_SIZE);
2969 : oFileList.AddStringDirectly(VSIGetCanonicalFilename(
2970 6 : CPLFormFilenameSafe(
2971 6 : CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
2972 : szAuxFile, nullptr)
2973 3 : .c_str()));
2974 :
2975 : // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + N.rel
2976 3 : CPLStrlcpy(szAuxFile,
2977 6 : CPLGetBasenameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
2978 : MM_CPL_PATH_BUF_SIZE);
2979 3 : CPLStrlcat(szAuxFile, (pszMMExt[0] == 'a') ? "N.rel" : "N.REL",
2980 : MM_CPL_PATH_BUF_SIZE);
2981 : oFileList.AddStringDirectly(VSIGetCanonicalFilename(
2982 6 : CPLFormFilenameSafe(
2983 6 : CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
2984 : szAuxFile, nullptr)
2985 3 : .c_str()));
2986 :
2987 : // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + N.dbf
2988 3 : CPLStrlcpy(szAuxFile,
2989 6 : CPLGetBasenameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
2990 : MM_CPL_PATH_BUF_SIZE);
2991 3 : CPLStrlcat(szAuxFile, (pszMMExt[0] == 'a') ? "N.dbf" : "N.DBF",
2992 : MM_CPL_PATH_BUF_SIZE);
2993 3 : oFileList.AddStringDirectly(VSIGetCanonicalFilename(
2994 6 : CPLFormFilenameSafe(
2995 6 : CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
2996 : szAuxFile, nullptr)
2997 3 : .c_str()));
2998 : }
2999 4 : else if (phMiraMonLayer->bIsPolygon)
3000 : {
3001 : // As it's explicit on documentation a point has also eight more files:
3002 : char szArcFileName[MM_CPL_PATH_BUF_SIZE];
3003 :
3004 : // FILE_NAME_WITHOUT_EXTENSION.pol --> FILE_NAME_WITHOUT_EXTENSION + P.rel
3005 4 : CPLStrlcpy(szAuxFile,
3006 8 : CPLGetBasenameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
3007 : MM_CPL_PATH_BUF_SIZE);
3008 4 : CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "P.rel" : "P.REL",
3009 : MM_CPL_PATH_BUF_SIZE);
3010 : oFileList.AddStringDirectly(VSIGetCanonicalFilename(
3011 8 : CPLFormFilenameSafe(
3012 8 : CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
3013 : szAuxFile, nullptr)
3014 4 : .c_str()));
3015 :
3016 : // The name of the arc is in THIS metadata file
3017 4 : char *pszArcLayerName = MMReturnValueFromSectionINIFile(
3018 8 : CPLFormFilenameSafe(
3019 8 : CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
3020 : szAuxFile, nullptr)
3021 : .c_str(),
3022 : SECTION_OVVW_ASPECTES_TECNICS, KEY_ArcSource);
3023 4 : if (!pszArcLayerName)
3024 : {
3025 0 : CPLFree(pszMMExt);
3026 0 : return; //Some files are missing
3027 : }
3028 4 : CPLStrlcpy(szArcFileName, pszArcLayerName, MM_CPL_PATH_BUF_SIZE);
3029 :
3030 4 : MM_RemoveInitial_and_FinalQuotationMarks(szArcFileName);
3031 :
3032 : // If extension is not specified ".arc" will be used
3033 4 : if (MMIsEmptyString(CPLGetExtensionSafe(pszArcLayerName).c_str()))
3034 0 : CPLStrlcat(szArcFileName, (pszMMExt[0] == 'p') ? ".arc" : ".ARC",
3035 : MM_CPL_PATH_BUF_SIZE);
3036 :
3037 4 : CPLFree(pszArcLayerName);
3038 :
3039 : const std::string osCompleteArcFileName = CPLFormFilenameSafe(
3040 4 : CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
3041 8 : szArcFileName, nullptr);
3042 :
3043 : // The arc that has the coordinates of the polygon
3044 : oFileList.AddStringDirectly(
3045 4 : VSIGetCanonicalFilename(osCompleteArcFileName.c_str()));
3046 :
3047 : // FILE_NAME_WITHOUT_EXTENSION.pol --> FILE_NAME_WITHOUT_EXTENSION + P.dbf
3048 4 : CPLStrlcpy(szAuxFile,
3049 8 : CPLGetBasenameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
3050 : MM_CPL_PATH_BUF_SIZE);
3051 4 : CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "P.dbf" : "P.DBF",
3052 : MM_CPL_PATH_BUF_SIZE);
3053 : oFileList.AddStringDirectly(VSIGetCanonicalFilename(
3054 8 : CPLFormFilenameSafe(
3055 8 : CPLGetDirnameSafe(phMiraMonLayer->pszSrcLayerName).c_str(),
3056 : szAuxFile, nullptr)
3057 4 : .c_str()));
3058 :
3059 : // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + A.rel
3060 : const std::string osBaseArcName =
3061 4 : CPLGetBasenameSafe(osCompleteArcFileName.c_str());
3062 4 : CPLStrlcpy(szAuxFile, osBaseArcName.c_str(), MM_CPL_PATH_BUF_SIZE);
3063 4 : CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "A.rel" : "A.REL",
3064 : MM_CPL_PATH_BUF_SIZE);
3065 : oFileList.AddStringDirectly(VSIGetCanonicalFilename(
3066 8 : CPLFormFilenameSafe(
3067 8 : CPLGetDirnameSafe(osCompleteArcFileName.c_str()).c_str(),
3068 : szAuxFile, nullptr)
3069 4 : .c_str()));
3070 :
3071 : // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + A.dbf
3072 4 : CPLStrlcpy(szAuxFile, osBaseArcName.c_str(), MM_CPL_PATH_BUF_SIZE);
3073 4 : CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "A.dbf" : "A.DBF",
3074 : MM_CPL_PATH_BUF_SIZE);
3075 : oFileList.AddStringDirectly(VSIGetCanonicalFilename(
3076 8 : CPLFormFilenameSafe(
3077 8 : CPLGetDirnameSafe(osCompleteArcFileName.c_str()).c_str(),
3078 : szAuxFile, nullptr)
3079 4 : .c_str()));
3080 :
3081 : // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + .nod
3082 4 : CPLStrlcpy(szAuxFile, osBaseArcName.c_str(), MM_CPL_PATH_BUF_SIZE);
3083 4 : CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? ".nod" : ".NOD",
3084 : MM_CPL_PATH_BUF_SIZE);
3085 : oFileList.AddStringDirectly(VSIGetCanonicalFilename(
3086 8 : CPLFormFilenameSafe(
3087 8 : CPLGetDirnameSafe(osCompleteArcFileName.c_str()).c_str(),
3088 : szAuxFile, nullptr)
3089 4 : .c_str()));
3090 :
3091 : // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + N.rel
3092 4 : CPLStrlcpy(szAuxFile, osBaseArcName.c_str(), MM_CPL_PATH_BUF_SIZE);
3093 4 : CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "N.rel" : "N.REL",
3094 : MM_CPL_PATH_BUF_SIZE);
3095 : oFileList.AddStringDirectly(VSIGetCanonicalFilename(
3096 8 : CPLFormFilenameSafe(
3097 8 : CPLGetDirnameSafe(osCompleteArcFileName.c_str()).c_str(),
3098 : szAuxFile, nullptr)
3099 4 : .c_str()));
3100 :
3101 : // FILE_NAME_WITHOUT_EXTENSION.arc --> FILE_NAME_WITHOUT_EXTENSION + N.dbf
3102 4 : CPLStrlcpy(szAuxFile, osBaseArcName.c_str(), MM_CPL_PATH_BUF_SIZE);
3103 4 : CPLStrlcat(szAuxFile, (pszMMExt[0] == 'p') ? "N.dbf" : "N.DBF",
3104 : MM_CPL_PATH_BUF_SIZE);
3105 : oFileList.AddStringDirectly(VSIGetCanonicalFilename(
3106 8 : CPLFormFilenameSafe(
3107 8 : CPLGetDirnameSafe(osCompleteArcFileName.c_str()).c_str(),
3108 : szAuxFile, nullptr)
3109 4 : .c_str()));
3110 : }
3111 10 : CPLFree(pszMMExt);
3112 : }
|