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