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