Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: OpenGIS Simple Features Reference Implementation
4 : * Purpose: C MiraMon code adapted to be used in GDAL
5 : * Author: Abel Pau, a.pau@creaf.uab.cat, based on the MiraMon codes,
6 : * mainly written by Xavier Pons, Joan Maso (correctly written
7 : * "Mas0xF3"), Abel Pau, Nuria Julia (N0xFAria Juli0xE0),
8 : * Xavier Calaf, Lluis (Llu0xEDs) Pesquer and Alaitz Zabala, from
9 : * CREAF and Universitat Autonoma (Aut0xF2noma) de Barcelona.
10 : * For a complete list of contributors:
11 : * https://www.miramon.cat/eng/QuiSom.htm
12 : ******************************************************************************
13 : * Copyright (c) 2024, Xavier Pons
14 : *
15 : * SPDX-License-Identifier: MIT
16 : ****************************************************************************/
17 :
18 : #include "ogr_api.h" // For CPL_C_START
19 : #include "mm_gdal_functions.h" // For CPLStrlcpy()
20 : #ifdef EMBED_RESOURCE_FILES
21 : #include "embedded_resources.h"
22 : #endif
23 :
24 : CPL_C_START // Necessary for compiling in GDAL project
25 : #include "cpl_string.h" // For CPL_ENC_UTF8
26 :
27 : const char *MM_pszLogFilename = nullptr;
28 :
29 : static const char MM_EmptyString[] = {""};
30 : #define MM_SetEndOfString (*MM_EmptyString)
31 :
32 1538 : CPL_DLL void fclose_and_nullify(VSILFILE **pFunc)
33 : {
34 1538 : if (!pFunc || !(*pFunc))
35 359 : return;
36 1179 : VSIFCloseL(*pFunc);
37 1179 : *pFunc = nullptr;
38 : }
39 :
40 : // CREATING AN EXTENDED MIRAMON DBF
41 4264 : CPL_DLL void MM_InitializeField(struct MM_FIELD *pField)
42 : {
43 4264 : memset(pField, '\0', sizeof(*pField));
44 4264 : pField->FieldType = 'C';
45 4264 : pField->GeoTopoTypeField = MM_NO_ES_CAMP_GEOTOPO;
46 4264 : }
47 :
48 : #define MM_ACCEPTABLE_NUMBER_OF_FIELDS 20000
49 :
50 339 : CPL_DLL struct MM_FIELD *MM_CreateAllFields(MM_EXT_DBF_N_FIELDS nFields)
51 : {
52 : struct MM_FIELD *camp;
53 : MM_EXT_DBF_N_FIELDS i;
54 :
55 : // MiraMon could accept a number of fields 13.4 million
56 : // but GDAL prefers to limit that to 20.000 to avoid
57 : // too large memory allocation attempts with corrupted datasets
58 339 : if (nFields > MM_ACCEPTABLE_NUMBER_OF_FIELDS)
59 : {
60 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
61 : "More than 20000 fields not accepted");
62 0 : return nullptr;
63 : }
64 :
65 : #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
66 339 : if (nFields >= UINT32_MAX / sizeof(*camp))
67 0 : return nullptr;
68 : #else
69 : if (nFields >= (1000U * 1000 * 1000) / sizeof(*camp))
70 : return nullptr;
71 : #endif
72 :
73 339 : if ((camp = VSICalloc(nFields, sizeof(*camp))) == nullptr)
74 0 : return nullptr;
75 :
76 2791 : for (i = 0; i < nFields; i++)
77 2452 : MM_InitializeField(camp + i);
78 339 : return camp;
79 : }
80 :
81 194 : static struct MM_DATA_BASE_XP *MM_CreateEmptyHeader(MM_EXT_DBF_N_FIELDS nFields)
82 : {
83 : struct MM_DATA_BASE_XP *data_base_XP;
84 :
85 194 : if ((data_base_XP = (struct MM_DATA_BASE_XP *)VSICalloc(
86 : 1, sizeof(struct MM_DATA_BASE_XP))) == nullptr)
87 0 : return nullptr;
88 :
89 194 : if (nFields == 0)
90 : {
91 : ;
92 : }
93 : else
94 : {
95 194 : data_base_XP->pField = (struct MM_FIELD *)MM_CreateAllFields(nFields);
96 194 : if (!data_base_XP->pField)
97 : {
98 0 : VSIFree(data_base_XP);
99 0 : return nullptr;
100 : }
101 : }
102 194 : data_base_XP->nFields = nFields;
103 194 : return data_base_XP;
104 : }
105 :
106 194 : CPL_DLL struct MM_DATA_BASE_XP *MM_CreateDBFHeader(MM_EXT_DBF_N_FIELDS n_camps,
107 : MM_BYTE charset)
108 : {
109 : struct MM_DATA_BASE_XP *bd_xp;
110 : struct MM_FIELD *camp;
111 : MM_EXT_DBF_N_FIELDS i;
112 :
113 194 : if (nullptr == (bd_xp = MM_CreateEmptyHeader(n_camps)))
114 0 : return nullptr;
115 :
116 194 : bd_xp->CharSet = charset;
117 :
118 194 : strcpy(bd_xp->ReadingMode, "a+b");
119 :
120 194 : bd_xp->IdGraficField = n_camps;
121 194 : bd_xp->IdEntityField = MM_MAX_EXT_DBF_N_FIELDS_TYPE;
122 194 : bd_xp->dbf_version = (MM_BYTE)((n_camps > MM_MAX_N_CAMPS_DBF_CLASSICA)
123 : ? MM_MARCA_VERSIO_1_DBF_ESTESA
124 : : MM_MARCA_DBASE4);
125 :
126 1430 : for (i = 0, camp = bd_xp->pField; i < n_camps; i++, camp++)
127 : {
128 1236 : MM_InitializeField(camp);
129 1236 : if (i < 99999)
130 1236 : snprintf(camp->FieldName, sizeof(camp->FieldName), "CAMP%05u",
131 1236 : (unsigned)(i + 1));
132 : else
133 0 : snprintf(camp->FieldName, sizeof(camp->FieldName), "CM%u",
134 0 : (unsigned)(i + 1));
135 1236 : camp->FieldType = 'C';
136 1236 : camp->DecimalsIfFloat = 0;
137 1236 : camp->BytesPerField = 50;
138 : }
139 194 : return bd_xp;
140 : }
141 :
142 1236 : static MM_BYTE MM_GetDefaultDesiredDBFFieldWidth(const struct MM_FIELD *camp)
143 : {
144 : size_t a, b, c, d, e;
145 :
146 1236 : b = strlen(camp->FieldName);
147 1236 : c = strlen(camp->FieldDescription[0]);
148 :
149 1236 : if (camp->FieldType == 'D')
150 : {
151 68 : d = (b > c ? b : c);
152 68 : a = (size_t)camp->BytesPerField + 2;
153 68 : return (MM_BYTE)(a > d ? a : d);
154 : }
155 1168 : a = camp->BytesPerField;
156 1168 : d = (unsigned int)(b > c ? b : c);
157 1168 : e = (a > d ? a : d);
158 1168 : return (MM_BYTE)(e < 80 ? e : 80);
159 : }
160 :
161 9122 : static MM_BOOLEAN MM_is_field_name_lowercase(const char *szChain)
162 : {
163 : const char *p;
164 :
165 56634 : for (p = szChain; *p; p++)
166 : {
167 50839 : if ((*p >= 'a' && *p <= 'z'))
168 3327 : return TRUE;
169 : }
170 5795 : return FALSE;
171 : }
172 :
173 : static MM_BOOLEAN
174 9154 : MM_Is_classical_DBF_field_name_or_lowercase(const char *szChain)
175 : {
176 : const char *p;
177 :
178 77114 : for (p = szChain; *p; p++)
179 : {
180 67992 : if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') ||
181 6335 : (*p >= '0' && *p <= '9') || *p == '_')
182 : ;
183 : else
184 32 : return FALSE;
185 : }
186 9122 : if (szChain[0] == '_')
187 0 : return FALSE;
188 9122 : return TRUE;
189 : }
190 :
191 : static MM_BOOLEAN
192 81935 : MM_Is_character_valid_for_extended_DBF_field_name(int valor,
193 : int *valor_substitut)
194 : {
195 81935 : if (valor_substitut)
196 : {
197 0 : switch (valor)
198 : {
199 0 : case 32:
200 0 : *valor_substitut = '_';
201 0 : return FALSE;
202 0 : case 91:
203 0 : *valor_substitut = '(';
204 0 : return FALSE;
205 0 : case 93:
206 0 : *valor_substitut = ')';
207 0 : return FALSE;
208 0 : case 96:
209 0 : *valor_substitut = '\'';
210 0 : return FALSE;
211 0 : case 127:
212 0 : *valor_substitut = '_';
213 0 : return FALSE;
214 0 : case 168:
215 0 : *valor_substitut = '-';
216 0 : return FALSE;
217 : }
218 : }
219 : else
220 : {
221 81935 : if (valor < 32 || valor == 91 || valor == 93 || valor == 96 ||
222 81935 : valor == 127 || valor == 168)
223 0 : return FALSE;
224 : }
225 81935 : return TRUE;
226 : }
227 :
228 10272 : CPL_DLL int MM_ISExtendedNameBD_XP(const char *nom_camp)
229 : {
230 : size_t mida, j;
231 :
232 10272 : mida = strlen(nom_camp);
233 10272 : if (mida >= MM_MAX_LON_FIELD_NAME_DBF)
234 0 : return MM_DBF_NAME_NO_VALID;
235 :
236 92207 : for (j = 0; j < mida; j++)
237 : {
238 81935 : if (!MM_Is_character_valid_for_extended_DBF_field_name(
239 81935 : (unsigned char)nom_camp[j], nullptr))
240 0 : return MM_DBF_NAME_NO_VALID;
241 : }
242 :
243 10272 : if (mida >= MM_MAX_LON_CLASSICAL_FIELD_NAME_DBF)
244 1118 : return MM_VALID_EXTENDED_DBF_NAME;
245 :
246 9154 : if (!MM_Is_classical_DBF_field_name_or_lowercase(nom_camp))
247 32 : return MM_VALID_EXTENDED_DBF_NAME;
248 :
249 9122 : if (MM_is_field_name_lowercase(nom_camp))
250 3327 : return MM_DBF_NAME_LOWERCASE_AND_VALID;
251 :
252 5795 : return NM_CLASSICAL_DBF_AND_VALID_NAME;
253 : }
254 :
255 530 : CPL_DLL MM_BYTE MM_CalculateBytesExtendedFieldName(struct MM_FIELD *camp)
256 : {
257 530 : camp->reserved_2[MM_OFFSET_RESERVED2_EXTENDED_NAME_SIZE] =
258 530 : (MM_BYTE)strlen(camp->FieldName);
259 530 : return MM_DonaBytesNomEstesCamp(camp);
260 : }
261 :
262 : static MM_ACCUMULATED_BYTES_TYPE_DBF
263 194 : MM_CalculateBytesExtendedFieldNames(const struct MM_DATA_BASE_XP *bd_xp)
264 : {
265 194 : MM_ACCUMULATED_BYTES_TYPE_DBF bytes_acumulats = 0;
266 : MM_EXT_DBF_N_FIELDS i_camp;
267 :
268 1430 : for (i_camp = 0; i_camp < bd_xp->nFields; i_camp++)
269 : {
270 1236 : if (MM_VALID_EXTENDED_DBF_NAME ==
271 1236 : MM_ISExtendedNameBD_XP(bd_xp->pField[i_camp].FieldName))
272 91 : bytes_acumulats +=
273 91 : MM_CalculateBytesExtendedFieldName(bd_xp->pField + i_camp);
274 : }
275 :
276 194 : return bytes_acumulats;
277 : }
278 :
279 : static MM_FIRST_RECORD_OFFSET_TYPE
280 194 : MM_CalculateBytesFirstRecordOffset(struct MM_DATA_BASE_XP *bd_xp)
281 : {
282 194 : if (bd_xp)
283 194 : return (32 + 32 * bd_xp->nFields + 1 +
284 194 : MM_CalculateBytesExtendedFieldNames(bd_xp));
285 0 : return 0;
286 : }
287 :
288 194 : static void MM_CheckDBFHeader(struct MM_DATA_BASE_XP *bd_xp)
289 : {
290 : struct MM_FIELD *camp;
291 : MM_EXT_DBF_N_FIELDS i;
292 194 : MM_BOOLEAN cal_DBF_estesa = FALSE;
293 :
294 194 : bd_xp->BytesPerRecord = 1;
295 1430 : for (i = 0, camp = bd_xp->pField; i < bd_xp->nFields; i++, camp++)
296 : {
297 1236 : camp->AccumulatedBytes = bd_xp->BytesPerRecord;
298 1236 : bd_xp->BytesPerRecord += camp->BytesPerField;
299 1236 : if (camp->DesiredWidth == 0)
300 1236 : camp->DesiredWidth = camp->OriginalDesiredWidth =
301 1236 : MM_GetDefaultDesiredDBFFieldWidth(camp); //camp->BytesPerField;
302 1236 : if (camp->FieldType == 'C' &&
303 192 : camp->BytesPerField > MM_MAX_AMPLADA_CAMP_C_DBF_CLASSICA)
304 0 : cal_DBF_estesa = TRUE;
305 1236 : if (MM_VALID_EXTENDED_DBF_NAME ==
306 1236 : MM_ISExtendedNameBD_XP(camp->FieldName))
307 91 : cal_DBF_estesa = TRUE;
308 : }
309 :
310 194 : bd_xp->FirstRecordOffset = MM_CalculateBytesFirstRecordOffset(bd_xp);
311 :
312 194 : if (cal_DBF_estesa || bd_xp->nFields > MM_MAX_N_CAMPS_DBF_CLASSICA ||
313 170 : bd_xp->nRecords > UINT32_MAX)
314 24 : bd_xp->dbf_version = (MM_BYTE)MM_MARCA_VERSIO_1_DBF_ESTESA;
315 : else
316 170 : bd_xp->dbf_version = MM_MARCA_DBASE4;
317 194 : }
318 :
319 : static void
320 2115 : MM_InitializeOffsetExtendedFieldNameFields(struct MM_DATA_BASE_XP *bd_xp,
321 : MM_EXT_DBF_N_FIELDS i_camp)
322 : {
323 2115 : memset((char *)(&bd_xp->pField[i_camp].reserved_2) +
324 : MM_OFFSET_RESERVAT2_OFFSET_NOM_ESTES,
325 : 0, 4);
326 2115 : }
327 :
328 : static void
329 2115 : MM_InitializeBytesExtendedFieldNameFields(struct MM_DATA_BASE_XP *bd_xp,
330 : MM_EXT_DBF_N_FIELDS i_camp)
331 : {
332 2115 : memset((char *)(&bd_xp->pField[i_camp].reserved_2) +
333 : MM_OFFSET_RESERVED2_EXTENDED_NAME_SIZE,
334 : 0, 1);
335 2115 : }
336 :
337 91 : static short int MM_return_common_valid_DBF_field_name_string(char *szChain)
338 : {
339 : char *p;
340 91 : short int error_retornat = 0;
341 :
342 91 : if (!szChain)
343 0 : return 0;
344 : //strupr(szChain);
345 1204 : for (p = szChain; *p; p++)
346 : {
347 1113 : (*p) = (char)toupper((unsigned char)*p);
348 1113 : if ((*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9') || *p == '_')
349 : ;
350 : else
351 : {
352 7 : *p = '_';
353 7 : error_retornat |= MM_FIELD_NAME_CHARACTER_INVALID;
354 : }
355 : }
356 91 : if (szChain[0] == '_')
357 : {
358 : // To avoid having field names starting by '_' this case is
359 : // substituted by a 0 (not a '\0').
360 0 : szChain[0] = '0';
361 0 : error_retornat |= MM_FIELD_NAME_FIRST_CHARACTER_;
362 : }
363 91 : return error_retornat;
364 : }
365 :
366 91 : CPL_DLL short int MM_ReturnValidClassicDBFFieldName(char *szChain)
367 : {
368 : size_t long_nom_camp;
369 91 : short int error_retornat = 0;
370 :
371 91 : long_nom_camp = strlen(szChain);
372 91 : if ((long_nom_camp < 1) ||
373 : (long_nom_camp >= MM_MAX_LON_CLASSICAL_FIELD_NAME_DBF))
374 : {
375 89 : szChain[MM_MAX_LON_FIELD_NAME_DBF - 1] = '\0';
376 89 : error_retornat |= MM_FIELD_NAME_TOO_LONG;
377 : }
378 91 : error_retornat |= MM_return_common_valid_DBF_field_name_string(szChain);
379 91 : return error_retornat;
380 : }
381 :
382 : static MM_BOOLEAN
383 91 : MM_CheckClassicFieldNameEqual(const struct MM_DATA_BASE_XP *data_base_XP,
384 : const char *classical_name)
385 : {
386 : MM_EXT_DBF_N_FIELDS i;
387 :
388 1300 : for (i = 0; i < data_base_XP->nFields; i++)
389 : {
390 1209 : if ((strcasecmp(data_base_XP->pField[i].ClassicalDBFFieldName,
391 1209 : classical_name)) == 0 ||
392 1209 : (strcasecmp(data_base_XP->pField[i].FieldName, classical_name)) ==
393 : 0)
394 0 : return TRUE;
395 : }
396 91 : return FALSE;
397 : }
398 :
399 0 : static char *MM_GiveNewStringWithCharacterInFront(const char *text,
400 : char character)
401 : {
402 : char *ptr;
403 : size_t i;
404 :
405 0 : if (!text)
406 0 : return nullptr;
407 :
408 0 : i = strlen(text);
409 0 : if ((ptr = VSICalloc(1, i + 2)) == nullptr)
410 0 : return nullptr;
411 :
412 0 : *ptr = character;
413 0 : memcpy(ptr + 1, text, i + 1);
414 0 : return ptr;
415 : }
416 :
417 0 : static char *MM_SetSubIndexFieldNam(const char *nom_camp,
418 : MM_EXT_DBF_N_FIELDS index,
419 : size_t ampladamax)
420 : {
421 : char *NomCamp_SubIndex;
422 : char *_subindex;
423 : char subindex[19 + 1];
424 : size_t sizet_subindex;
425 : size_t sizet_nomcamp;
426 :
427 0 : NomCamp_SubIndex = VSICalloc(1, ampladamax);
428 0 : if (!NomCamp_SubIndex)
429 0 : return nullptr;
430 :
431 0 : CPLStrlcpy(NomCamp_SubIndex, nom_camp, ampladamax);
432 0 : NomCamp_SubIndex[ampladamax - 1] = '\0';
433 :
434 0 : snprintf(subindex, sizeof(subindex), sprintf_UINT64, (GUInt64)index);
435 :
436 0 : _subindex = MM_GiveNewStringWithCharacterInFront(subindex, '_');
437 0 : if (!_subindex)
438 : {
439 0 : VSIFree(NomCamp_SubIndex);
440 0 : return nullptr;
441 : }
442 :
443 0 : sizet_subindex = strlen(_subindex);
444 0 : sizet_nomcamp = strlen(NomCamp_SubIndex);
445 :
446 0 : if (sizet_nomcamp + sizet_subindex > ampladamax - 1)
447 0 : memcpy(NomCamp_SubIndex + ((ampladamax - 1) - sizet_subindex),
448 : _subindex, strlen(_subindex));
449 : else
450 0 : NomCamp_SubIndex = strcat(NomCamp_SubIndex, _subindex);
451 :
452 0 : VSIFree(_subindex);
453 :
454 0 : return NomCamp_SubIndex;
455 : }
456 :
457 : CPL_DLL MM_FIRST_RECORD_OFFSET_TYPE
458 771 : MM_GiveOffsetExtendedFieldName(const struct MM_FIELD *camp)
459 : {
460 : MM_FIRST_RECORD_OFFSET_TYPE offset_nom_camp;
461 :
462 771 : memcpy(&offset_nom_camp,
463 771 : (char *)(&camp->reserved_2) + MM_OFFSET_RESERVAT2_OFFSET_NOM_ESTES,
464 : 4);
465 771 : return offset_nom_camp;
466 : }
467 :
468 311 : CPL_DLL int MM_WriteNRecordsMMBD_XPFile(struct MMAdmDatabase *MMAdmDB)
469 : {
470 311 : if (!MMAdmDB->pMMBDXP || !MMAdmDB->pMMBDXP->pfDataBase)
471 0 : return 0;
472 :
473 : // Updating number of features in features table
474 311 : VSIFSeekL(MMAdmDB->pMMBDXP->pfDataBase, MM_FIRST_OFFSET_to_N_RECORDS,
475 : SEEK_SET);
476 :
477 311 : if (MMAdmDB->pMMBDXP->nRecords > UINT32_MAX)
478 : {
479 0 : MMAdmDB->pMMBDXP->dbf_version = MM_MARCA_VERSIO_1_DBF_ESTESA;
480 : }
481 : else
482 : {
483 311 : MMAdmDB->pMMBDXP->dbf_version = MM_MARCA_DBASE4;
484 : }
485 :
486 : {
487 311 : GUInt32 nRecords32LowBits =
488 311 : (GUInt32)(MMAdmDB->pMMBDXP->nRecords & UINT32_MAX);
489 311 : if (VSIFWriteL(&nRecords32LowBits, 4, 1,
490 311 : MMAdmDB->pMMBDXP->pfDataBase) != 1)
491 0 : return 1;
492 : }
493 :
494 311 : VSIFSeekL(MMAdmDB->pMMBDXP->pfDataBase, MM_SECOND_OFFSET_to_N_RECORDS,
495 : SEEK_SET);
496 311 : if (MMAdmDB->pMMBDXP->dbf_version == MM_MARCA_VERSIO_1_DBF_ESTESA)
497 : {
498 : /* from 16 to 19, position MM_SECOND_OFFSET_to_N_RECORDS */
499 0 : GUInt32 nRecords32HighBits =
500 0 : (GUInt32)(MMAdmDB->pMMBDXP->nRecords >> 32);
501 0 : if (VSIFWriteL(&nRecords32HighBits, 4, 1,
502 0 : MMAdmDB->pMMBDXP->pfDataBase) != 1)
503 0 : return 1;
504 :
505 : /* from 20 to 27 */
506 0 : if (VSIFWriteL(&(MMAdmDB->pMMBDXP->dbf_on_a_LAN), 8, 1,
507 0 : MMAdmDB->pMMBDXP->pfDataBase) != 1)
508 0 : return 1;
509 : }
510 : else
511 : {
512 311 : if (VSIFWriteL(&(MMAdmDB->pMMBDXP->dbf_on_a_LAN), 12, 1,
513 311 : MMAdmDB->pMMBDXP->pfDataBase) != 1)
514 0 : return 1;
515 : }
516 :
517 311 : return 0;
518 : }
519 :
520 : static MM_BOOLEAN
521 311 : MM_OpenIfNeededAndUpdateEntireHeader(struct MM_DATA_BASE_XP *data_base_XP)
522 : {
523 : MM_BYTE variable_byte;
524 311 : MM_EXT_DBF_N_FIELDS i, j = 0;
525 311 : char zero[11] = {0};
526 311 : const MM_BYTE byte_zero = 0;
527 311 : char ModeLectura_previ[4] = "";
528 : MM_FIRST_RECORD_OFFSET_TYPE bytes_acumulats;
529 : MM_BYTE name_size;
530 : int estat;
531 : char nom_camp[MM_MAX_LON_FIELD_NAME_DBF];
532 : size_t retorn_fwrite;
533 :
534 311 : if (!data_base_XP)
535 0 : return FALSE;
536 :
537 311 : if (data_base_XP->pfDataBase == nullptr)
538 : {
539 194 : strcpy(ModeLectura_previ, data_base_XP->ReadingMode);
540 194 : strcpy(data_base_XP->ReadingMode, "wb+");
541 :
542 194 : if ((data_base_XP->pfDataBase = VSIFOpenL(data_base_XP->szFileName,
543 194 : data_base_XP->ReadingMode)) ==
544 : nullptr)
545 : {
546 0 : return FALSE;
547 : }
548 : }
549 : else
550 : {
551 : // If it's open we just update the header
552 117 : VSIFSeekL(data_base_XP->pfDataBase, 0, SEEK_SET);
553 : }
554 :
555 311 : if ((data_base_XP->nFields) > MM_MAX_N_CAMPS_DBF_CLASSICA)
556 0 : data_base_XP->dbf_version = MM_MARCA_VERSIO_1_DBF_ESTESA;
557 311 : else if ((data_base_XP->nRecords) > UINT32_MAX)
558 0 : data_base_XP->dbf_version = MM_MARCA_VERSIO_1_DBF_ESTESA;
559 : else
560 : {
561 311 : if (data_base_XP->dbf_version == MM_MARCA_VERSIO_1_DBF_ESTESA)
562 24 : data_base_XP->dbf_version = MM_MARCA_DBASE4;
563 2253 : for (i = 0; i < data_base_XP->nFields; i++)
564 : {
565 2032 : if (data_base_XP->pField[i].FieldType == 'C' &&
566 348 : data_base_XP->pField[i].BytesPerField >
567 : MM_MAX_AMPLADA_CAMP_C_DBF_CLASSICA)
568 : {
569 0 : data_base_XP->dbf_version = MM_MARCA_VERSIO_1_DBF_ESTESA;
570 0 : break;
571 : }
572 2032 : if (MM_VALID_EXTENDED_DBF_NAME ==
573 2032 : MM_ISExtendedNameBD_XP(data_base_XP->pField[i].FieldName))
574 : {
575 90 : data_base_XP->dbf_version = MM_MARCA_VERSIO_1_DBF_ESTESA;
576 90 : break;
577 : }
578 : }
579 : }
580 :
581 : // Writing header
582 311 : VSIFSeekL(data_base_XP->pfDataBase, 0, SEEK_SET);
583 :
584 : /* Byte 0 */
585 311 : if (VSIFWriteL(&(data_base_XP->dbf_version), 1, 1,
586 : data_base_XP->pfDataBase) != 1)
587 : {
588 0 : VSIFCloseL(data_base_XP->pfDataBase);
589 0 : data_base_XP->pfDataBase = nullptr;
590 0 : return FALSE;
591 : }
592 :
593 : /* MM_BYTE from 1 to 3 */
594 311 : variable_byte = (MM_BYTE)(data_base_XP->year - 1900);
595 311 : if (VSIFWriteL(&variable_byte, 1, 1, data_base_XP->pfDataBase) != 1)
596 : {
597 0 : VSIFCloseL(data_base_XP->pfDataBase);
598 0 : data_base_XP->pfDataBase = nullptr;
599 0 : return FALSE;
600 : }
601 311 : if (VSIFWriteL(&(data_base_XP->month), 1, 1, data_base_XP->pfDataBase) != 1)
602 : {
603 0 : VSIFCloseL(data_base_XP->pfDataBase);
604 0 : data_base_XP->pfDataBase = nullptr;
605 0 : return FALSE;
606 : }
607 311 : if (VSIFWriteL(&(data_base_XP->day), 1, 1, data_base_XP->pfDataBase) != 1)
608 : {
609 0 : VSIFCloseL(data_base_XP->pfDataBase);
610 0 : data_base_XP->pfDataBase = nullptr;
611 0 : return FALSE;
612 : }
613 :
614 : /* from 4 a 7, position MM_FIRST_OFFSET_to_N_RECORDS */
615 : {
616 311 : GUInt32 nRecords32LowBits =
617 311 : (GUInt32)(data_base_XP->nRecords & UINT32_MAX);
618 311 : if (VSIFWriteL(&nRecords32LowBits, 4, 1, data_base_XP->pfDataBase) != 1)
619 : {
620 0 : VSIFCloseL(data_base_XP->pfDataBase);
621 0 : data_base_XP->pfDataBase = nullptr;
622 0 : return FALSE;
623 : }
624 : }
625 :
626 : /* from 8 a 9, position MM_PRIMER_OFFSET_a_OFFSET_1a_FITXA */
627 311 : if (VSIFWriteL(&(data_base_XP->FirstRecordOffset), 2, 1,
628 : data_base_XP->pfDataBase) != 1)
629 : {
630 0 : VSIFCloseL(data_base_XP->pfDataBase);
631 0 : data_base_XP->pfDataBase = nullptr;
632 0 : return FALSE;
633 : }
634 : /* from 10 to 11, & from 12 to 13 */
635 311 : if (MM_ES_DBF_ESTESA(data_base_XP->dbf_version))
636 : {
637 90 : if (VSIFWriteL(&(data_base_XP->BytesPerRecord),
638 : sizeof(MM_ACCUMULATED_BYTES_TYPE_DBF), 1,
639 : data_base_XP->pfDataBase) != 1)
640 : {
641 0 : VSIFCloseL(data_base_XP->pfDataBase);
642 0 : data_base_XP->pfDataBase = nullptr;
643 0 : return FALSE;
644 : }
645 : }
646 : else
647 : {
648 : /* from 10 to 11 */
649 221 : if (VSIFWriteL(&(data_base_XP->BytesPerRecord), 2, 1,
650 : data_base_XP->pfDataBase) != 1)
651 : {
652 0 : VSIFCloseL(data_base_XP->pfDataBase);
653 0 : data_base_XP->pfDataBase = nullptr;
654 0 : return FALSE;
655 : }
656 : /* from 12 to 13 */
657 221 : if (VSIFWriteL(&(data_base_XP->reserved_1), 2, 1,
658 : data_base_XP->pfDataBase) != 1)
659 : {
660 0 : VSIFCloseL(data_base_XP->pfDataBase);
661 0 : data_base_XP->pfDataBase = nullptr;
662 0 : return FALSE;
663 : }
664 : }
665 : /* byte 14 */
666 311 : if (VSIFWriteL(&(data_base_XP->transaction_flag), 1, 1,
667 : data_base_XP->pfDataBase) != 1)
668 : {
669 0 : VSIFCloseL(data_base_XP->pfDataBase);
670 0 : data_base_XP->pfDataBase = nullptr;
671 0 : return FALSE;
672 : }
673 : /* byte 15 */
674 311 : if (VSIFWriteL(&(data_base_XP->encryption_flag), 1, 1,
675 : data_base_XP->pfDataBase) != 1)
676 : {
677 0 : VSIFCloseL(data_base_XP->pfDataBase);
678 0 : data_base_XP->pfDataBase = nullptr;
679 0 : return FALSE;
680 : }
681 :
682 : /* from 16 to 27 */
683 311 : if (data_base_XP->nRecords > UINT32_MAX)
684 : {
685 : /* from 16 to 19, position MM_SECOND_OFFSET_to_N_RECORDS */
686 0 : GUInt32 nRecords32HighBits = (GUInt32)(data_base_XP->nRecords >> 32);
687 0 : if (VSIFWriteL(&nRecords32HighBits, 4, 1, data_base_XP->pfDataBase) !=
688 : 1)
689 : {
690 0 : VSIFCloseL(data_base_XP->pfDataBase);
691 0 : data_base_XP->pfDataBase = nullptr;
692 0 : return FALSE;
693 : }
694 :
695 : /* from 20 to 27 */
696 0 : if (VSIFWriteL(&(data_base_XP->dbf_on_a_LAN), 8, 1,
697 : data_base_XP->pfDataBase) != 1)
698 : {
699 0 : VSIFCloseL(data_base_XP->pfDataBase);
700 0 : data_base_XP->pfDataBase = nullptr;
701 0 : return FALSE;
702 : }
703 : }
704 : else
705 : {
706 : /* from 16 to 27 */
707 311 : if (VSIFWriteL(&(data_base_XP->dbf_on_a_LAN), 12, 1,
708 : data_base_XP->pfDataBase) != 1)
709 : {
710 0 : VSIFCloseL(data_base_XP->pfDataBase);
711 0 : data_base_XP->pfDataBase = nullptr;
712 0 : return FALSE;
713 : }
714 : }
715 : /* byte 28 */
716 311 : if (VSIFWriteL(&(data_base_XP->MDX_flag), 1, 1, data_base_XP->pfDataBase) !=
717 : 1)
718 : {
719 0 : VSIFCloseL(data_base_XP->pfDataBase);
720 0 : data_base_XP->pfDataBase = nullptr;
721 0 : return FALSE;
722 : }
723 :
724 : /* Byte 29 */
725 311 : if (VSIFWriteL(&(data_base_XP->CharSet), 1, 1, data_base_XP->pfDataBase) !=
726 : 1)
727 : {
728 0 : VSIFCloseL(data_base_XP->pfDataBase);
729 0 : data_base_XP->pfDataBase = nullptr;
730 0 : return FALSE;
731 : }
732 :
733 : /* Bytes from 30 to 31, in position MM_SEGON_OFFSET_a_OFFSET_1a_FITXA */
734 311 : if (MM_ES_DBF_ESTESA(data_base_XP->dbf_version))
735 : {
736 90 : if (VSIFWriteL(((char *)&(data_base_XP->FirstRecordOffset)) + 2, 2, 1,
737 : data_base_XP->pfDataBase) != 1)
738 : {
739 0 : VSIFCloseL(data_base_XP->pfDataBase);
740 0 : data_base_XP->pfDataBase = nullptr;
741 0 : return FALSE;
742 : }
743 : }
744 : else
745 : {
746 221 : if (VSIFWriteL(&(data_base_XP->reserved_2), 2, 1,
747 : data_base_XP->pfDataBase) != 1)
748 : {
749 0 : VSIFCloseL(data_base_XP->pfDataBase);
750 0 : data_base_XP->pfDataBase = nullptr;
751 0 : return FALSE;
752 : }
753 : }
754 :
755 : /* At 32th byte fields description begins */
756 : /* Every description is 32 bytes long */
757 311 : bytes_acumulats = 32 + 32 * (data_base_XP->nFields) + 1;
758 :
759 2865 : for (i = 0; i < data_base_XP->nFields; i++)
760 : {
761 : /* Bytes from 0 to 10 -> Field name, \0 finished */
762 2554 : estat = MM_ISExtendedNameBD_XP(data_base_XP->pField[i].FieldName);
763 2554 : if (estat == NM_CLASSICAL_DBF_AND_VALID_NAME ||
764 : estat == MM_DBF_NAME_LOWERCASE_AND_VALID)
765 : {
766 2115 : j = (short)strlen(data_base_XP->pField[i].FieldName);
767 :
768 2115 : retorn_fwrite = VSIFWriteL(&data_base_XP->pField[i].FieldName, 1, j,
769 : data_base_XP->pfDataBase);
770 2115 : if (retorn_fwrite != (size_t)j)
771 : {
772 0 : VSIFCloseL(data_base_XP->pfDataBase);
773 0 : data_base_XP->pfDataBase = nullptr;
774 0 : return FALSE;
775 : }
776 2115 : MM_InitializeOffsetExtendedFieldNameFields(data_base_XP, i);
777 2115 : MM_InitializeBytesExtendedFieldNameFields(data_base_XP, i);
778 : }
779 439 : else if (estat == MM_VALID_EXTENDED_DBF_NAME)
780 : {
781 439 : if (*(data_base_XP->pField[i].ClassicalDBFFieldName) == '\0')
782 : {
783 : char nom_temp[MM_MAX_LON_FIELD_NAME_DBF];
784 :
785 91 : CPLStrlcpy(nom_temp, data_base_XP->pField[i].FieldName,
786 : MM_MAX_LON_FIELD_NAME_DBF);
787 91 : MM_ReturnValidClassicDBFFieldName(nom_temp);
788 91 : nom_temp[MM_MAX_LON_CLASSICAL_FIELD_NAME_DBF - 1] = '\0';
789 91 : if ((MM_CheckClassicFieldNameEqual(data_base_XP, nom_temp)) ==
790 : TRUE)
791 : {
792 : char *c;
793 :
794 0 : c = MM_SetSubIndexFieldNam(
795 : nom_temp, i, MM_MAX_LON_CLASSICAL_FIELD_NAME_DBF);
796 :
797 0 : if (c)
798 : {
799 0 : j = 0;
800 0 : while (MM_CheckClassicFieldNameEqual(data_base_XP, c) ==
801 0 : TRUE &&
802 0 : j < data_base_XP->nFields)
803 : {
804 0 : VSIFree(c);
805 0 : c = MM_SetSubIndexFieldNam(
806 : nom_temp, ++j,
807 : MM_MAX_LON_CLASSICAL_FIELD_NAME_DBF);
808 : }
809 0 : if (c)
810 : {
811 0 : CPLStrlcpy(
812 0 : data_base_XP->pField[i].ClassicalDBFFieldName,
813 : c,
814 : sizeof(data_base_XP->pField[i]
815 : .ClassicalDBFFieldName));
816 0 : VSIFree(c);
817 : }
818 : }
819 : }
820 : else
821 91 : CPLStrlcpy(
822 91 : data_base_XP->pField[i].ClassicalDBFFieldName, nom_temp,
823 : sizeof(data_base_XP->pField[i].ClassicalDBFFieldName));
824 : }
825 :
826 : // This is a 11-byte fixed size field consisting of the filename
827 : // and it's been padding calculated some next lines.
828 439 : j = (short)strlen(data_base_XP->pField[i].ClassicalDBFFieldName);
829 :
830 : retorn_fwrite =
831 439 : VSIFWriteL(&data_base_XP->pField[i].ClassicalDBFFieldName, 1, j,
832 : data_base_XP->pfDataBase);
833 439 : if (retorn_fwrite != (size_t)j)
834 : {
835 0 : VSIFCloseL(data_base_XP->pfDataBase);
836 0 : data_base_XP->pfDataBase = nullptr;
837 0 : return FALSE;
838 : }
839 :
840 : name_size =
841 439 : MM_CalculateBytesExtendedFieldName(data_base_XP->pField + i);
842 439 : MM_EscriuOffsetNomEstesBD_XP(data_base_XP, i, bytes_acumulats);
843 439 : bytes_acumulats += name_size;
844 : }
845 : else
846 : {
847 0 : VSIFCloseL(data_base_XP->pfDataBase);
848 0 : data_base_XP->pfDataBase = nullptr;
849 0 : return FALSE;
850 : }
851 :
852 2554 : if (VSIFWriteL(zero, 1, 11 - j, data_base_XP->pfDataBase) !=
853 2554 : 11 - (size_t)j)
854 : {
855 0 : VSIFCloseL(data_base_XP->pfDataBase);
856 0 : data_base_XP->pfDataBase = nullptr;
857 0 : return FALSE;
858 : }
859 : /* Byte 11, Field type */
860 2554 : if (VSIFWriteL(&data_base_XP->pField[i].FieldType, 1, 1,
861 : data_base_XP->pfDataBase) != 1)
862 : {
863 0 : VSIFCloseL(data_base_XP->pfDataBase);
864 0 : data_base_XP->pfDataBase = nullptr;
865 0 : return FALSE;
866 : }
867 : /* Bytes 12 to 15 --> Reserved */
868 2554 : if (VSIFWriteL(&data_base_XP->pField[i].reserved_1, 4, 1,
869 : data_base_XP->pfDataBase) != 1)
870 : {
871 0 : VSIFCloseL(data_base_XP->pfDataBase);
872 0 : data_base_XP->pfDataBase = nullptr;
873 0 : return FALSE;
874 : }
875 : /* Byte 16, or OFFSET_BYTESxCAMP_CAMP_CLASSIC --> BytesPerField */
876 2554 : if (MM_ES_DBF_ESTESA(data_base_XP->dbf_version) &&
877 1192 : data_base_XP->pField[i].FieldType == 'C')
878 : {
879 201 : if (VSIFWriteL((void *)&byte_zero, 1, 1,
880 : data_base_XP->pfDataBase) != 1)
881 : {
882 0 : VSIFCloseL(data_base_XP->pfDataBase);
883 0 : data_base_XP->pfDataBase = nullptr;
884 0 : return FALSE;
885 : }
886 : }
887 : else
888 : {
889 2353 : if (VSIFWriteL(&data_base_XP->pField[i].BytesPerField, 1, 1,
890 : data_base_XP->pfDataBase) != 1)
891 : {
892 0 : VSIFCloseL(data_base_XP->pfDataBase);
893 0 : data_base_XP->pfDataBase = nullptr;
894 0 : return FALSE;
895 : }
896 : }
897 : /* 17th byte 17 --> In fields of type 'N' and 'F' indicates decimal places.*/
898 2554 : if (data_base_XP->pField[i].FieldType == 'N' ||
899 716 : data_base_XP->pField[i].FieldType == 'F')
900 : {
901 1838 : if (VSIFWriteL(&data_base_XP->pField[i].DecimalsIfFloat, 1, 1,
902 : data_base_XP->pfDataBase) != 1)
903 : {
904 0 : VSIFCloseL(data_base_XP->pfDataBase);
905 0 : data_base_XP->pfDataBase = nullptr;
906 0 : return FALSE;
907 : }
908 : }
909 : else
910 : {
911 716 : if (VSIFWriteL(zero, 1, 1, data_base_XP->pfDataBase) != 1)
912 : {
913 0 : VSIFCloseL(data_base_XP->pfDataBase);
914 0 : data_base_XP->pfDataBase = nullptr;
915 0 : return FALSE;
916 : }
917 : }
918 2554 : if (MM_ES_DBF_ESTESA(data_base_XP->dbf_version) &&
919 1192 : data_base_XP->pField[i].FieldType == 'C')
920 : {
921 : /* Bytes from 18 to 20 --> Reserved */
922 201 : if (VSIFWriteL(&data_base_XP->pField[i].reserved_2, 20 - 18 + 1, 1,
923 : data_base_XP->pfDataBase) != 1)
924 : {
925 0 : VSIFCloseL(data_base_XP->pfDataBase);
926 0 : data_base_XP->pfDataBase = nullptr;
927 0 : return FALSE;
928 : }
929 : /* Bytes from 21 to 24 --> OFFSET_BYTESxCAMP_CAMP_ESPECIAL, special fields, like C
930 : in extended DBF */
931 201 : if (VSIFWriteL(&data_base_XP->pField[i].BytesPerField,
932 : sizeof(MM_BYTES_PER_FIELD_TYPE_DBF), 1,
933 : data_base_XP->pfDataBase) != 1)
934 : {
935 0 : VSIFCloseL(data_base_XP->pfDataBase);
936 0 : data_base_XP->pfDataBase = nullptr;
937 0 : return FALSE;
938 : }
939 :
940 : /* Bytes from 25 to 30 --> Reserved */
941 201 : if (VSIFWriteL(&data_base_XP->pField[i].reserved_2[25 - 18],
942 : 30 - 25 + 1, 1, data_base_XP->pfDataBase) != 1)
943 : {
944 0 : VSIFCloseL(data_base_XP->pfDataBase);
945 0 : data_base_XP->pfDataBase = nullptr;
946 0 : return FALSE;
947 : }
948 : }
949 : else
950 : {
951 : /* Bytes de 21 a 24 --> OFFSET_BYTESxCAMP_CAMP_ESPECIAL, special fields, like C */
952 2353 : memset(data_base_XP->pField[i].reserved_2 +
953 : MM_OFFSET_RESERVAT2_BYTESxCAMP_CAMP_ESPECIAL,
954 : '\0', 4);
955 : /* Bytes from 18 to 30 --> Reserved */
956 2353 : if (VSIFWriteL(&data_base_XP->pField[i].reserved_2, 13, 1,
957 : data_base_XP->pfDataBase) != 1)
958 : {
959 0 : VSIFCloseL(data_base_XP->pfDataBase);
960 0 : data_base_XP->pfDataBase = nullptr;
961 0 : return FALSE;
962 : }
963 : }
964 : /* Byte 31 --> MDX flag. */
965 2554 : if (VSIFWriteL(&data_base_XP->pField[i].MDX_field_flag, 1, 1,
966 : data_base_XP->pfDataBase) != 1)
967 : {
968 0 : VSIFCloseL(data_base_XP->pfDataBase);
969 0 : data_base_XP->pfDataBase = nullptr;
970 0 : return FALSE;
971 : }
972 : }
973 :
974 311 : variable_byte = 13;
975 311 : if (VSIFWriteL(&variable_byte, 1, 1, data_base_XP->pfDataBase) != 1)
976 : {
977 0 : VSIFCloseL(data_base_XP->pfDataBase);
978 0 : data_base_XP->pfDataBase = nullptr;
979 0 : return FALSE;
980 : }
981 :
982 311 : if (data_base_XP->FirstRecordOffset != bytes_acumulats)
983 : {
984 0 : VSIFCloseL(data_base_XP->pfDataBase);
985 0 : data_base_XP->pfDataBase = nullptr;
986 0 : return FALSE;
987 : }
988 :
989 : // Extended fields
990 2865 : for (i = 0; i < data_base_XP->nFields; i++)
991 : {
992 2554 : if (MM_VALID_EXTENDED_DBF_NAME ==
993 2554 : MM_ISExtendedNameBD_XP(data_base_XP->pField[i].FieldName))
994 : {
995 439 : bytes_acumulats =
996 439 : MM_GiveOffsetExtendedFieldName(data_base_XP->pField + i);
997 439 : name_size = MM_DonaBytesNomEstesCamp(data_base_XP->pField + i);
998 :
999 439 : VSIFSeekL(data_base_XP->pfDataBase, bytes_acumulats, SEEK_SET);
1000 :
1001 439 : strcpy(nom_camp, data_base_XP->pField[i].FieldName);
1002 : //CanviaJocCaracPerEscriureDBF(nom_camp, JocCaracDBFaMM(data_base_XP->CharSet, ParMM.JocCaracDBFPerDefecte));
1003 :
1004 : retorn_fwrite =
1005 439 : VSIFWriteL(nom_camp, 1, name_size, data_base_XP->pfDataBase);
1006 :
1007 439 : if (retorn_fwrite != (size_t)name_size)
1008 : {
1009 0 : VSIFCloseL(data_base_XP->pfDataBase);
1010 0 : data_base_XP->pfDataBase = nullptr;
1011 0 : return FALSE;
1012 : }
1013 : }
1014 : }
1015 :
1016 311 : return TRUE;
1017 : } /* End of MM_OpenIfNeededAndUpdateEntireHeader() */
1018 :
1019 194 : CPL_DLL MM_BOOLEAN MM_CreateAndOpenDBFFile(struct MM_DATA_BASE_XP *bd_xp,
1020 : const char *NomFitxer)
1021 : {
1022 : time_t currentTime;
1023 :
1024 194 : if (!NomFitxer || MMIsEmptyString(NomFitxer) || !bd_xp)
1025 0 : return FALSE;
1026 :
1027 194 : MM_CheckDBFHeader(bd_xp);
1028 :
1029 : // Setting the current date
1030 194 : currentTime = time(nullptr);
1031 :
1032 : struct tm ltime;
1033 194 : VSILocalTime(¤tTime, <ime);
1034 :
1035 194 : bd_xp->year = (short int)(ltime.tm_year + 1900);
1036 194 : bd_xp->month = (MM_BYTE)(ltime.tm_mon + 1);
1037 194 : bd_xp->day = (MM_BYTE)ltime.tm_mday;
1038 :
1039 194 : CPLStrlcpy(bd_xp->szFileName, NomFitxer, sizeof(bd_xp->szFileName));
1040 194 : return MM_OpenIfNeededAndUpdateEntireHeader(bd_xp);
1041 : }
1042 :
1043 340 : CPL_DLL void MM_ReleaseMainFields(struct MM_DATA_BASE_XP *data_base_XP)
1044 : {
1045 : MM_EXT_DBF_N_FIELDS i;
1046 : size_t j;
1047 : char **szChain;
1048 :
1049 340 : if (data_base_XP->pField)
1050 : {
1051 2791 : for (i = 0; i < data_base_XP->nFields; i++)
1052 : {
1053 12260 : for (j = 0; j < MM_NUM_IDIOMES_MD_MULTIDIOMA; j++)
1054 : {
1055 9808 : szChain = data_base_XP->pField[i].Separator;
1056 9808 : if (szChain[j])
1057 : {
1058 0 : VSIFree(szChain[j]);
1059 0 : szChain[j] = nullptr;
1060 : }
1061 : }
1062 : }
1063 339 : VSIFree(data_base_XP->pField);
1064 339 : data_base_XP->pField = nullptr;
1065 339 : data_base_XP->nFields = 0;
1066 : }
1067 340 : return;
1068 : }
1069 :
1070 : // READING THE HEADER OF AN EXTENDED DBF
1071 : // Free with MM_ReleaseDBFHeader()
1072 147 : CPL_DLL int MM_ReadExtendedDBFHeaderFromFile(const char *szFileName,
1073 : struct MM_DATA_BASE_XP *pMMBDXP,
1074 : const char *pszRelFile)
1075 : {
1076 : MM_BYTE variable_byte;
1077 : VSILFILE *pf;
1078 : unsigned short int two_bytes;
1079 : MM_EXT_DBF_N_FIELDS nIField;
1080 : uint16_t offset_primera_fitxa;
1081 147 : MM_FIRST_RECORD_OFFSET_TYPE offset_fals = 0;
1082 147 : MM_BOOLEAN incoherent_record_size = FALSE;
1083 : MM_BYTE un_byte;
1084 : MM_BYTES_PER_FIELD_TYPE_DBF bytes_per_camp;
1085 : MM_BYTE tretze_bytes[13];
1086 : MM_FIRST_RECORD_OFFSET_TYPE offset_possible;
1087 147 : MM_BYTE some_problems_when_reading = 0;
1088 147 : MM_FILE_OFFSET offset_reintent = 0; // For retrying
1089 : char cpg_file[MM_CPL_PATH_BUF_SIZE];
1090 : char *pszDesc;
1091 : char section[MM_MAX_LON_FIELD_NAME_DBF + 25]; // TAULA_PRINCIPAL:field_name
1092 : GUInt32 nRecords32LowBits;
1093 : char *pszString;
1094 :
1095 147 : if (!szFileName || !pMMBDXP)
1096 0 : return 1;
1097 :
1098 147 : CPLStrlcpy(pMMBDXP->szFileName, szFileName, sizeof(pMMBDXP->szFileName));
1099 147 : strcpy(pMMBDXP->ReadingMode, "rb");
1100 :
1101 147 : if ((pMMBDXP->pfDataBase =
1102 147 : VSIFOpenL(pMMBDXP->szFileName, pMMBDXP->ReadingMode)) == nullptr)
1103 2 : return 1;
1104 :
1105 145 : pf = pMMBDXP->pfDataBase;
1106 :
1107 145 : VSIFSeekL(pf, 0, SEEK_SET);
1108 : /* ====== Header reading (32 bytes) =================== */
1109 145 : offset_primera_fitxa = 0;
1110 :
1111 290 : if (1 != VSIFReadL(&(pMMBDXP->dbf_version), 1, 1, pf) ||
1112 290 : 1 != VSIFReadL(&variable_byte, 1, 1, pf) ||
1113 290 : 1 != VSIFReadL(&(pMMBDXP->month), 1, 1, pf) ||
1114 145 : 1 != VSIFReadL(&(pMMBDXP->day), 1, 1, pf))
1115 : {
1116 0 : fclose_and_nullify(&pMMBDXP->pfDataBase);
1117 0 : return 1;
1118 : }
1119 :
1120 145 : if (1 != VSIFReadL(&nRecords32LowBits, 4, 1, pf))
1121 : {
1122 0 : fclose_and_nullify(&pMMBDXP->pfDataBase);
1123 0 : return 1;
1124 : }
1125 :
1126 145 : if (1 != VSIFReadL(&offset_primera_fitxa, 2, 1, pf))
1127 : {
1128 0 : fclose_and_nullify(&pMMBDXP->pfDataBase);
1129 0 : return 1;
1130 : }
1131 :
1132 145 : pMMBDXP->year = (short)(1900 + variable_byte);
1133 145 : reintenta_lectura_per_si_error_CreaCampBD_XP:
1134 :
1135 145 : if (some_problems_when_reading > 0)
1136 : {
1137 0 : if (!MM_ES_DBF_ESTESA(pMMBDXP->dbf_version))
1138 : {
1139 0 : offset_fals =
1140 0 : offset_primera_fitxa & (MM_FIRST_RECORD_OFFSET_TYPE)(~31);
1141 : }
1142 : }
1143 : else
1144 145 : offset_reintent = VSIFTellL(pf);
1145 :
1146 290 : if (1 != VSIFReadL(&two_bytes, 2, 1, pf) ||
1147 290 : 1 != VSIFReadL(&(pMMBDXP->reserved_1), 2, 1, pf) ||
1148 290 : 1 != VSIFReadL(&(pMMBDXP->transaction_flag), 1, 1, pf) ||
1149 290 : 1 != VSIFReadL(&(pMMBDXP->encryption_flag), 1, 1, pf) ||
1150 145 : 1 != VSIFReadL(&(pMMBDXP->dbf_on_a_LAN), 12, 1, pf))
1151 : {
1152 0 : VSIFree(pMMBDXP->pField);
1153 0 : pMMBDXP->pField = nullptr;
1154 0 : pMMBDXP->nFields = 0;
1155 0 : fclose_and_nullify(&pMMBDXP->pfDataBase);
1156 0 : return 1;
1157 : }
1158 :
1159 145 : if (MM_ES_DBF_ESTESA(pMMBDXP->dbf_version))
1160 : {
1161 : GUInt32 nRecords32HighBits;
1162 :
1163 : // Getting 4 bytes of the 8 bytes variable
1164 38 : memcpy(&nRecords32HighBits, &pMMBDXP->dbf_on_a_LAN, 4);
1165 :
1166 : // Getting other 4 bytes of the 8 bytes variable
1167 : // The cast to GUInt64 of the high 32 bits is important to
1168 : // make sure the left bit shift is done correctly
1169 38 : pMMBDXP->nRecords =
1170 38 : ((GUInt64)nRecords32HighBits << 32) | nRecords32LowBits;
1171 : }
1172 : else
1173 107 : pMMBDXP->nRecords = nRecords32LowBits;
1174 :
1175 290 : if (1 != VSIFReadL(&(pMMBDXP->MDX_flag), 1, 1, pf) ||
1176 290 : 1 != VSIFReadL(&(pMMBDXP->CharSet), 1, 1, pf) ||
1177 145 : 1 != VSIFReadL(&(pMMBDXP->reserved_2), 2, 1, pf))
1178 : {
1179 0 : VSIFree(pMMBDXP->pField);
1180 0 : pMMBDXP->pField = nullptr;
1181 0 : pMMBDXP->nFields = 0;
1182 0 : fclose_and_nullify(&pMMBDXP->pfDataBase);
1183 0 : return 1;
1184 : }
1185 :
1186 : // Checking for a cpg file
1187 145 : if (pMMBDXP->CharSet == 0)
1188 : {
1189 : VSILFILE *f_cpg;
1190 : char charset_cpg[11];
1191 :
1192 3 : strcpy(cpg_file, pMMBDXP->szFileName);
1193 3 : CPLStrlcpy(cpg_file, CPLResetExtension(cpg_file, "cpg"),
1194 : sizeof(cpg_file));
1195 3 : f_cpg = VSIFOpenL(cpg_file, "r");
1196 3 : if (f_cpg)
1197 : {
1198 : char *p;
1199 : size_t read_bytes;
1200 0 : VSIFSeekL(f_cpg, 0L, SEEK_SET);
1201 0 : if (11 > (read_bytes = VSIFReadL(charset_cpg, 1, 10, f_cpg)))
1202 : {
1203 0 : charset_cpg[read_bytes] = '\0';
1204 0 : p = MM_stristr(charset_cpg, "UTF-8");
1205 0 : if (p)
1206 0 : pMMBDXP->CharSet = MM_JOC_CARAC_UTF8_DBF;
1207 0 : p = MM_stristr(charset_cpg, "UTF8");
1208 0 : if (p)
1209 0 : pMMBDXP->CharSet = MM_JOC_CARAC_UTF8_DBF;
1210 0 : p = MM_stristr(charset_cpg, "ISO-8859-1");
1211 0 : if (p)
1212 0 : pMMBDXP->CharSet = MM_JOC_CARAC_ANSI_DBASE;
1213 : }
1214 0 : VSIFCloseL(f_cpg);
1215 : }
1216 : }
1217 145 : if (MM_ES_DBF_ESTESA(pMMBDXP->dbf_version))
1218 : {
1219 : unsigned short FirstRecordOffsetLow16Bits;
1220 : unsigned short FirstRecordOffsetHigh16Bits;
1221 : GUInt32 nTmp;
1222 :
1223 38 : memcpy(&FirstRecordOffsetLow16Bits, &offset_primera_fitxa, 2);
1224 38 : memcpy(&FirstRecordOffsetHigh16Bits, &pMMBDXP->reserved_2, 2);
1225 :
1226 38 : nTmp = ((GUInt32)FirstRecordOffsetHigh16Bits << 16) |
1227 : FirstRecordOffsetLow16Bits;
1228 38 : if (nTmp > INT32_MAX)
1229 : {
1230 0 : VSIFree(pMMBDXP->pField);
1231 0 : pMMBDXP->pField = nullptr;
1232 0 : pMMBDXP->nFields = 0;
1233 0 : fclose_and_nullify(&pMMBDXP->pfDataBase);
1234 0 : return 1;
1235 : }
1236 38 : pMMBDXP->FirstRecordOffset = (MM_FIRST_RECORD_OFFSET_TYPE)nTmp;
1237 :
1238 38 : if (some_problems_when_reading > 0)
1239 0 : offset_fals = pMMBDXP->FirstRecordOffset;
1240 :
1241 38 : memcpy(&FirstRecordOffsetLow16Bits, &two_bytes, 2);
1242 38 : memcpy(&FirstRecordOffsetHigh16Bits, &pMMBDXP->reserved_1, 2);
1243 :
1244 38 : pMMBDXP->BytesPerRecord = ((GUInt32)FirstRecordOffsetHigh16Bits << 16) |
1245 : FirstRecordOffsetLow16Bits;
1246 : }
1247 : else
1248 : {
1249 107 : pMMBDXP->FirstRecordOffset = offset_primera_fitxa;
1250 107 : pMMBDXP->BytesPerRecord = two_bytes;
1251 : }
1252 :
1253 : /* ====== Record structure ========================= */
1254 :
1255 145 : if (some_problems_when_reading > 0)
1256 : {
1257 0 : if (offset_fals < 1 + 32)
1258 0 : pMMBDXP->nFields = 0;
1259 : else
1260 0 : pMMBDXP->nFields =
1261 0 : (MM_EXT_DBF_N_FIELDS)(((offset_fals - 1) - 32) / 32);
1262 : }
1263 : else
1264 : {
1265 : // There's a chance that bytes_acumulats could overflow if it's GUInt32.
1266 : // For that reason it's better to promote to GUInt64.
1267 145 : GUInt64 bytes_acumulats = 1;
1268 :
1269 145 : pMMBDXP->nFields = 0;
1270 :
1271 145 : VSIFSeekL(pf, 0, SEEK_END);
1272 145 : if (32 - 1 < VSIFTellL(pf))
1273 : {
1274 145 : VSIFSeekL(pf, 32, SEEK_SET);
1275 : do
1276 : {
1277 1216 : bytes_per_camp = 0;
1278 1216 : VSIFSeekL(pf,
1279 1216 : 32 + (MM_FILE_OFFSET)pMMBDXP->nFields * 32 +
1280 : (MM_MAX_LON_CLASSICAL_FIELD_NAME_DBF + 1 + 4),
1281 : SEEK_SET);
1282 2432 : if (1 != VSIFReadL(&bytes_per_camp, 1, 1, pf) ||
1283 2432 : 1 != VSIFReadL(&un_byte, 1, 1, pf) ||
1284 1216 : 1 != VSIFReadL(&tretze_bytes, 3 + sizeof(bytes_per_camp), 1,
1285 : pf))
1286 : {
1287 0 : VSIFree(pMMBDXP->pField);
1288 0 : pMMBDXP->pField = nullptr;
1289 0 : pMMBDXP->nFields = 0;
1290 0 : fclose_and_nullify(&pMMBDXP->pfDataBase);
1291 0 : return 1;
1292 : }
1293 1216 : if (bytes_per_camp == 0)
1294 79 : memcpy(&bytes_per_camp, (char *)(&tretze_bytes) + 3,
1295 : sizeof(bytes_per_camp));
1296 :
1297 1216 : bytes_acumulats += bytes_per_camp;
1298 1216 : pMMBDXP->nFields++;
1299 1216 : } while (bytes_acumulats < pMMBDXP->BytesPerRecord);
1300 : }
1301 : }
1302 :
1303 145 : if (pMMBDXP->nFields != 0)
1304 : {
1305 145 : VSIFree(pMMBDXP->pField);
1306 145 : pMMBDXP->pField = MM_CreateAllFields(pMMBDXP->nFields);
1307 145 : if (!pMMBDXP->pField)
1308 : {
1309 0 : pMMBDXP->nFields = 0;
1310 0 : fclose_and_nullify(&pMMBDXP->pfDataBase);
1311 0 : return 1;
1312 : }
1313 : }
1314 : else
1315 : {
1316 0 : VSIFree(pMMBDXP->pField);
1317 0 : pMMBDXP->pField = nullptr;
1318 : }
1319 :
1320 145 : VSIFSeekL(pf, 32, SEEK_SET);
1321 1361 : for (nIField = 0; nIField < pMMBDXP->nFields; nIField++)
1322 : {
1323 1216 : if (1 != VSIFReadL(pMMBDXP->pField[nIField].FieldName,
1324 1216 : MM_MAX_LON_CLASSICAL_FIELD_NAME_DBF, 1, pf) ||
1325 2432 : 1 != VSIFReadL(&(pMMBDXP->pField[nIField].FieldType), 1, 1, pf) ||
1326 2432 : 1 != VSIFReadL(&(pMMBDXP->pField[nIField].reserved_1), 4, 1, pf) ||
1327 1216 : 1 != VSIFReadL(&(pMMBDXP->pField[nIField].BytesPerField), 1, 1,
1328 1216 : pf) ||
1329 1216 : 1 != VSIFReadL(&(pMMBDXP->pField[nIField].DecimalsIfFloat), 1, 1,
1330 1216 : pf) ||
1331 2432 : 1 != VSIFReadL(&(pMMBDXP->pField[nIField].reserved_2), 13, 1, pf) ||
1332 : 1 !=
1333 1216 : VSIFReadL(&(pMMBDXP->pField[nIField].MDX_field_flag), 1, 1, pf))
1334 : {
1335 0 : VSIFree(pMMBDXP->pField);
1336 0 : pMMBDXP->pField = nullptr;
1337 0 : pMMBDXP->nFields = 0;
1338 0 : VSIFCloseL(pf);
1339 0 : pMMBDXP->pfDataBase = nullptr;
1340 0 : return 1;
1341 : }
1342 :
1343 1216 : if (pMMBDXP->pField[nIField].FieldType == 'F')
1344 0 : pMMBDXP->pField[nIField].FieldType = 'N';
1345 :
1346 1216 : pMMBDXP->pField[nIField]
1347 1216 : .FieldName[MM_MAX_LON_CLASSICAL_FIELD_NAME_DBF - 1] = '\0';
1348 1216 : if (EQUAL(pMMBDXP->pField[nIField].FieldName,
1349 : szMMNomCampIdGraficDefecte))
1350 117 : pMMBDXP->IdGraficField = nIField;
1351 :
1352 : // Limit BytesPerField to avoid later integer overflows
1353 : // We could potentially limit further...
1354 1216 : if (pMMBDXP->pField[nIField].BytesPerField > (uint32_t)(INT32_MAX - 1))
1355 : {
1356 0 : VSIFree(pMMBDXP->pField);
1357 0 : pMMBDXP->pField = nullptr;
1358 0 : pMMBDXP->nFields = 0;
1359 0 : VSIFCloseL(pf);
1360 0 : pMMBDXP->pfDataBase = nullptr;
1361 0 : return 1;
1362 : }
1363 :
1364 1216 : if (pMMBDXP->pField[nIField].BytesPerField == 0)
1365 : {
1366 79 : if (!MM_ES_DBF_ESTESA(pMMBDXP->dbf_version))
1367 : {
1368 0 : VSIFree(pMMBDXP->pField);
1369 0 : pMMBDXP->pField = nullptr;
1370 0 : pMMBDXP->nFields = 0;
1371 0 : VSIFCloseL(pf);
1372 0 : pMMBDXP->pfDataBase = nullptr;
1373 0 : return 1;
1374 : }
1375 79 : if (pMMBDXP->pField[nIField].FieldType != 'C')
1376 : {
1377 0 : VSIFree(pMMBDXP->pField);
1378 0 : pMMBDXP->pField = nullptr;
1379 0 : pMMBDXP->nFields = 0;
1380 0 : VSIFCloseL(pf);
1381 0 : pMMBDXP->pfDataBase = nullptr;
1382 0 : return 1;
1383 : }
1384 :
1385 79 : memcpy(&pMMBDXP->pField[nIField].BytesPerField,
1386 79 : (char *)(&pMMBDXP->pField[nIField].reserved_2) + 3,
1387 : sizeof(MM_BYTES_PER_FIELD_TYPE_DBF));
1388 : }
1389 :
1390 1216 : if (nIField)
1391 : {
1392 : // To avoid overflow
1393 1071 : if (pMMBDXP->pField[nIField - 1].AccumulatedBytes >
1394 1071 : UINT32_MAX - pMMBDXP->pField[nIField - 1].BytesPerField)
1395 : {
1396 0 : VSIFree(pMMBDXP->pField);
1397 0 : pMMBDXP->pField = nullptr;
1398 0 : pMMBDXP->nFields = 0;
1399 0 : VSIFCloseL(pf);
1400 0 : pMMBDXP->pfDataBase = nullptr;
1401 0 : return 1;
1402 : }
1403 :
1404 1071 : pMMBDXP->pField[nIField].AccumulatedBytes =
1405 1071 : (pMMBDXP->pField[nIField - 1].AccumulatedBytes +
1406 1071 : pMMBDXP->pField[nIField - 1].BytesPerField);
1407 : }
1408 : else
1409 : {
1410 145 : pMMBDXP->pField[nIField].AccumulatedBytes = 1;
1411 : }
1412 :
1413 1216 : if (pszRelFile)
1414 : {
1415 : // Usually, in multilingual MiraMon metadata files, the main
1416 : // language is the default one and has no "_cat", "_spa", or
1417 : // "_eng" suffix after the keyword. So, to retrieve all
1418 : // languages in a multilingual file, first, we'll identify
1419 : // the one with no suffix "_cat", "_spa", or "_eng", and then the
1420 : // others. If one of them lacks a value, it gets the default value.
1421 1210 : snprintf(section, sizeof(section), "TAULA_PRINCIPAL:%s",
1422 1210 : pMMBDXP->pField[nIField].FieldName);
1423 :
1424 : // MM_DEF_LANGUAGE
1425 1210 : pszDesc = MMReturnValueFromSectionINIFile(pszRelFile, section,
1426 : "descriptor");
1427 1210 : if (pszDesc)
1428 : {
1429 632 : CPLStrlcpy(
1430 632 : pMMBDXP->pField[nIField].FieldDescription[MM_DEF_LANGUAGE],
1431 : pszDesc, MM_MAX_LON_DESCRIPCIO_CAMP_DBF);
1432 :
1433 632 : VSIFree(pszDesc);
1434 : }
1435 : else
1436 578 : *pMMBDXP->pField[nIField].FieldDescription[MM_DEF_LANGUAGE] =
1437 : '\0';
1438 :
1439 : // MM_ENG_LANGUAGE
1440 1210 : pszDesc = MMReturnValueFromSectionINIFile(pszRelFile, section,
1441 : "descriptor_eng");
1442 1210 : if (pszDesc)
1443 : {
1444 70 : CPLStrlcpy(
1445 70 : pMMBDXP->pField[nIField].FieldDescription[MM_ENG_LANGUAGE],
1446 : pszDesc, MM_MAX_LON_DESCRIPCIO_CAMP_DBF);
1447 :
1448 70 : if (*pMMBDXP->pField[nIField]
1449 : .FieldDescription[MM_DEF_LANGUAGE] == '\0')
1450 : {
1451 0 : CPLStrlcpy(pMMBDXP->pField[nIField]
1452 0 : .FieldDescription[MM_DEF_LANGUAGE],
1453 : pszDesc, MM_MAX_LON_DESCRIPCIO_CAMP_DBF);
1454 : }
1455 70 : VSIFree(pszDesc);
1456 : }
1457 : else
1458 : {
1459 : // If there is no value descriptor_eng it's because it's the
1460 : // default one. So, it's taken from there.
1461 1140 : CPLStrlcpy(
1462 1140 : pMMBDXP->pField[nIField].FieldDescription[MM_ENG_LANGUAGE],
1463 1140 : pMMBDXP->pField[nIField].FieldDescription[MM_DEF_LANGUAGE],
1464 : MM_MAX_LON_DESCRIPCIO_CAMP_DBF);
1465 : }
1466 :
1467 : // MM_CAT_LANGUAGE
1468 1210 : pszDesc = MMReturnValueFromSectionINIFile(pszRelFile, section,
1469 : "descriptor_cat");
1470 1210 : if (pszDesc)
1471 : {
1472 0 : CPLStrlcpy(
1473 0 : pMMBDXP->pField[nIField].FieldDescription[MM_CAT_LANGUAGE],
1474 : pszDesc, MM_MAX_LON_DESCRIPCIO_CAMP_DBF);
1475 :
1476 0 : if (*pMMBDXP->pField[nIField]
1477 : .FieldDescription[MM_DEF_LANGUAGE] == '\0')
1478 : {
1479 0 : CPLStrlcpy(pMMBDXP->pField[nIField]
1480 0 : .FieldDescription[MM_DEF_LANGUAGE],
1481 : pszDesc, MM_MAX_LON_DESCRIPCIO_CAMP_DBF);
1482 : }
1483 :
1484 0 : VSIFree(pszDesc);
1485 : }
1486 : else
1487 : {
1488 : // If there is no value descriptor_cat it's because it's the
1489 : // default one. So, it's taken from there.
1490 1210 : CPLStrlcpy(
1491 1210 : pMMBDXP->pField[nIField].FieldDescription[MM_CAT_LANGUAGE],
1492 1210 : pMMBDXP->pField[nIField].FieldDescription[MM_DEF_LANGUAGE],
1493 : MM_MAX_LON_DESCRIPCIO_CAMP_DBF);
1494 : }
1495 :
1496 : // MM_SPA_LANGUAGE
1497 1210 : pszDesc = MMReturnValueFromSectionINIFile(pszRelFile, section,
1498 : "descriptor_spa");
1499 1210 : if (pszDesc)
1500 : {
1501 70 : CPLStrlcpy(
1502 70 : pMMBDXP->pField[nIField].FieldDescription[MM_SPA_LANGUAGE],
1503 : pszDesc, MM_MAX_LON_DESCRIPCIO_CAMP_DBF);
1504 :
1505 70 : if (*pMMBDXP->pField[nIField]
1506 : .FieldDescription[MM_DEF_LANGUAGE] == '\0')
1507 : {
1508 0 : CPLStrlcpy(pMMBDXP->pField[nIField]
1509 0 : .FieldDescription[MM_DEF_LANGUAGE],
1510 : pszDesc, MM_MAX_LON_DESCRIPCIO_CAMP_DBF);
1511 : }
1512 :
1513 70 : VSIFree(pszDesc);
1514 : }
1515 : else
1516 : {
1517 : // If there is no value descriptor_spa it's because it's the
1518 : // default one. So, it's taken from there.
1519 1140 : CPLStrlcpy(
1520 1140 : pMMBDXP->pField[nIField].FieldDescription[MM_SPA_LANGUAGE],
1521 1140 : pMMBDXP->pField[nIField].FieldDescription[MM_DEF_LANGUAGE],
1522 : MM_MAX_LON_DESCRIPCIO_CAMP_DBF);
1523 : }
1524 : }
1525 : }
1526 :
1527 145 : if (!pMMBDXP->nFields)
1528 : {
1529 0 : if (pMMBDXP->BytesPerRecord)
1530 0 : incoherent_record_size = TRUE;
1531 : }
1532 : else
1533 : {
1534 : // To avoid overflow
1535 145 : if (pMMBDXP->pField[pMMBDXP->nFields - 1].AccumulatedBytes >
1536 145 : UINT32_MAX - pMMBDXP->pField[pMMBDXP->nFields - 1].BytesPerField)
1537 : {
1538 0 : VSIFree(pMMBDXP->pField);
1539 0 : pMMBDXP->pField = nullptr;
1540 0 : pMMBDXP->nFields = 0;
1541 0 : VSIFCloseL(pf);
1542 0 : pMMBDXP->pfDataBase = nullptr;
1543 0 : return 1;
1544 : }
1545 145 : if (pMMBDXP->pField[pMMBDXP->nFields - 1].BytesPerField +
1546 145 : pMMBDXP->pField[pMMBDXP->nFields - 1].AccumulatedBytes >
1547 145 : pMMBDXP->BytesPerRecord)
1548 0 : incoherent_record_size = TRUE;
1549 : }
1550 145 : if (incoherent_record_size)
1551 : {
1552 0 : if (some_problems_when_reading == 0)
1553 : {
1554 0 : incoherent_record_size = FALSE;
1555 0 : VSIFSeekL(pf, offset_reintent, SEEK_SET);
1556 0 : some_problems_when_reading++;
1557 : /* Reset IdGraficField as it might no longer be valid */
1558 0 : pMMBDXP->IdGraficField = 0;
1559 0 : goto reintenta_lectura_per_si_error_CreaCampBD_XP;
1560 : }
1561 : else
1562 : {
1563 0 : VSIFree(pMMBDXP->pField);
1564 0 : pMMBDXP->pField = nullptr;
1565 0 : pMMBDXP->nFields = 0;
1566 0 : VSIFCloseL(pf);
1567 0 : pMMBDXP->pfDataBase = nullptr;
1568 0 : return 1;
1569 : }
1570 : }
1571 :
1572 145 : offset_possible = 32 + 32 * (pMMBDXP->nFields) + 1;
1573 :
1574 145 : if (!incoherent_record_size &&
1575 145 : offset_possible != pMMBDXP->FirstRecordOffset)
1576 : { // Extended names
1577 : MM_FIRST_RECORD_OFFSET_TYPE offset_nom_camp;
1578 : int mida_nom;
1579 :
1580 370 : for (nIField = 0; nIField < pMMBDXP->nFields; nIField++)
1581 : {
1582 : offset_nom_camp =
1583 332 : MM_GiveOffsetExtendedFieldName(pMMBDXP->pField + nIField);
1584 332 : mida_nom = MM_DonaBytesNomEstesCamp(pMMBDXP->pField + nIField);
1585 332 : if (mida_nom > 0 && mida_nom < MM_MAX_LON_FIELD_NAME_DBF &&
1586 101 : offset_nom_camp >= offset_possible &&
1587 101 : offset_nom_camp < pMMBDXP->FirstRecordOffset)
1588 : {
1589 101 : CPLStrlcpy(pMMBDXP->pField[nIField].ClassicalDBFFieldName,
1590 101 : pMMBDXP->pField[nIField].FieldName,
1591 : MM_MAX_LON_CLASSICAL_FIELD_NAME_DBF);
1592 101 : VSIFSeekL(pf, offset_nom_camp, SEEK_SET);
1593 101 : if (1 != VSIFReadL(pMMBDXP->pField[nIField].FieldName, mida_nom,
1594 : 1, pf))
1595 : {
1596 0 : VSIFree(pMMBDXP->pField);
1597 0 : pMMBDXP->pField = nullptr;
1598 0 : pMMBDXP->nFields = 0;
1599 0 : VSIFCloseL(pf);
1600 0 : pMMBDXP->pfDataBase = nullptr;
1601 0 : return 1;
1602 : }
1603 101 : pMMBDXP->pField[nIField].FieldName[mida_nom] = '\0';
1604 :
1605 : // All field names to UTF-8
1606 101 : if (pMMBDXP->CharSet == MM_JOC_CARAC_ANSI_DBASE)
1607 : {
1608 81 : pszString = CPLRecode(pMMBDXP->pField[nIField].FieldName,
1609 : CPL_ENC_ISO8859_1, CPL_ENC_UTF8);
1610 81 : CPLStrlcpy(pMMBDXP->pField[nIField].FieldName, pszString,
1611 : MM_MAX_LON_FIELD_NAME_DBF);
1612 81 : CPLFree(pszString);
1613 : }
1614 20 : else if (pMMBDXP->CharSet == MM_JOC_CARAC_OEM850_DBASE)
1615 : {
1616 15 : MM_oemansi(pMMBDXP->pField[nIField].FieldName);
1617 15 : pszString = CPLRecode(pMMBDXP->pField[nIField].FieldName,
1618 : CPL_ENC_ISO8859_1, CPL_ENC_UTF8);
1619 15 : CPLStrlcpy(pMMBDXP->pField[nIField].FieldName, pszString,
1620 : MM_MAX_LON_FIELD_NAME_DBF - 1);
1621 15 : CPLFree(pszString);
1622 : }
1623 : }
1624 : }
1625 : }
1626 :
1627 145 : pMMBDXP->IdEntityField = MM_MAX_EXT_DBF_N_FIELDS_TYPE;
1628 145 : return 0;
1629 : } // End of MM_ReadExtendedDBFHeaderFromFile()
1630 :
1631 312 : CPL_DLL void MM_ReleaseDBFHeader(struct MM_DATA_BASE_XP **data_base_XP)
1632 : {
1633 312 : if (!data_base_XP)
1634 0 : return;
1635 312 : if (!*data_base_XP)
1636 0 : return;
1637 :
1638 312 : MM_ReleaseMainFields(*data_base_XP);
1639 312 : VSIFree(*data_base_XP);
1640 312 : *data_base_XP = nullptr;
1641 :
1642 312 : return;
1643 : }
1644 :
1645 576 : CPL_DLL int MM_ModifyFieldNameAndDescriptorIfPresentBD_XP(
1646 : struct MM_FIELD *camp, struct MM_DATA_BASE_XP *bd_xp,
1647 : MM_BOOLEAN no_modifica_descriptor, size_t mida_nom)
1648 : {
1649 : MM_EXT_DBF_N_FIELDS i_camp;
1650 576 : unsigned n_digits_i = 0, i;
1651 576 : int retorn = 0;
1652 :
1653 576 : if (mida_nom == 0)
1654 576 : mida_nom = MM_MAX_LON_FIELD_NAME_DBF;
1655 :
1656 5747 : for (i_camp = 0; i_camp < bd_xp->nFields; i_camp++)
1657 : {
1658 5241 : if (bd_xp->pField + i_camp == camp)
1659 506 : continue;
1660 4735 : if (!strcasecmp(bd_xp->pField[i_camp].FieldName, camp->FieldName))
1661 70 : break;
1662 : }
1663 576 : if (i_camp < bd_xp->nFields)
1664 : {
1665 70 : retorn = 1;
1666 70 : if (strlen(camp->FieldName) > mida_nom - 2)
1667 0 : camp->FieldName[mida_nom - 2] = '\0';
1668 70 : strcat(camp->FieldName, "0");
1669 70 : for (i = 2; i < (size_t)10; i++)
1670 : {
1671 70 : snprintf(camp->FieldName + strlen(camp->FieldName) - 1,
1672 70 : sizeof(camp->FieldName) - strlen(camp->FieldName) + 1,
1673 : "%u", i);
1674 965 : for (i_camp = 0; i_camp < bd_xp->nFields; i_camp++)
1675 : {
1676 895 : if (bd_xp->pField + i_camp == camp)
1677 70 : continue;
1678 825 : if (!strcasecmp(bd_xp->pField[i_camp].FieldName,
1679 825 : camp->FieldName))
1680 0 : break;
1681 : }
1682 70 : if (i_camp == bd_xp->nFields)
1683 : {
1684 70 : n_digits_i = 1;
1685 70 : break;
1686 : }
1687 : }
1688 70 : if (i == 10)
1689 : {
1690 0 : camp->FieldName[strlen(camp->FieldName) - 1] = '\0';
1691 0 : if (strlen(camp->FieldName) > mida_nom - 3)
1692 0 : camp->FieldName[mida_nom - 3] = '\0';
1693 0 : strcat(camp->FieldName, "00");
1694 0 : for (i = 10; i < (size_t)100; i++)
1695 : {
1696 0 : snprintf(camp->FieldName + strlen(camp->FieldName) - 2,
1697 0 : sizeof(camp->FieldName) - strlen(camp->FieldName) + 2,
1698 : "%u", i);
1699 0 : for (i_camp = 0; i_camp < bd_xp->nFields; i_camp++)
1700 : {
1701 0 : if (bd_xp->pField + i_camp == camp)
1702 0 : continue;
1703 0 : if (!strcasecmp(bd_xp->pField[i_camp].FieldName,
1704 0 : camp->FieldName))
1705 0 : break;
1706 : }
1707 0 : if (i_camp == bd_xp->nFields)
1708 : {
1709 0 : n_digits_i = 2;
1710 0 : break;
1711 : }
1712 : }
1713 0 : if (i == 100)
1714 : {
1715 0 : camp->FieldName[strlen(camp->FieldName) - 2] = '\0';
1716 0 : if (strlen(camp->FieldName) > mida_nom - 4)
1717 0 : camp->FieldName[mida_nom - 4] = '\0';
1718 0 : strcat(camp->FieldName, "000");
1719 0 : for (i = 100; i < (size_t)256 + 2; i++)
1720 : {
1721 0 : snprintf(camp->FieldName + strlen(camp->FieldName) - 3,
1722 0 : sizeof(camp->FieldName) - strlen(camp->FieldName) +
1723 : 3,
1724 : "%u", i);
1725 0 : for (i_camp = 0; i_camp < bd_xp->nFields; i_camp++)
1726 : {
1727 0 : if (bd_xp->pField + i_camp == camp)
1728 0 : continue;
1729 0 : if (!strcasecmp(bd_xp->pField[i_camp].FieldName,
1730 0 : camp->FieldName))
1731 0 : break;
1732 : }
1733 0 : if (i_camp == bd_xp->nFields)
1734 : {
1735 0 : n_digits_i = 3;
1736 0 : break;
1737 : }
1738 : }
1739 0 : if (i == 256)
1740 0 : return 2;
1741 : }
1742 : }
1743 : }
1744 : else
1745 : {
1746 506 : i = 1;
1747 : }
1748 :
1749 576 : if ((*(camp->FieldDescription[0]) == '\0') || no_modifica_descriptor)
1750 477 : return retorn;
1751 :
1752 1329 : for (i_camp = 0; i_camp < bd_xp->nFields; i_camp++)
1753 : {
1754 1230 : if (bd_xp->pField + i_camp == camp)
1755 99 : continue;
1756 1131 : if (!strcasecmp(bd_xp->pField[i_camp].FieldDescription[0],
1757 1131 : camp->FieldDescription[0]))
1758 0 : break;
1759 : }
1760 99 : if (i_camp == bd_xp->nFields)
1761 99 : return retorn;
1762 :
1763 0 : if (retorn == 1)
1764 : {
1765 0 : if (strlen(camp->FieldDescription[0]) >
1766 0 : MM_MAX_LON_DESCRIPCIO_CAMP_DBF - 4 - n_digits_i)
1767 0 : camp->FieldDescription[0][mida_nom - 4 - n_digits_i] = '\0';
1768 :
1769 0 : snprintf(camp->FieldDescription[0] + strlen(camp->FieldDescription[0]),
1770 : sizeof(camp->FieldDescription[0]) -
1771 0 : strlen(camp->FieldDescription[0]),
1772 : " (%u)", i);
1773 0 : for (i_camp = 0; i_camp < bd_xp->nFields; i_camp++)
1774 : {
1775 0 : if (bd_xp->pField + i_camp == camp)
1776 0 : continue;
1777 0 : if (!strcasecmp(bd_xp->pField[i_camp].FieldDescription[0],
1778 0 : camp->FieldDescription[0]))
1779 0 : break;
1780 : }
1781 0 : if (i_camp == bd_xp->nFields)
1782 0 : return retorn;
1783 : }
1784 :
1785 0 : retorn = 1;
1786 0 : if (strlen(camp->FieldDescription[0]) >
1787 0 : MM_MAX_LON_DESCRIPCIO_CAMP_DBF - 4 - n_digits_i)
1788 0 : camp->FieldDescription[0][mida_nom - 4 - n_digits_i] = '\0';
1789 0 : camp->FieldDescription[0][strlen(camp->FieldDescription[0]) - 4 -
1790 0 : n_digits_i + 1] = '\0';
1791 0 : if (strlen(camp->FieldDescription[0]) > MM_MAX_LON_DESCRIPCIO_CAMP_DBF - 7)
1792 0 : camp->FieldDescription[0][mida_nom - 7] = '\0';
1793 0 : for (i++; i < (size_t)256; i++)
1794 : {
1795 : //if (camp->FieldDescription[0] + strlen(camp->FieldDescription[0]))
1796 0 : snprintf(camp->FieldDescription[0] + strlen(camp->FieldDescription[0]),
1797 : sizeof(camp->FieldDescription[0]) -
1798 0 : strlen(camp->FieldDescription[0]),
1799 : " (%u)", i);
1800 0 : for (i_camp = 0; i_camp < bd_xp->nFields; i_camp++)
1801 : {
1802 0 : if (bd_xp->pField + i_camp == camp)
1803 0 : continue;
1804 0 : if (!strcasecmp(bd_xp->pField[i_camp].FieldName, camp->FieldName))
1805 0 : break;
1806 : }
1807 0 : if (i_camp == bd_xp->nFields)
1808 0 : return retorn;
1809 : }
1810 0 : return 2;
1811 : } // End of MM_ModifyFieldNameAndDescriptorIfPresentBD_XP()
1812 :
1813 576 : static int MM_DuplicateMultilingualString(
1814 : char *(szChain_final[MM_NUM_IDIOMES_MD_MULTIDIOMA]),
1815 : const char *const(szChain_inicial[MM_NUM_IDIOMES_MD_MULTIDIOMA]))
1816 : {
1817 : size_t i;
1818 :
1819 2880 : for (i = 0; i < MM_NUM_IDIOMES_MD_MULTIDIOMA; i++)
1820 : {
1821 2304 : if (szChain_inicial[i])
1822 : {
1823 0 : if (nullptr == (szChain_final[i] = strdup(szChain_inicial[i])))
1824 0 : return 1;
1825 : }
1826 : else
1827 2304 : szChain_final[i] = nullptr;
1828 : }
1829 576 : return 0;
1830 : }
1831 :
1832 576 : CPL_DLL int MM_DuplicateFieldDBXP(struct MM_FIELD *camp_final,
1833 : const struct MM_FIELD *camp_inicial)
1834 : {
1835 576 : *camp_final = *camp_inicial;
1836 :
1837 576 : if (0 != MM_DuplicateMultilingualString(
1838 576 : camp_final->Separator,
1839 576 : (const char *const(*))camp_inicial->Separator))
1840 0 : return 1;
1841 :
1842 576 : return 0;
1843 : }
1844 :
1845 : // If n_bytes==SIZE_MAX, the parameter is ignored ant, then,
1846 : // it's assumed that szszChain is NUL terminated
1847 2715 : CPL_DLL char *MM_oemansi_n(char *szszChain, size_t n_bytes)
1848 : {
1849 : size_t u_i;
1850 : unsigned char *punter_bait;
1851 2715 : unsigned char t_oemansi[128] = {
1852 : 199, 252, 233, 226, 228, 224, 229, 231, 234, 235, 232, 239, 238,
1853 : 236, 196, 197, 201, 230, 198, 244, 246, 242, 251, 249, 255, 214,
1854 : 220, 248, 163, 216, 215, 131, 225, 237, 243, 250, 241, 209, 170,
1855 : 186, 191, 174, 172, 189, 188, 161, 171, 187, 164, 164, 164, 166,
1856 : 166, 193, 194, 192, 169, 166, 166, 164, 164, 162, 165, 164, 164,
1857 : 164, 164, 164, 164, 164, 227, 195, 164, 164, 164, 164, 166, 164,
1858 : 164, 164, 240, 208, 202, 203, 200, 180, 205, 206, 207, 164, 164,
1859 : 164, 164, 166, 204, 164, 211, 223, 212, 210, 245, 213, 181, 254,
1860 : 222, 218, 219, 217, 253, 221, 175, 180, 173, 177, 164, 190, 182,
1861 : 167, 247, 184, 176, 168, 183, 185, 179, 178, 164, 183};
1862 2715 : if (n_bytes == SIZE_MAX)
1863 : {
1864 27997 : for (punter_bait = (unsigned char *)szszChain; *punter_bait;
1865 25430 : punter_bait++)
1866 : {
1867 25430 : if (*punter_bait > 127)
1868 310 : *punter_bait = t_oemansi[*punter_bait - 128];
1869 : }
1870 : }
1871 : else
1872 : {
1873 2056 : for (u_i = 0, punter_bait = (unsigned char *)szszChain; u_i < n_bytes;
1874 1908 : punter_bait++, u_i++)
1875 : {
1876 1908 : if (*punter_bait > 127)
1877 0 : *punter_bait = t_oemansi[*punter_bait - 128];
1878 : }
1879 : }
1880 2715 : return szszChain;
1881 : }
1882 :
1883 : // An implementation of non-sensitive strstr()
1884 1408 : CPL_DLL char *MM_stristr(const char *haystack, const char *needle)
1885 : {
1886 1408 : if (!haystack)
1887 0 : return nullptr;
1888 :
1889 1408 : if (!needle)
1890 0 : return nullptr;
1891 :
1892 1408 : if (!*needle)
1893 0 : return (char *)haystack;
1894 :
1895 1408 : char *p1 = (char *)haystack;
1896 28772 : while (*p1 != '\0' && !EQUALN(p1, needle, strlen(needle)))
1897 27364 : p1++;
1898 :
1899 1408 : if (*p1 == '\0')
1900 501 : return nullptr;
1901 :
1902 907 : return p1;
1903 : }
1904 :
1905 2567 : CPL_DLL char *MM_oemansi(char *szszChain)
1906 : {
1907 2567 : return MM_oemansi_n(szszChain, SIZE_MAX);
1908 : }
1909 :
1910 : CPL_DLL int
1911 1333 : MM_SecureCopyStringFieldValue(char **pszStringDst, const char *pszStringSrc,
1912 : MM_EXT_DBF_N_FIELDS *nStringCurrentLength)
1913 : {
1914 :
1915 1333 : if (!pszStringSrc)
1916 : {
1917 0 : if (1 >= *nStringCurrentLength)
1918 : {
1919 0 : void *new_ptr = VSIRealloc(*pszStringDst, 2);
1920 0 : if (!new_ptr)
1921 0 : return 1;
1922 0 : *pszStringDst = new_ptr;
1923 0 : *nStringCurrentLength = (MM_EXT_DBF_N_FIELDS)2;
1924 : }
1925 0 : strcpy(*pszStringDst, "\0");
1926 0 : return 0;
1927 : }
1928 :
1929 1333 : if (strlen(pszStringSrc) >= *nStringCurrentLength)
1930 : {
1931 446 : void *new_ptr = VSIRealloc(*pszStringDst, strlen(pszStringSrc) + 1);
1932 446 : if (!new_ptr)
1933 0 : return 1;
1934 446 : (*pszStringDst) = new_ptr;
1935 446 : *nStringCurrentLength = (MM_EXT_DBF_N_FIELDS)(strlen(pszStringSrc) + 1);
1936 : }
1937 1333 : strcpy(*pszStringDst, pszStringSrc);
1938 1333 : return 0;
1939 : }
1940 :
1941 : // This function assumes that all the file is saved in disk and closed.
1942 117 : CPL_DLL int MM_ChangeDBFWidthField(struct MM_DATA_BASE_XP *data_base_XP,
1943 : MM_EXT_DBF_N_FIELDS nIField,
1944 : MM_BYTES_PER_FIELD_TYPE_DBF nNewWidth,
1945 : MM_BYTE nNewPrecision)
1946 : {
1947 117 : char *record, *whites = nullptr;
1948 : MM_BYTES_PER_FIELD_TYPE_DBF l_glop1, l_glop2, i_glop2;
1949 : MM_EXT_DBF_N_RECORDS nfitx, i_reg;
1950 : int canvi_amplada; // change width
1951 : GInt32 j;
1952 : MM_EXT_DBF_N_FIELDS i_camp;
1953 : size_t retorn_fwrite;
1954 : int retorn_TruncaFitxer;
1955 :
1956 117 : if (!data_base_XP)
1957 0 : return 1;
1958 :
1959 117 : canvi_amplada = nNewWidth - data_base_XP->pField[nIField].BytesPerField;
1960 :
1961 117 : if (data_base_XP->nRecords != 0)
1962 : {
1963 48 : l_glop1 = data_base_XP->pField[nIField].AccumulatedBytes;
1964 48 : i_glop2 = l_glop1 + data_base_XP->pField[nIField].BytesPerField;
1965 48 : if (nIField == data_base_XP->nFields - 1)
1966 26 : l_glop2 = 0;
1967 : else
1968 22 : l_glop2 = data_base_XP->BytesPerRecord -
1969 22 : data_base_XP->pField[nIField + 1].AccumulatedBytes;
1970 :
1971 48 : if ((record = VSICalloc(1, (size_t)data_base_XP->BytesPerRecord)) ==
1972 : nullptr)
1973 0 : return 1;
1974 :
1975 48 : record[data_base_XP->BytesPerRecord - 1] = MM_SetEndOfString;
1976 :
1977 48 : if ((whites = (char *)VSICalloc(1, (size_t)nNewWidth)) == nullptr)
1978 : {
1979 0 : VSIFree(record);
1980 0 : return 1;
1981 : }
1982 48 : memset(whites, ' ', nNewWidth);
1983 :
1984 48 : nfitx = data_base_XP->nRecords;
1985 48 : i_reg = (canvi_amplada < 0 ? 0 : nfitx - 1);
1986 : while (TRUE)
1987 : {
1988 48 : if (0 != VSIFSeekL(data_base_XP->pfDataBase,
1989 48 : data_base_XP->FirstRecordOffset +
1990 48 : (MM_FILE_OFFSET)i_reg *
1991 48 : data_base_XP->BytesPerRecord,
1992 : SEEK_SET))
1993 : {
1994 0 : VSIFree(whites);
1995 0 : VSIFree(record);
1996 0 : return 1;
1997 : }
1998 :
1999 48 : if (1 != VSIFReadL(record, data_base_XP->BytesPerRecord, 1,
2000 : data_base_XP->pfDataBase))
2001 : {
2002 0 : VSIFree(whites);
2003 0 : VSIFree(record);
2004 0 : return 1;
2005 : }
2006 :
2007 48 : if (0 !=
2008 48 : VSIFSeekL(
2009 : data_base_XP->pfDataBase,
2010 48 : (MM_FILE_OFFSET)data_base_XP->FirstRecordOffset +
2011 48 : i_reg * ((MM_FILE_OFFSET)data_base_XP->BytesPerRecord +
2012 : canvi_amplada),
2013 : SEEK_SET))
2014 : {
2015 0 : VSIFree(whites);
2016 0 : VSIFree(record);
2017 0 : return 1;
2018 : }
2019 :
2020 48 : if (1 != VSIFWriteL(record, l_glop1, 1, data_base_XP->pfDataBase))
2021 : {
2022 0 : VSIFree(whites);
2023 0 : VSIFree(record);
2024 0 : return 1;
2025 : }
2026 :
2027 48 : switch (data_base_XP->pField[nIField].FieldType)
2028 : {
2029 30 : case 'C':
2030 : case 'L':
2031 30 : memcpy(whites, record + l_glop1,
2032 : (canvi_amplada < 0
2033 : ? nNewWidth
2034 30 : : data_base_XP->pField[nIField].BytesPerField));
2035 30 : retorn_fwrite = VSIFWriteL(whites, nNewWidth, 1,
2036 : data_base_XP->pfDataBase);
2037 :
2038 30 : if (1 != retorn_fwrite)
2039 : {
2040 0 : VSIFree(whites);
2041 0 : VSIFree(record);
2042 0 : return 1;
2043 : }
2044 30 : break;
2045 18 : case 'N':
2046 :
2047 18 : if (canvi_amplada >= 0)
2048 : {
2049 18 : if (1 != VSIFWriteL(whites, canvi_amplada, 1,
2050 18 : data_base_XP->pfDataBase) ||
2051 : 1 !=
2052 18 : VSIFWriteL(
2053 18 : record + l_glop1,
2054 18 : data_base_XP->pField[nIField].BytesPerField,
2055 : 1, data_base_XP->pfDataBase))
2056 : {
2057 0 : VSIFree(whites);
2058 0 : VSIFree(record);
2059 0 : return 1;
2060 : }
2061 : }
2062 0 : else if (canvi_amplada < 0)
2063 : {
2064 0 : j = (GInt32)(l_glop1 + (data_base_XP->pField[nIField]
2065 0 : .BytesPerField -
2066 : 1));
2067 : while (TRUE)
2068 : {
2069 0 : j--;
2070 :
2071 0 : if (j < (GInt32)l_glop1 || record[j] == ' ')
2072 : {
2073 0 : j++;
2074 0 : break;
2075 : }
2076 : }
2077 :
2078 0 : if ((data_base_XP->pField[nIField].BytesPerField +
2079 0 : l_glop1 - j) < nNewWidth)
2080 0 : j -= (GInt32)(nNewWidth -
2081 0 : (data_base_XP->pField[nIField]
2082 0 : .BytesPerField +
2083 : l_glop1 - j));
2084 :
2085 0 : retorn_fwrite = VSIFWriteL(record + j, nNewWidth, 1,
2086 : data_base_XP->pfDataBase);
2087 0 : if (1 != retorn_fwrite)
2088 : {
2089 0 : VSIFree(whites);
2090 0 : VSIFree(record);
2091 0 : return 1;
2092 : }
2093 : }
2094 :
2095 18 : break;
2096 0 : default:
2097 0 : VSIFree(whites);
2098 0 : VSIFree(record);
2099 0 : return 1;
2100 : }
2101 48 : if (l_glop2)
2102 : {
2103 22 : retorn_fwrite = VSIFWriteL(record + i_glop2, l_glop2, 1,
2104 : data_base_XP->pfDataBase);
2105 22 : if (1 != retorn_fwrite)
2106 : {
2107 0 : VSIFree(whites);
2108 0 : VSIFree(record);
2109 0 : return 1;
2110 : }
2111 : }
2112 :
2113 48 : if (canvi_amplada < 0)
2114 : {
2115 0 : if (i_reg + 1 == nfitx)
2116 0 : break;
2117 0 : i_reg++;
2118 : }
2119 : else
2120 : {
2121 48 : if (i_reg == 0)
2122 48 : break;
2123 0 : i_reg--;
2124 : }
2125 : }
2126 :
2127 48 : VSIFree(whites);
2128 48 : VSIFree(record);
2129 :
2130 48 : retorn_TruncaFitxer = VSIFTruncateL(
2131 : data_base_XP->pfDataBase,
2132 48 : (MM_FILE_OFFSET)data_base_XP->FirstRecordOffset +
2133 48 : (MM_FILE_OFFSET)data_base_XP->nRecords *
2134 48 : ((MM_FILE_OFFSET)data_base_XP->BytesPerRecord +
2135 : canvi_amplada));
2136 48 : if (canvi_amplada < 0 && retorn_TruncaFitxer)
2137 0 : return 1;
2138 : } /* Fi de registres de != 0*/
2139 :
2140 117 : if (canvi_amplada != 0)
2141 : {
2142 117 : data_base_XP->pField[nIField].BytesPerField = nNewWidth;
2143 117 : data_base_XP->BytesPerRecord += canvi_amplada;
2144 117 : for (i_camp = (MM_EXT_DBF_N_FIELDS)(nIField + 1);
2145 477 : i_camp < data_base_XP->nFields; i_camp++)
2146 360 : data_base_XP->pField[i_camp].AccumulatedBytes += canvi_amplada;
2147 : }
2148 117 : data_base_XP->pField[nIField].DecimalsIfFloat = nNewPrecision;
2149 :
2150 117 : if ((MM_OpenIfNeededAndUpdateEntireHeader(data_base_XP)) == FALSE)
2151 0 : return 1;
2152 :
2153 117 : return 0;
2154 : } /* End of MMChangeCFieldWidthDBF() */
2155 :
2156 15872 : static char *MM_l_RemoveWhitespacesFromEndOfString(char *punter,
2157 : size_t l_szChain)
2158 : {
2159 15872 : size_t longitud_szChain = l_szChain;
2160 35838 : while (longitud_szChain > 0)
2161 : {
2162 35414 : longitud_szChain--;
2163 35414 : if (punter[longitud_szChain] != ' ' && punter[longitud_szChain] != '\t')
2164 : {
2165 15448 : break;
2166 : }
2167 19966 : punter[longitud_szChain] = '\0';
2168 : }
2169 15872 : return punter;
2170 : }
2171 :
2172 50 : CPL_DLL char *MM_RemoveInitial_and_FinalQuotationMarks(char *szChain)
2173 : {
2174 : char *ptr1, *ptr2;
2175 50 : char cometa = '"';
2176 :
2177 50 : if (*szChain == cometa)
2178 : {
2179 11 : ptr1 = szChain;
2180 11 : ptr2 = ptr1 + 1;
2181 11 : if (*ptr2)
2182 : {
2183 182 : while (*ptr2)
2184 : {
2185 171 : *ptr1 = *ptr2;
2186 171 : ptr1++;
2187 171 : ptr2++;
2188 : }
2189 11 : if (*ptr1 == cometa)
2190 11 : *(ptr1 - 1) = 0;
2191 : else
2192 0 : *ptr1 = 0;
2193 : }
2194 : }
2195 50 : return szChain;
2196 : } /* End of MM_RemoveInitial_and_FinalQuotationMarks() */
2197 :
2198 84 : CPL_DLL char *MM_RemoveLeadingWhitespaceOfString(char *szChain)
2199 : {
2200 : char *ptr;
2201 : char *ptr2;
2202 :
2203 84 : if (szChain == nullptr)
2204 0 : return szChain;
2205 :
2206 630 : for (ptr = szChain; *ptr && (*ptr == ' ' || *ptr == '\t'); ptr++)
2207 546 : continue;
2208 :
2209 84 : if (ptr != szChain)
2210 : {
2211 66 : ptr2 = szChain;
2212 534 : while (*ptr)
2213 : {
2214 468 : *ptr2 = *ptr;
2215 468 : ptr2++;
2216 468 : ptr++;
2217 : }
2218 66 : *ptr2 = 0;
2219 : }
2220 84 : return szChain;
2221 : }
2222 :
2223 : // Checks if a string is empty
2224 6460 : CPL_DLL int MMIsEmptyString(const char *string)
2225 : {
2226 6460 : const char *ptr = string;
2227 :
2228 15105 : for (; *ptr; ptr++)
2229 14420 : if (*ptr != ' ' && *ptr != '\t')
2230 5775 : return 0;
2231 :
2232 685 : return 1;
2233 : }
2234 :
2235 15872 : CPL_DLL char *MM_RemoveWhitespacesFromEndOfString(char *str)
2236 : {
2237 15872 : if (str == nullptr)
2238 0 : return str;
2239 15872 : return MM_l_RemoveWhitespacesFromEndOfString(str, strlen(str));
2240 : }
2241 :
2242 113 : CPL_DLL struct MM_ID_GRAFIC_MULTIPLE_RECORD *MMCreateExtendedDBFIndex(
2243 : VSILFILE *f, MM_EXT_DBF_N_RECORDS nNumberOfRecords,
2244 : MM_FIRST_RECORD_OFFSET_TYPE offset_1era,
2245 : MM_ACCUMULATED_BYTES_TYPE_DBF bytes_per_fitxa,
2246 : MM_ACCUMULATED_BYTES_TYPE_DBF bytes_acumulats_id_grafic,
2247 : MM_BYTES_PER_FIELD_TYPE_DBF bytes_id_grafic, MM_BOOLEAN *isListField,
2248 : MM_EXT_DBF_N_RECORDS *nMaxN)
2249 : {
2250 : struct MM_ID_GRAFIC_MULTIPLE_RECORD *id;
2251 : MM_EXT_DBF_N_RECORDS i_dbf;
2252 : MM_EXT_DBF_SIGNED_N_RECORDS i, id_grafic;
2253 : char *fitxa;
2254 113 : MM_BYTES_PER_FIELD_TYPE_DBF bytes_final_id_principi_id1 =
2255 : bytes_per_fitxa - bytes_id_grafic;
2256 :
2257 113 : *isListField = FALSE;
2258 113 : *nMaxN = 0;
2259 113 : if (!nNumberOfRecords)
2260 9 : return nullptr; // No elements to read
2261 :
2262 104 : if (MMCheckSize_t(nNumberOfRecords, sizeof(*id)))
2263 0 : return nullptr;
2264 104 : if (nullptr == (id = (struct MM_ID_GRAFIC_MULTIPLE_RECORD *)VSICalloc(
2265 : (size_t)nNumberOfRecords, sizeof(*id))))
2266 0 : return nullptr;
2267 :
2268 104 : if (bytes_id_grafic == UINT32_MAX)
2269 : {
2270 0 : VSIFree(id);
2271 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Overflow in bytes_id_graphic");
2272 0 : return nullptr;
2273 : }
2274 :
2275 104 : if (nullptr == (fitxa = (char *)VSICalloc(1, (size_t)bytes_id_grafic + 1)))
2276 : {
2277 0 : VSIFree(id);
2278 0 : return nullptr;
2279 : }
2280 104 : fitxa[bytes_id_grafic] = '\0';
2281 :
2282 104 : VSIFSeekL(f,
2283 104 : (MM_FILE_OFFSET)offset_1era +
2284 104 : (MM_FILE_OFFSET)bytes_acumulats_id_grafic,
2285 : SEEK_SET);
2286 :
2287 104 : i_dbf = 0;
2288 : do
2289 : {
2290 104 : if (i_dbf == nNumberOfRecords ||
2291 104 : VSIFReadL(fitxa, 1, bytes_id_grafic, f) != (size_t)bytes_id_grafic)
2292 : {
2293 0 : VSIFree(id);
2294 0 : VSIFree(fitxa);
2295 0 : return nullptr;
2296 : }
2297 104 : i_dbf++;
2298 : } while (1 !=
2299 208 : sscanf(fitxa, scanf_MM_EXT_DBF_SIGNED_N_RECORDS, &id_grafic) ||
2300 104 : id_grafic < 0);
2301 104 : i = 0;
2302 :
2303 : while (TRUE)
2304 : {
2305 560 : if (i > id_grafic)
2306 : {
2307 0 : VSIFree(id);
2308 0 : VSIFree(fitxa);
2309 0 : return nullptr;
2310 : }
2311 560 : i = id_grafic;
2312 560 : if (i >= (MM_EXT_DBF_SIGNED_N_RECORDS)nNumberOfRecords)
2313 : {
2314 0 : VSIFree(fitxa);
2315 0 : return id;
2316 : }
2317 560 : id[(size_t)i].offset = (MM_FILE_OFFSET)offset_1era +
2318 560 : (MM_FILE_OFFSET)(i_dbf - 1) * bytes_per_fitxa;
2319 : do
2320 : {
2321 602 : id[(size_t)i].nMR++;
2322 602 : if (!(*isListField) && id[(size_t)i].nMR > 1)
2323 33 : *isListField = TRUE;
2324 602 : if (*nMaxN < id[(size_t)i].nMR)
2325 141 : *nMaxN = id[(size_t)i].nMR;
2326 :
2327 602 : if (i_dbf == nNumberOfRecords)
2328 : {
2329 104 : VSIFree(fitxa);
2330 104 : return id;
2331 : }
2332 498 : VSIFSeekL(f, bytes_final_id_principi_id1, SEEK_CUR);
2333 498 : if (VSIFReadL(fitxa, 1, bytes_id_grafic, f) !=
2334 : (size_t)bytes_id_grafic)
2335 : {
2336 0 : VSIFree(id);
2337 0 : VSIFree(fitxa);
2338 0 : return nullptr;
2339 : }
2340 498 : if (1 != sscanf(fitxa, scanf_MM_EXT_DBF_SIGNED_N_RECORDS,
2341 498 : &id_grafic) ||
2342 498 : id_grafic >= (MM_EXT_DBF_SIGNED_N_RECORDS)nNumberOfRecords)
2343 : {
2344 0 : VSIFree(fitxa);
2345 0 : return id;
2346 : }
2347 498 : i_dbf++;
2348 498 : } while (id_grafic == i);
2349 : }
2350 : } // End of MMCreateExtendedDBFIndex()
2351 :
2352 : // READING/CREATING MIRAMON METADATA
2353 : // Returns the value of an INI file. Used to read MiraMon metadata
2354 6473 : CPL_DLL char *MMReturnValueFromSectionINIFile(const char *filename,
2355 : const char *section,
2356 : const char *key)
2357 : {
2358 6473 : char *value = nullptr;
2359 : const char *pszLine;
2360 6473 : char *section_header = nullptr;
2361 6473 : size_t key_len = 0;
2362 :
2363 6473 : VSILFILE *file = VSIFOpenL(filename, "rb");
2364 6473 : if (file == nullptr)
2365 : {
2366 0 : CPLError(CE_Failure, CPLE_OpenFailed, "Cannot open INI file %s.",
2367 : filename);
2368 0 : return nullptr;
2369 : }
2370 :
2371 6473 : if (key)
2372 6187 : key_len = strlen(key);
2373 :
2374 459723 : while ((pszLine = CPLReadLine2L(file, 10000, nullptr)) != nullptr)
2375 : {
2376 455608 : char *pszString = CPLRecode(pszLine, CPL_ENC_ISO8859_1, CPL_ENC_UTF8);
2377 :
2378 : // Skip comments and empty lines
2379 455608 : if (*pszString == ';' || *pszString == '#' || *pszString == '\n' ||
2380 455608 : *pszString == '\r')
2381 : {
2382 0 : VSIFree(pszString);
2383 : // Move to next line
2384 0 : continue;
2385 : }
2386 :
2387 : // Check for section header
2388 455608 : if (*pszString == '[')
2389 : {
2390 96334 : char *section_end = strchr(pszString, ']');
2391 96334 : if (section_end != nullptr)
2392 : {
2393 96334 : *section_end = '\0'; // Terminate the string at ']'
2394 96334 : if (section_header)
2395 89862 : VSIFree(section_header);
2396 96334 : section_header = CPLStrdup(pszString + 1); // Skip the '['
2397 : }
2398 96334 : VSIFree(pszString);
2399 96334 : continue;
2400 : }
2401 :
2402 359274 : if (key)
2403 : {
2404 : // If the current line belongs to the desired section
2405 358989 : if (section_header != nullptr &&
2406 358989 : strcmp(section_header, section) == 0)
2407 : {
2408 : // Check if the line contains the desired key
2409 12904 : if (strncmp(pszString, key, key_len) == 0 &&
2410 2499 : pszString[key_len] == '=')
2411 : {
2412 : // Extract the value
2413 2073 : char *value_start = pszString + key_len + 1;
2414 2073 : char *value_end = strstr(value_start, "\r\n");
2415 2073 : if (value_end != nullptr)
2416 : {
2417 0 : *value_end =
2418 : '\0'; // Terminate the string at newline character if found
2419 : }
2420 : else
2421 : {
2422 2073 : value_end = strstr(value_start, "\n");
2423 2073 : if (value_end != nullptr)
2424 : {
2425 0 : *value_end =
2426 : '\0'; // Terminate the string at newline character if found
2427 : }
2428 : else
2429 : {
2430 2073 : value_end = strstr(value_start, "\r");
2431 2073 : if (value_end != nullptr)
2432 : {
2433 0 : *value_end =
2434 : '\0'; // Terminate the string at newline character if found
2435 : }
2436 : }
2437 : }
2438 :
2439 2073 : VSIFree(value);
2440 2073 : value = CPLStrdup(value_start);
2441 2073 : VSIFCloseL(file);
2442 2073 : VSIFree(section_header); // Free allocated memory
2443 2073 : VSIFree(pszString);
2444 2073 : return value;
2445 : }
2446 : }
2447 : }
2448 : else
2449 : {
2450 285 : VSIFree(value);
2451 285 : value = nullptr;
2452 285 : if (section_header)
2453 : {
2454 285 : if (!strcmp(section_header, section))
2455 : {
2456 285 : value = section_header; // Freed out
2457 285 : section_header = nullptr;
2458 : }
2459 : }
2460 :
2461 285 : VSIFCloseL(file);
2462 285 : VSIFree(pszString);
2463 285 : VSIFree(section_header);
2464 285 : return value;
2465 : }
2466 356916 : VSIFree(pszString);
2467 : }
2468 :
2469 4115 : if (section_header)
2470 4114 : VSIFree(section_header); // Free allocated memory
2471 4115 : VSIFCloseL(file);
2472 4115 : return value;
2473 : }
2474 :
2475 : // Retrieves EPSG codes from a CSV file based on provided geodetic identifiers.
2476 274 : CPL_DLL int MMReturnCodeFromMM_m_idofic(const char *pMMSRS_or_pSRS,
2477 : char *szResult, MM_BYTE direction)
2478 : {
2479 274 : char *aMMIDDBFFile = nullptr; //m_idofic.dbf
2480 274 : VSILFILE *pfMMSRS = nullptr;
2481 : const char *pszLine;
2482 : size_t nLong;
2483 : char *id_geodes, *psidgeodes, *epsg;
2484 :
2485 274 : if (!pMMSRS_or_pSRS)
2486 : {
2487 71 : return 1;
2488 : }
2489 :
2490 : {
2491 : #ifdef USE_ONLY_EMBEDDED_RESOURCE_FILES
2492 : const char *pszFilename = nullptr;
2493 : #else
2494 203 : const char *pszFilename = CPLFindFile("gdal", "MM_m_idofic.csv");
2495 : #endif
2496 : #ifdef EMBED_RESOURCE_FILES
2497 : if (!pszFilename || EQUAL(pszFilename, "MM_m_idofic.csv"))
2498 : {
2499 : pfMMSRS = VSIFileFromMemBuffer(
2500 : nullptr, (GByte *)(MiraMonGetMM_m_idofic_csv()),
2501 : (int)(strlen(MiraMonGetMM_m_idofic_csv())),
2502 : /* bTakeOwnership = */ false);
2503 : }
2504 : else
2505 : #endif
2506 203 : if (pszFilename)
2507 : {
2508 203 : aMMIDDBFFile = CPLStrdup(pszFilename);
2509 : }
2510 : }
2511 :
2512 : #ifdef EMBED_RESOURCE_FILES
2513 : if (!pfMMSRS)
2514 : #endif
2515 : {
2516 203 : if (!aMMIDDBFFile)
2517 : {
2518 0 : CPLError(CE_Failure, CPLE_OpenFailed,
2519 : "Error opening data\\MM_m_idofic.csv.\n");
2520 0 : return 1;
2521 : }
2522 :
2523 : // Opening the file with SRS information
2524 203 : if (nullptr == (pfMMSRS = VSIFOpenL(aMMIDDBFFile, "r")))
2525 : {
2526 0 : VSIFree(aMMIDDBFFile);
2527 0 : CPLError(CE_Failure, CPLE_OpenFailed,
2528 : "Error opening data\\MM_m_idofic.csv.\n");
2529 0 : return 1;
2530 : }
2531 203 : VSIFree(aMMIDDBFFile);
2532 : }
2533 :
2534 : // Checking the header of the csv file
2535 203 : pszLine = CPLReadLine2L(pfMMSRS, 10000, nullptr);
2536 :
2537 203 : if (!pszLine)
2538 :
2539 : {
2540 0 : VSIFCloseL(pfMMSRS);
2541 0 : CPLError(CE_Failure, CPLE_NotSupported,
2542 : "Wrong format in data\\MM_m_idofic.csv.\n");
2543 0 : return 1;
2544 : }
2545 203 : id_geodes = MM_stristr(pszLine, "ID_GEODES");
2546 203 : if (!id_geodes)
2547 : {
2548 0 : VSIFCloseL(pfMMSRS);
2549 0 : CPLError(CE_Failure, CPLE_NotSupported,
2550 : "Wrong format in data\\MM_m_idofic.csv.\n");
2551 0 : return 1;
2552 : }
2553 203 : id_geodes[strlen("ID_GEODES")] = '\0';
2554 203 : psidgeodes = MM_stristr(pszLine, "PSIDGEODES");
2555 203 : if (!psidgeodes)
2556 : {
2557 0 : VSIFCloseL(pfMMSRS);
2558 0 : CPLError(CE_Failure, CPLE_NotSupported,
2559 : "Wrong format in data\\MM_m_idofic.csv.\n");
2560 0 : return 1;
2561 : }
2562 203 : psidgeodes[strlen("PSIDGEODES")] = '\0';
2563 :
2564 : // Is PSIDGEODES in first place?
2565 203 : if (strncmp(pszLine, psidgeodes, strlen("PSIDGEODES")))
2566 : {
2567 0 : VSIFCloseL(pfMMSRS);
2568 0 : CPLError(CE_Failure, CPLE_NotSupported,
2569 : "Wrong format in data\\MM_m_idofic.csv.\n");
2570 0 : return 1;
2571 : }
2572 : // Is ID_GEODES after PSIDGEODES?
2573 203 : if (strncmp(pszLine + strlen("PSIDGEODES") + 1, "ID_GEODES",
2574 : strlen("ID_GEODES")))
2575 : {
2576 0 : VSIFCloseL(pfMMSRS);
2577 0 : CPLError(CE_Failure, CPLE_NotSupported,
2578 : "Wrong format in data\\MM_m_idofic.csv.\n");
2579 0 : return 1;
2580 : }
2581 :
2582 : // Looking for the information.
2583 49932 : while ((pszLine = CPLReadLine2L(pfMMSRS, 10000, nullptr)) != nullptr)
2584 : {
2585 49870 : id_geodes = strstr(pszLine, ";");
2586 49870 : if (!id_geodes)
2587 : {
2588 0 : VSIFCloseL(pfMMSRS);
2589 0 : CPLError(CE_Failure, CPLE_NotSupported,
2590 : "Wrong format in data\\MM_m_idofic.csv.\n");
2591 0 : return 1;
2592 : }
2593 :
2594 49870 : psidgeodes = strstr(id_geodes + 1, ";");
2595 49870 : if (!psidgeodes)
2596 : {
2597 0 : VSIFCloseL(pfMMSRS);
2598 0 : CPLError(CE_Failure, CPLE_NotSupported,
2599 : "Wrong format in data\\MM_m_idofic.csv.\n");
2600 0 : return 1;
2601 : }
2602 :
2603 49870 : id_geodes[(ptrdiff_t)psidgeodes - (ptrdiff_t)id_geodes] = '\0';
2604 49870 : psidgeodes = CPLStrdup(pszLine);
2605 49870 : psidgeodes[(ptrdiff_t)id_geodes - (ptrdiff_t)pszLine] = '\0';
2606 49870 : id_geodes++;
2607 :
2608 49870 : if (direction == EPSG_FROM_MMSRS)
2609 : {
2610 : // I have pMMSRS and I want pSRS
2611 45430 : if (strcmp(pMMSRS_or_pSRS, id_geodes))
2612 : {
2613 45310 : VSIFree(psidgeodes);
2614 45310 : continue;
2615 : }
2616 :
2617 120 : epsg = strstr(psidgeodes, "EPSG:");
2618 120 : nLong = strlen("EPSG:");
2619 120 : if (epsg && !strncmp(epsg, psidgeodes, nLong))
2620 : {
2621 120 : if (epsg[nLong] != '\0')
2622 : {
2623 120 : strcpy(szResult, epsg + nLong);
2624 120 : VSIFree(psidgeodes);
2625 120 : VSIFCloseL(pfMMSRS);
2626 120 : return 0; // found
2627 : }
2628 : else
2629 : {
2630 0 : VSIFCloseL(pfMMSRS);
2631 0 : *szResult = '\0';
2632 0 : VSIFree(psidgeodes);
2633 0 : return 1; // not found
2634 : }
2635 : }
2636 : }
2637 : else
2638 : {
2639 : // I have pSRS and I want pMMSRS
2640 4440 : epsg = strstr(psidgeodes, "EPSG:");
2641 4440 : nLong = strlen("EPSG:");
2642 4440 : if (epsg && !strncmp(epsg, psidgeodes, nLong))
2643 : {
2644 3483 : if (epsg[nLong] != '\0')
2645 : {
2646 3483 : if (!strcmp(pMMSRS_or_pSRS, epsg + nLong))
2647 : {
2648 21 : strcpy(szResult, id_geodes);
2649 21 : VSIFCloseL(pfMMSRS);
2650 21 : VSIFree(psidgeodes);
2651 21 : return 0; // found
2652 : }
2653 : }
2654 : }
2655 : }
2656 4419 : VSIFree(psidgeodes);
2657 : }
2658 :
2659 62 : VSIFCloseL(pfMMSRS);
2660 62 : return 1; // not found
2661 : }
2662 :
2663 : // Verifies the version of a MiraMon REL 4 file.
2664 289 : CPL_DLL int MMCheck_REL_FILE(const char *szREL_file)
2665 : {
2666 : char *pszLine;
2667 : VSILFILE *pF;
2668 :
2669 : // Does the REL file exist?
2670 289 : pF = VSIFOpenL(szREL_file, "r");
2671 289 : if (!pF)
2672 : {
2673 3 : CPLError(CE_Failure, CPLE_OpenFailed, "The file %s must exist.",
2674 : szREL_file);
2675 3 : return 1;
2676 : }
2677 286 : VSIFCloseL(pF);
2678 :
2679 : // Does the REL file have VERSION?
2680 : pszLine =
2681 286 : MMReturnValueFromSectionINIFile(szREL_file, SECTION_VERSIO, nullptr);
2682 286 : if (!pszLine)
2683 : {
2684 1 : CPLError(CE_Failure, CPLE_OpenFailed,
2685 : "The file \"%s\" must be REL4. "
2686 : "You can use ConvREL.exe from MiraMon software "
2687 : " or GeM+ "
2688 : "to convert this file to REL4.",
2689 : szREL_file);
2690 1 : return 1;
2691 : }
2692 285 : VSIFree(pszLine);
2693 :
2694 : // Does the REL file have the correct VERSION?
2695 : // Vers>=4?
2696 : pszLine =
2697 285 : MMReturnValueFromSectionINIFile(szREL_file, SECTION_VERSIO, KEY_Vers);
2698 285 : if (pszLine)
2699 : {
2700 285 : if (*pszLine == '\0' || atoi(pszLine) < (int)MM_VERS)
2701 : {
2702 0 : CPLError(CE_Failure, CPLE_OpenFailed,
2703 : "The file \"%s\" must have %s>=%d.", szREL_file, KEY_Vers,
2704 : MM_VERS);
2705 0 : VSIFree(pszLine);
2706 0 : return 1;
2707 : }
2708 285 : VSIFree(pszLine);
2709 : }
2710 : else
2711 : {
2712 0 : CPLError(CE_Failure, CPLE_OpenFailed,
2713 : "The file \"%s\" must have %s>=%d.", szREL_file, KEY_Vers,
2714 : MM_VERS);
2715 0 : return 1;
2716 : }
2717 :
2718 : // SubVers>=0?
2719 285 : pszLine = MMReturnValueFromSectionINIFile(szREL_file, SECTION_VERSIO,
2720 : KEY_SubVers);
2721 285 : if (pszLine)
2722 : {
2723 285 : if (*pszLine == '\0' || atoi(pszLine) < (int)MM_SUBVERS_ACCEPTED)
2724 : {
2725 0 : CPLError(CE_Failure, CPLE_OpenFailed,
2726 : "The file \"%s\" must have %s>=%d.", szREL_file,
2727 : KEY_SubVers, MM_SUBVERS_ACCEPTED);
2728 :
2729 0 : VSIFree(pszLine);
2730 0 : return 1;
2731 : }
2732 285 : VSIFree(pszLine);
2733 : }
2734 : else
2735 : {
2736 0 : CPLError(CE_Failure, CPLE_OpenFailed,
2737 : "The file \"%s\" must have %s>=%d.", szREL_file, KEY_SubVers,
2738 : MM_SUBVERS_ACCEPTED);
2739 0 : return 1;
2740 : }
2741 :
2742 : // VersMetaDades>=4?
2743 285 : pszLine = MMReturnValueFromSectionINIFile(szREL_file, SECTION_VERSIO,
2744 : KEY_VersMetaDades);
2745 285 : if (pszLine)
2746 : {
2747 284 : if (*pszLine == '\0' || atoi(pszLine) < (int)MM_VERS_METADADES_ACCEPTED)
2748 : {
2749 0 : CPLError(CE_Failure, CPLE_OpenFailed,
2750 : "The file \"%s\" must have %s>=%d.", szREL_file,
2751 : KEY_VersMetaDades, MM_VERS_METADADES_ACCEPTED);
2752 0 : VSIFree(pszLine);
2753 0 : return 1;
2754 : }
2755 284 : VSIFree(pszLine);
2756 : }
2757 : else
2758 : {
2759 1 : CPLError(CE_Failure, CPLE_OpenFailed,
2760 : "The file \"%s\" must have %s>=%d.", szREL_file,
2761 : KEY_VersMetaDades, MM_VERS_METADADES_ACCEPTED);
2762 1 : return 1;
2763 : }
2764 :
2765 : // SubVersMetaDades>=0?
2766 284 : pszLine = MMReturnValueFromSectionINIFile(szREL_file, SECTION_VERSIO,
2767 : KEY_SubVersMetaDades);
2768 284 : if (pszLine)
2769 : {
2770 284 : if (*pszLine == '\0' || atoi(pszLine) < (int)MM_SUBVERS_METADADES)
2771 : {
2772 0 : CPLError(CE_Failure, CPLE_OpenFailed,
2773 : "The file \"%s\" must have %s>=%d.", szREL_file,
2774 : KEY_SubVersMetaDades, MM_SUBVERS_METADADES);
2775 0 : VSIFree(pszLine);
2776 0 : return 1;
2777 : }
2778 284 : VSIFree(pszLine);
2779 : }
2780 : else
2781 : {
2782 0 : CPLError(CE_Failure, CPLE_OpenFailed,
2783 : "The file \"%s\" must have %s>=%d.", szREL_file,
2784 : KEY_SubVersMetaDades, MM_SUBVERS_METADADES);
2785 0 : return 1;
2786 : }
2787 284 : return 0;
2788 : }
2789 :
2790 : /* -------------------------------------------------------------------- */
2791 : /* Managing errors and warnings */
2792 : /* -------------------------------------------------------------------- */
2793 :
2794 : // Checks for potential arithmetic overflow when performing multiplication
2795 : // operations between two GUInt64 values and converting the result to size_t.
2796 : // Important for 32 vs. 64 bit compiling compatibility.
2797 5479 : CPL_DLL int MMCheckSize_t(GUInt64 nCount, GUInt64 nSize)
2798 : {
2799 : if ((size_t)nCount != nCount)
2800 : return 1;
2801 :
2802 : if ((size_t)nSize != nSize)
2803 : return 1;
2804 :
2805 : #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
2806 5479 : if (nCount != 0 && nSize > SIZE_MAX / nCount)
2807 : #else
2808 : if (nCount != 0 && nSize > (1000 * 1000 * 1000U) / nCount)
2809 : #endif
2810 : {
2811 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Overflow in MMCheckSize_t()");
2812 0 : return 1;
2813 : }
2814 5479 : return 0;
2815 : }
2816 :
2817 : CPL_C_END // Necessary for compiling in GDAL project
|