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