Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: ISO 8211 Access
4 : * Purpose: Implements the DDFFieldDefn class.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 1999, Frank Warmerdam
9 : * Copyright (c) 2026, Even Rouault
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_port.h"
15 : #include "iso8211.h"
16 :
17 : #include <algorithm>
18 : #include <cctype>
19 : #include <cstddef>
20 : #include <cstdio>
21 : #include <cstdlib>
22 : #include <cstring>
23 :
24 : #include "cpl_conv.h"
25 : #include "cpl_error.h"
26 : #include "cpl_string.h"
27 :
28 : #define CPLE_DiscardedFormat 1301
29 :
30 : /************************************************************************/
31 : /* DDFFieldDefn() */
32 : /************************************************************************/
33 :
34 : DDFFieldDefn::DDFFieldDefn() = default;
35 :
36 : /************************************************************************/
37 : /* ~DDFFieldDefn() */
38 : /************************************************************************/
39 :
40 : DDFFieldDefn::~DDFFieldDefn() = default;
41 :
42 : /************************************************************************/
43 : /* AddSubfield() */
44 : /************************************************************************/
45 :
46 1691 : void DDFFieldDefn::AddSubfield(const char *pszName, const char *pszFormat)
47 :
48 : {
49 1691 : auto poSFDefn = std::make_unique<DDFSubfieldDefn>();
50 :
51 1691 : poSFDefn->SetName(pszName);
52 1691 : poSFDefn->SetFormat(pszFormat);
53 1691 : AddSubfield(std::move(poSFDefn));
54 1691 : }
55 :
56 : /************************************************************************/
57 : /* AddSubfield() */
58 : /************************************************************************/
59 :
60 64497 : void DDFFieldDefn::AddSubfield(std::unique_ptr<DDFSubfieldDefn> poNewSFDefn,
61 : bool bDontAddToFormat)
62 :
63 : {
64 64497 : if (bDontAddToFormat)
65 : {
66 62806 : apoSubfields.push_back(std::move(poNewSFDefn));
67 62806 : return;
68 : }
69 :
70 : /* -------------------------------------------------------------------- */
71 : /* Add this format to the format list. We don't bother */
72 : /* aggregating formats here. */
73 : /* -------------------------------------------------------------------- */
74 1691 : if (_formatControls.empty())
75 : {
76 342 : _formatControls = "()";
77 : }
78 :
79 3382 : std::string osNewFormatControls = _formatControls;
80 1691 : osNewFormatControls.pop_back();
81 1691 : if (!osNewFormatControls.empty() && osNewFormatControls.back() != '(')
82 1349 : osNewFormatControls += ',';
83 1691 : osNewFormatControls += poNewSFDefn->GetFormat();
84 1691 : osNewFormatControls += ')';
85 :
86 1691 : _formatControls = std::move(osNewFormatControls);
87 :
88 : /* -------------------------------------------------------------------- */
89 : /* Add the subfield name to the list. */
90 : /* -------------------------------------------------------------------- */
91 3192 : if (!_arrayDescr.empty() &&
92 1501 : (_arrayDescr[0] != '*' || _arrayDescr.size() > 1))
93 1349 : _arrayDescr += '!';
94 1691 : _arrayDescr += poNewSFDefn->GetName();
95 :
96 1691 : apoSubfields.push_back(std::move(poNewSFDefn));
97 : }
98 :
99 : /************************************************************************/
100 : /* Create() */
101 : /* */
102 : /* Initialize a new field defn from application input, instead */
103 : /* of from an existing file. */
104 : /************************************************************************/
105 :
106 3178 : int DDFFieldDefn::Create(const char *pszTagIn, const char *pszFieldName,
107 : const char *pszDescription,
108 : DDF_data_struct_code eDataStructCode,
109 : DDF_data_type_code eDataTypeCode,
110 : const char *pszFormat)
111 :
112 : {
113 3178 : CPLAssert(osTag.empty());
114 3178 : poModule = nullptr;
115 3178 : osTag = pszTagIn;
116 3178 : _fieldName = pszFieldName;
117 3178 : _arrayDescr = pszDescription ? pszDescription : "";
118 :
119 3178 : _data_struct_code = eDataStructCode;
120 3178 : _data_type_code = eDataTypeCode;
121 :
122 3178 : _formatControls = pszFormat ? pszFormat : "";
123 :
124 3178 : bRepeatingSubfields = (pszDescription != nullptr && *pszDescription == '*');
125 :
126 3178 : if (!_formatControls.empty() && _data_struct_code != dsc_elementary)
127 : {
128 2592 : if (!BuildSubfields())
129 0 : return false;
130 :
131 2592 : if (apoFieldParts.empty() && !ApplyFormats())
132 0 : return false;
133 : }
134 :
135 3178 : return TRUE;
136 : }
137 :
138 : /************************************************************************/
139 : /* GenerateDDREntry() */
140 : /************************************************************************/
141 :
142 9474 : int DDFFieldDefn::GenerateDDREntry(DDFModule *poModuleIn, char **ppachData,
143 : int *pnLength)
144 :
145 : {
146 9474 : const int iFDOffset = poModuleIn->GetFieldControlLength();
147 9474 : CPLAssert(iFDOffset >= 6 && iFDOffset <= 9);
148 9474 : *pnLength = static_cast<int>(iFDOffset + _fieldName.size() + 1 +
149 9474 : _arrayDescr.size() + 1);
150 9474 : if (!_formatControls.empty())
151 : {
152 8808 : *pnLength += static_cast<int>(_formatControls.size() + 1);
153 : }
154 :
155 9474 : if (ppachData == nullptr)
156 6316 : return TRUE;
157 :
158 3158 : *ppachData = static_cast<char *>(CPLMalloc(*pnLength + 1));
159 3158 : (*ppachData)[*pnLength] = 0;
160 :
161 3158 : if (_data_struct_code == dsc_elementary)
162 242 : (*ppachData)[0] = '0';
163 2916 : else if (_data_struct_code == dsc_vector)
164 1512 : (*ppachData)[0] = '1';
165 1404 : else if (_data_struct_code == dsc_array)
166 1100 : (*ppachData)[0] = '2';
167 304 : else if (_data_struct_code == dsc_concatenated)
168 304 : (*ppachData)[0] = '3';
169 :
170 3158 : if (_data_type_code == dtc_char_string)
171 224 : (*ppachData)[1] = '0';
172 2934 : else if (_data_type_code == dtc_implicit_point)
173 1288 : (*ppachData)[1] = '1';
174 1646 : else if (_data_type_code == dtc_explicit_point)
175 0 : (*ppachData)[1] = '2';
176 1646 : else if (_data_type_code == dtc_explicit_point_scaled)
177 0 : (*ppachData)[1] = '3';
178 1646 : else if (_data_type_code == dtc_char_bit_string)
179 0 : (*ppachData)[1] = '4';
180 1646 : else if (_data_type_code == dtc_bit_string)
181 57 : (*ppachData)[1] = '5';
182 1589 : else if (_data_type_code == dtc_mixed_data_type)
183 1589 : (*ppachData)[1] = '6';
184 :
185 3158 : (*ppachData)[2] = '0';
186 3158 : (*ppachData)[3] = '0';
187 3158 : (*ppachData)[4] = ';';
188 3158 : (*ppachData)[5] = '&';
189 3158 : if (iFDOffset > 6 && _escapeSequence.size() >= 1)
190 3158 : (*ppachData)[6] = _escapeSequence[0];
191 3158 : if (iFDOffset > 7 && _escapeSequence.size() >= 2)
192 3158 : (*ppachData)[7] = _escapeSequence[1];
193 3158 : if (iFDOffset > 8 && _escapeSequence.size() >= 3)
194 3158 : (*ppachData)[8] = _escapeSequence[2];
195 3158 : snprintf(*ppachData + iFDOffset, *pnLength + 1 - iFDOffset, "%s",
196 : _fieldName.c_str());
197 3158 : snprintf(*ppachData + strlen(*ppachData),
198 3158 : *pnLength + 1 - strlen(*ppachData), "%c%s", DDF_UNIT_TERMINATOR,
199 : _arrayDescr.c_str());
200 3158 : if (!_formatControls.empty())
201 : {
202 : // empty for '0000' of S-57 & S-111
203 2936 : snprintf(*ppachData + strlen(*ppachData),
204 2936 : *pnLength + 1 - strlen(*ppachData), "%c%s",
205 : DDF_UNIT_TERMINATOR, _formatControls.c_str());
206 : }
207 3158 : snprintf(*ppachData + strlen(*ppachData),
208 3158 : *pnLength + 1 - strlen(*ppachData), "%c", DDF_FIELD_TERMINATOR);
209 :
210 3158 : return TRUE;
211 : }
212 :
213 : /************************************************************************/
214 : /* Initialize() */
215 : /* */
216 : /* Initialize the field definition from the information in the */
217 : /* DDR record. This is called by DDFModule::Open(). */
218 : /************************************************************************/
219 :
220 10256 : int DDFFieldDefn::Initialize(DDFModule *poModuleIn, const char *pszTagIn,
221 : int nFieldEntrySize, const char *pachFieldArea)
222 :
223 : {
224 10256 : int iFDOffset = poModuleIn->GetFieldControlLength();
225 :
226 10256 : poModule = poModuleIn;
227 :
228 10256 : osTag = pszTagIn;
229 :
230 : /* -------------------------------------------------------------------- */
231 : /* Set the data struct and type codes. */
232 : /* -------------------------------------------------------------------- */
233 10256 : switch (pachFieldArea[0])
234 : {
235 773 : case ' ': /* for ADRG, DIGEST USRP, DIGEST ASRP files */
236 : case '0':
237 773 : _data_struct_code = dsc_elementary;
238 773 : break;
239 :
240 5026 : case '1':
241 5026 : _data_struct_code = dsc_vector;
242 5026 : break;
243 :
244 3495 : case '2':
245 3495 : _data_struct_code = dsc_array;
246 3495 : break;
247 :
248 962 : case '3':
249 962 : _data_struct_code = dsc_concatenated;
250 962 : break;
251 :
252 0 : default:
253 0 : CPLError(CE_Failure, CPLE_AppDefined,
254 : "Unrecognized data_struct_code value %c.\n"
255 : "Field %s initialization incorrect.",
256 0 : pachFieldArea[0], osTag.c_str());
257 0 : _data_struct_code = dsc_elementary;
258 : }
259 :
260 10256 : switch (pachFieldArea[1])
261 : {
262 836 : case ' ': /* for ADRG, DIGEST USRP, DIGEST ASRP files */
263 : case '0':
264 836 : _data_type_code = dtc_char_string;
265 836 : break;
266 :
267 4349 : case '1':
268 4349 : _data_type_code = dtc_implicit_point;
269 4349 : break;
270 :
271 16 : case '2':
272 16 : _data_type_code = dtc_explicit_point;
273 16 : break;
274 :
275 0 : case '3':
276 0 : _data_type_code = dtc_explicit_point_scaled;
277 0 : break;
278 :
279 0 : case '4':
280 0 : _data_type_code = dtc_char_bit_string;
281 0 : break;
282 :
283 128 : case '5':
284 128 : _data_type_code = dtc_bit_string;
285 128 : break;
286 :
287 4927 : case '6':
288 4927 : _data_type_code = dtc_mixed_data_type;
289 4927 : break;
290 :
291 0 : default:
292 0 : CPLError(CE_Failure, CPLE_AppDefined,
293 : "Unrecognized data_type_code value %c.\n"
294 : "Field %s initialization incorrect.",
295 0 : pachFieldArea[1], osTag.c_str());
296 0 : _data_type_code = dtc_char_string;
297 : }
298 :
299 10256 : if (nFieldEntrySize >= iFDOffset && iFDOffset > 6)
300 9821 : _escapeSequence.assign(pachFieldArea + 6, iFDOffset - 6);
301 :
302 : /* -------------------------------------------------------------------- */
303 : /* Capture the field name, description (sub field names), and */
304 : /* format statements. */
305 : /* -------------------------------------------------------------------- */
306 :
307 10256 : int nCharsConsumed = 0;
308 10256 : _fieldName = DDFFetchVariable(
309 10256 : pachFieldArea + iFDOffset, nFieldEntrySize - iFDOffset,
310 10256 : DDF_UNIT_TERMINATOR, DDF_FIELD_TERMINATOR, &nCharsConsumed);
311 10256 : iFDOffset += nCharsConsumed;
312 :
313 10256 : _arrayDescr = DDFFetchVariable(
314 10256 : pachFieldArea + iFDOffset, nFieldEntrySize - iFDOffset,
315 10256 : DDF_UNIT_TERMINATOR, DDF_FIELD_TERMINATOR, &nCharsConsumed);
316 10256 : iFDOffset += nCharsConsumed;
317 :
318 10256 : _formatControls = DDFFetchVariable(
319 10256 : pachFieldArea + iFDOffset, nFieldEntrySize - iFDOffset,
320 10256 : DDF_UNIT_TERMINATOR, DDF_FIELD_TERMINATOR, &nCharsConsumed);
321 :
322 : /* -------------------------------------------------------------------- */
323 : /* Parse the subfield info. */
324 : /* -------------------------------------------------------------------- */
325 10256 : if (_data_struct_code != dsc_elementary)
326 : {
327 9483 : if (!BuildSubfields())
328 0 : return false;
329 :
330 9483 : if (apoFieldParts.empty() && !ApplyFormats())
331 0 : return false;
332 : }
333 :
334 10256 : return TRUE;
335 : }
336 :
337 : /************************************************************************/
338 : /* SetEscapeSequence() */
339 : /************************************************************************/
340 :
341 2724 : void DDFFieldDefn::SetEscapeSequence(const std::string &val)
342 : {
343 2724 : _escapeSequence = val;
344 2724 : }
345 :
346 : /************************************************************************/
347 : /* Dump() */
348 : /************************************************************************/
349 :
350 : /**
351 : * Write out field definition info to debugging file.
352 : *
353 : * A variety of information about this field definition, and all its
354 : * subfields is written to the give debugging file handle.
355 : *
356 : * @param fp The standard IO file handle to write to. i.e. stderr
357 : */
358 :
359 0 : void DDFFieldDefn::Dump(FILE *fp, int nNestingLevel) const
360 :
361 : {
362 0 : std::string osIndent;
363 0 : for (int i = 0; i < nNestingLevel; ++i)
364 0 : osIndent += " ";
365 :
366 : #define Print(...) \
367 : do \
368 : { \
369 : fprintf(fp, "%s", osIndent.c_str()); \
370 : fprintf(fp, __VA_ARGS__); \
371 : } while (0)
372 :
373 0 : const char *pszValue = "";
374 0 : CPL_IGNORE_RET_VAL(pszValue); // Make CSA happy
375 :
376 0 : Print("DDFFieldDefn:\n");
377 0 : Print(" Tag = `%s'\n", osTag.c_str());
378 0 : Print(" _fieldName = `%s'\n", _fieldName.c_str());
379 0 : Print(" _arrayDescr = `%s'\n", _arrayDescr.c_str());
380 0 : Print(" _formatControls = `%s'\n", _formatControls.c_str());
381 :
382 0 : switch (_data_struct_code)
383 : {
384 0 : case dsc_elementary:
385 0 : pszValue = "elementary";
386 0 : break;
387 :
388 0 : case dsc_vector:
389 0 : pszValue = "vector";
390 0 : break;
391 :
392 0 : case dsc_array:
393 0 : pszValue = "array";
394 0 : break;
395 :
396 0 : case dsc_concatenated:
397 0 : pszValue = "concatenated";
398 0 : break;
399 : }
400 :
401 0 : Print(" _data_struct_code = %s\n", pszValue);
402 :
403 0 : switch (_data_type_code)
404 : {
405 0 : case dtc_char_string:
406 0 : pszValue = "char_string";
407 0 : break;
408 :
409 0 : case dtc_implicit_point:
410 0 : pszValue = "implicit_point";
411 0 : break;
412 :
413 0 : case dtc_explicit_point:
414 0 : pszValue = "explicit_point";
415 0 : break;
416 :
417 0 : case dtc_explicit_point_scaled:
418 0 : pszValue = "explicit_point_scaled";
419 0 : break;
420 :
421 0 : case dtc_char_bit_string:
422 0 : pszValue = "char_bit_string";
423 0 : break;
424 :
425 0 : case dtc_bit_string:
426 0 : pszValue = "bit_string";
427 0 : break;
428 :
429 0 : case dtc_mixed_data_type:
430 0 : pszValue = "mixed_data_type";
431 0 : break;
432 : }
433 :
434 0 : Print(" _data_type_code = %s\n", pszValue);
435 :
436 0 : for (const auto &poField : apoFieldParts)
437 0 : poField->Dump(fp, nNestingLevel + 1);
438 :
439 0 : for (const auto &poSubfield : apoSubfields)
440 0 : poSubfield->Dump(fp, nNestingLevel + 1);
441 0 : }
442 :
443 : /************************************************************************/
444 : /* BuildSubfields() */
445 : /* */
446 : /* Based on the _arrayDescr build a set of subfields. */
447 : /************************************************************************/
448 :
449 14607 : bool DDFFieldDefn::BuildSubfields()
450 :
451 : {
452 14607 : const char *pszSublist = _arrayDescr.c_str();
453 :
454 14607 : if (_data_struct_code == dsc_concatenated)
455 : {
456 : // Split on two consecutive backslashes.
457 1266 : std::vector<std::string> aosPartDescr;
458 : {
459 2532 : std::string osCur;
460 80576 : for (size_t i = 0; i < _arrayDescr.size(); ++i)
461 : {
462 79310 : const char c = _arrayDescr[i];
463 79310 : if (c == '\\' && _arrayDescr[i + 1] == '\\')
464 : {
465 1266 : aosPartDescr.push_back(osCur);
466 1266 : osCur.clear();
467 1266 : ++i;
468 : }
469 : else
470 : {
471 78044 : osCur += c;
472 : }
473 : }
474 1266 : aosPartDescr.push_back(std::move(osCur));
475 : }
476 2532 : if (aosPartDescr.size() > 1 && !_formatControls.empty() &&
477 2532 : _formatControls.front() == '(' && _formatControls.back() == ')')
478 : {
479 1266 : const char *pszFormatCur = _formatControls.c_str() + 1;
480 3798 : for (size_t i = 0; i < aosPartDescr.size(); ++i)
481 : {
482 2532 : const std::string &osPartDescr = aosPartDescr[i];
483 : // Check there are no repeated subfields but in the last part
484 3798 : if (i < aosPartDescr.size() - 1 &&
485 1266 : osPartDescr.find('*') != std::string::npos)
486 : {
487 0 : CPLError(CE_Failure, CPLE_NotSupported,
488 : "Tag %s: repeated fields found in a part that is "
489 : "not the last one: %s",
490 : osTag.c_str(), _arrayDescr.c_str());
491 0 : return false;
492 : }
493 :
494 : const int nSubfieldsInPart = static_cast<int>(
495 2532 : std::count(osPartDescr.begin(), osPartDescr.end(), '!') +
496 2532 : 1);
497 2532 : int nSubFieldCounter = 0;
498 2532 : const char *pszFormatStart = pszFormatCur;
499 2532 : bool justAfterFieldFormat = true;
500 2532 : int nParenthesisLevel = 0;
501 19206 : while (i < aosPartDescr.size() - 1 && *pszFormatCur != '\0')
502 : {
503 17940 : if (justAfterFieldFormat && *pszFormatCur >= '1' &&
504 5838 : *pszFormatCur <= '9')
505 : {
506 2077 : char *pszNext = nullptr;
507 : const int nRepeat = static_cast<int>(
508 2077 : strtol(pszFormatCur, &pszNext, 10));
509 2077 : if (!(*pszNext) || nRepeat <= 0 || nRepeat > 1000)
510 : {
511 0 : CPLError(CE_Failure, CPLE_AppDefined,
512 : "Tag %s: invalid formatControls: %s",
513 : osTag.c_str(), _formatControls.c_str());
514 0 : return false;
515 : }
516 2077 : if (*pszNext == '(')
517 : {
518 0 : pszFormatCur = pszNext + 1;
519 0 : int nGroupSubFieldCount = 0;
520 0 : while (*pszFormatCur)
521 : {
522 0 : if (*pszFormatCur == '(')
523 : {
524 : // Implementation limitation. Perhaps OK per the standard
525 0 : CPLError(CE_Failure, CPLE_AppDefined,
526 : "Tag %s: unsupported "
527 : "formatControls: %s",
528 : osTag.c_str(),
529 : _formatControls.c_str());
530 0 : return false;
531 : }
532 0 : else if (*pszFormatCur >= '1' &&
533 0 : *pszFormatCur <= '9')
534 : {
535 : const long nIncrement =
536 0 : strtol(pszFormatCur, &pszNext, 10);
537 0 : if (!(*pszNext) ||
538 : nIncrement >
539 0 : INT_MAX - nGroupSubFieldCount)
540 : {
541 0 : CPLError(CE_Failure, CPLE_AppDefined,
542 : "Tag %s: invalid "
543 : "formatControls: %s",
544 : osTag.c_str(),
545 : _formatControls.c_str());
546 0 : return false;
547 : }
548 0 : nGroupSubFieldCount +=
549 : static_cast<int>(nIncrement);
550 0 : pszFormatCur = pszNext;
551 : }
552 0 : else if (*pszFormatCur == ',')
553 : {
554 0 : if (nGroupSubFieldCount == INT_MAX)
555 : {
556 0 : CPLError(CE_Failure, CPLE_AppDefined,
557 : "Tag %s: invalid "
558 : "formatControls: %s",
559 : osTag.c_str(),
560 : _formatControls.c_str());
561 0 : return false;
562 : }
563 0 : nGroupSubFieldCount++;
564 0 : ++pszFormatCur;
565 : }
566 0 : else if (*pszFormatCur == ')')
567 : {
568 0 : if (nGroupSubFieldCount == INT_MAX)
569 : {
570 0 : CPLError(CE_Failure, CPLE_AppDefined,
571 : "Tag %s: invalid "
572 : "formatControls: %s",
573 : osTag.c_str(),
574 : _formatControls.c_str());
575 0 : return false;
576 : }
577 0 : nGroupSubFieldCount++;
578 0 : break;
579 : }
580 : else
581 : {
582 0 : ++pszFormatCur;
583 : }
584 : }
585 0 : if (!*pszFormatCur)
586 : {
587 0 : CPLError(CE_Failure, CPLE_AppDefined,
588 : "Tag %s: invalid formatControls: %s",
589 : osTag.c_str(),
590 : _formatControls.c_str());
591 0 : return false;
592 : }
593 0 : ++pszFormatCur;
594 0 : if (nGroupSubFieldCount < 0 ||
595 0 : nGroupSubFieldCount > INT_MAX / nRepeat ||
596 : nSubFieldCounter >
597 0 : INT_MAX - nGroupSubFieldCount * nRepeat)
598 : {
599 0 : CPLError(CE_Failure, CPLE_AppDefined,
600 : "Tag %s: invalid "
601 : "formatControls: %s",
602 : osTag.c_str(),
603 : _formatControls.c_str());
604 0 : return false;
605 : }
606 0 : nSubFieldCounter += nGroupSubFieldCount * nRepeat;
607 0 : if (*pszFormatCur == ')')
608 0 : break;
609 0 : if (*pszFormatCur != ',')
610 : {
611 0 : CPLError(CE_Failure, CPLE_AppDefined,
612 : "Tag %s: invalid formatControls: %s",
613 : osTag.c_str(),
614 : _formatControls.c_str());
615 0 : return false;
616 : }
617 0 : ++pszFormatCur;
618 : }
619 : else
620 : {
621 2077 : nSubFieldCounter += nRepeat;
622 2077 : pszFormatCur = pszNext;
623 4970 : while (*pszFormatCur && *pszFormatCur != ',' &&
624 2893 : *pszFormatCur != ')')
625 : {
626 2893 : ++pszFormatCur;
627 : }
628 2077 : if (*pszFormatCur == ')')
629 0 : break;
630 2077 : if (*pszFormatCur != ',')
631 : {
632 0 : CPLError(CE_Failure, CPLE_AppDefined,
633 : "Tag %s: invalid formatControls: %s",
634 : osTag.c_str(),
635 : _formatControls.c_str());
636 0 : return false;
637 : }
638 2077 : ++pszFormatCur;
639 : }
640 2077 : justAfterFieldFormat = true;
641 : }
642 15863 : else if (*pszFormatCur == ',')
643 : {
644 3761 : ++nSubFieldCounter;
645 3761 : ++pszFormatCur;
646 3761 : justAfterFieldFormat = true;
647 : }
648 12102 : else if (*pszFormatCur == '(')
649 : {
650 837 : ++nParenthesisLevel;
651 837 : ++pszFormatCur;
652 837 : justAfterFieldFormat = false;
653 : }
654 11265 : else if (*pszFormatCur == ')')
655 : {
656 837 : if (--nParenthesisLevel < 0)
657 : {
658 0 : ++nSubFieldCounter;
659 0 : break;
660 : }
661 837 : ++pszFormatCur;
662 837 : justAfterFieldFormat = false;
663 : }
664 : else
665 : {
666 10428 : ++pszFormatCur;
667 10428 : justAfterFieldFormat = false;
668 : }
669 :
670 17940 : if (nSubFieldCounter > nSubfieldsInPart)
671 : {
672 0 : CPLError(CE_Failure, CPLE_AppDefined,
673 : "Tag %s: mismatch between arrayDescr:%s and "
674 : "formatControls: %s",
675 : osTag.c_str(), _arrayDescr.c_str(),
676 : _formatControls.c_str());
677 0 : return false;
678 : }
679 17940 : else if (nSubFieldCounter == nSubfieldsInPart)
680 : {
681 1266 : break;
682 : }
683 : }
684 2532 : if (i < aosPartDescr.size() - 1)
685 : {
686 1266 : if (*pszFormatCur == 0 || pszFormatCur[-1] != ',' ||
687 : nParenthesisLevel > 0)
688 : {
689 0 : CPLError(CE_Failure, CPLE_AppDefined,
690 : "Tag %s: invalid formatControls: %s",
691 : osTag.c_str(), _formatControls.c_str());
692 0 : return false;
693 : }
694 1266 : if (nSubFieldCounter != nSubfieldsInPart)
695 : {
696 0 : CPLError(CE_Failure, CPLE_AppDefined,
697 : "Tag %s: mismatch between arrayDescr:%s and "
698 : "formatControls: %s",
699 : osTag.c_str(), _arrayDescr.c_str(),
700 : _formatControls.c_str());
701 0 : return false;
702 : }
703 : }
704 :
705 2532 : std::string osPartFormatControls;
706 2532 : if (i < aosPartDescr.size() - 1)
707 : {
708 1266 : if (pszFormatCur == pszFormatStart)
709 : {
710 0 : CPLError(CE_Failure, CPLE_AppDefined,
711 : "Tag %s: mismatch between arrayDescr:%s and "
712 : "formatControls or invalid formatControls: %s",
713 : osTag.c_str(), _arrayDescr.c_str(),
714 : _formatControls.c_str());
715 0 : return false;
716 : }
717 1266 : osPartFormatControls = '(';
718 : osPartFormatControls.append(
719 1266 : pszFormatStart, pszFormatCur - pszFormatStart - 1);
720 1266 : osPartFormatControls += ')';
721 : }
722 : else
723 : {
724 2532 : if (*pszFormatStart == '(' && _formatControls.size() > 2 &&
725 1266 : _formatControls[_formatControls.size() - 2] == ')')
726 : {
727 : // S101 2.0
728 : osPartFormatControls.append(pszFormatStart,
729 1266 : strlen(pszFormatStart) - 1);
730 : }
731 : else
732 : {
733 : // Earlier versions
734 0 : osPartFormatControls = '(';
735 0 : osPartFormatControls += pszFormatStart;
736 : }
737 : }
738 :
739 2532 : auto poPartFieldDefn = std::make_unique<DDFFieldDefn>();
740 2532 : poPartFieldDefn->poModule = poModule;
741 : // poPartFieldDefn->osTag: not set on purpose
742 : // poPartFieldDefn->_fieldName: not set on purpose
743 2532 : poPartFieldDefn->_arrayDescr = osPartDescr;
744 2532 : poPartFieldDefn->_formatControls =
745 5064 : std::move(osPartFormatControls);
746 2532 : poPartFieldDefn->_data_struct_code =
747 : dsc_vector; // not necessarily exact, but good enough
748 2532 : poPartFieldDefn->_data_type_code = _data_type_code;
749 2532 : poPartFieldDefn->bRepeatingSubfields =
750 2532 : !osPartDescr.empty() && osPartDescr.front() == '*';
751 :
752 5064 : if (!poPartFieldDefn->BuildSubfields() ||
753 2532 : !poPartFieldDefn->ApplyFormats())
754 0 : return false;
755 :
756 2532 : apoFieldParts.push_back(std::move(poPartFieldDefn));
757 : }
758 :
759 1266 : return true;
760 : }
761 : }
762 :
763 : /* -------------------------------------------------------------------- */
764 : /* It is valid to define a field with _arrayDesc */
765 : /* '*STPT!CTPT!ENPT*YCOO!XCOO' and formatControls '(2b24)'. */
766 : /* This basically indicates that there are 3 (YCOO,XCOO) */
767 : /* structures named STPT, CTPT and ENPT. But we can't handle */
768 : /* such a case gracefully here, so we just ignore the */
769 : /* "structure names" and treat such a thing as a repeating */
770 : /* YCOO/XCOO array. This occurs with the AR2D field of some */
771 : /* AML S-57 files for instance. */
772 : /* */
773 : /* We accomplish this by ignoring everything before the last */
774 : /* '*' in the subfield list. */
775 : /* -------------------------------------------------------------------- */
776 13341 : if (strrchr(pszSublist, '*') != nullptr)
777 5735 : pszSublist = strrchr(pszSublist, '*');
778 :
779 : /* -------------------------------------------------------------------- */
780 : /* Strip off the repeating marker, when it occurs, but mark our */
781 : /* field as repeating. */
782 : /* -------------------------------------------------------------------- */
783 13341 : if (pszSublist[0] == '*')
784 : {
785 5735 : bRepeatingSubfields = TRUE;
786 5735 : pszSublist++;
787 : }
788 :
789 : /* -------------------------------------------------------------------- */
790 : /* split list of fields . */
791 : /* -------------------------------------------------------------------- */
792 : const CPLStringList aosSubfieldNames(
793 13341 : CSLTokenizeStringComplex(pszSublist, "!", FALSE, FALSE));
794 :
795 : /* -------------------------------------------------------------------- */
796 : /* minimally initialize the subfields. More will be done later. */
797 : /* -------------------------------------------------------------------- */
798 76147 : for (const char *pszSubfieldName : cpl::Iterate(aosSubfieldNames))
799 : {
800 62806 : auto poSFDefn = std::make_unique<DDFSubfieldDefn>();
801 :
802 62806 : poSFDefn->SetName(pszSubfieldName);
803 62806 : AddSubfield(std::move(poSFDefn), true);
804 : }
805 :
806 13341 : return true;
807 : }
808 :
809 : /************************************************************************/
810 : /* ExtractSubstring() */
811 : /* */
812 : /* Extract a substring terminated by a comma (or end of */
813 : /* string). Commas in brackets are ignored as terminated with */
814 : /* bracket nesting understood gracefully. If the returned */
815 : /* string would begin and end with a bracket then strip off the */
816 : /* brackets. */
817 : /* */
818 : /* Given a string like "(A,3(B,C),D),X,Y)" return "A,3(B,C),D". */
819 : /* Giveh a string like "3A,2C" return "3A". */
820 : /* Giveh a string like "(3A,2C" return an empty string */
821 : /* Giveh a string like "3A),2C" return an empty string */
822 : /************************************************************************/
823 :
824 23049 : std::string DDFFieldDefn::ExtractSubstring(const char *pszSrc)
825 :
826 : {
827 23049 : int nBracket = 0;
828 23049 : int i = 0; // Used after for.
829 212423 : for (; pszSrc[i] != '\0' && (nBracket > 0 || pszSrc[i] != ','); i++)
830 : {
831 189374 : if (pszSrc[i] == '(')
832 16296 : nBracket++;
833 173078 : else if (pszSrc[i] == ')')
834 : {
835 16296 : nBracket--;
836 16296 : if (nBracket < 0)
837 0 : return std::string();
838 : }
839 : }
840 23049 : if (nBracket > 0)
841 0 : return std::string();
842 :
843 23049 : if (pszSrc[0] == '(')
844 : {
845 13341 : CPLAssert(i >= 2);
846 13341 : return std::string(pszSrc + 1, i - 2);
847 : }
848 : else
849 : {
850 9708 : return std::string(pszSrc, i);
851 : }
852 : }
853 :
854 : /************************************************************************/
855 : /* ExpandFormat() */
856 : /************************************************************************/
857 :
858 36390 : std::string DDFFieldDefn::ExpandFormat(const char *pszSrc)
859 :
860 : {
861 72780 : std::string osDest;
862 36390 : size_t iSrc = 0;
863 :
864 187991 : while (pszSrc[iSrc] != '\0')
865 : {
866 : // This is presumably an extra level of brackets around some
867 : // binary stuff related to rescanning which we don't care to do
868 : // (see 6.4.3.3 of the standard. We just strip off the extra
869 : // layer of brackets.
870 151601 : if ((iSrc == 0 || pszSrc[iSrc - 1] == ',') && pszSrc[iSrc] == '(')
871 : {
872 13341 : const std::string osContents = ExtractSubstring(pszSrc + iSrc);
873 13341 : if (osContents.empty())
874 : {
875 0 : return std::string();
876 : }
877 : const std::string osExpandedContents =
878 13341 : ExpandFormat(osContents.c_str());
879 13341 : if (osExpandedContents.empty())
880 : {
881 0 : return std::string();
882 : }
883 :
884 13341 : if (osDest.size() + osExpandedContents.size() > 1024 * 1024)
885 : {
886 0 : return std::string();
887 : }
888 :
889 13341 : osDest += osExpandedContents;
890 :
891 26682 : iSrc += osContents.size() + 2;
892 : }
893 :
894 : // This is a repeated subclause.
895 138260 : else if ((iSrc == 0 || pszSrc[iSrc - 1] == ',') &&
896 47960 : isdigit(static_cast<unsigned char>(pszSrc[iSrc])))
897 : {
898 9708 : const int nRepeat = atoi(pszSrc + iSrc);
899 : // 100: arbitrary number. Higher values might cause performance
900 : // problems in the below loop
901 9708 : if (nRepeat < 0 || nRepeat > 100)
902 : {
903 0 : CPLError(CE_Failure, CPLE_AppDefined,
904 : "Too large repeat count: %d", nRepeat);
905 0 : return std::string();
906 : }
907 :
908 : // Skip over repeat count.
909 9708 : const char *pszNext = pszSrc + iSrc; // Used after for.
910 20251 : for (; isdigit(static_cast<unsigned char>(*pszNext)); pszNext++)
911 10543 : iSrc++;
912 :
913 9708 : const std::string osContents = ExtractSubstring(pszNext);
914 9708 : if (osContents.empty())
915 : {
916 0 : return std::string();
917 : }
918 : const std::string osExpandedContents =
919 9708 : ExpandFormat(osContents.c_str());
920 9708 : if (osExpandedContents.empty())
921 : {
922 0 : return std::string();
923 : }
924 :
925 9708 : const size_t nExpandedContentsLen = osExpandedContents.size();
926 9708 : if (osDest.size() + nExpandedContentsLen * nRepeat > 1024 * 1024)
927 : {
928 0 : return std::string();
929 : }
930 :
931 43970 : for (int i = 0; i < nRepeat; i++)
932 : {
933 34262 : if (i > 0)
934 24554 : osDest += ',';
935 34262 : osDest += osExpandedContents;
936 : }
937 :
938 9708 : if (pszNext[0] == '(')
939 0 : iSrc += osContents.size() + 2;
940 : else
941 19416 : iSrc += osContents.size();
942 : }
943 : else
944 : {
945 128552 : osDest += pszSrc[iSrc++];
946 : }
947 : }
948 :
949 36390 : return osDest;
950 : }
951 :
952 : /************************************************************************/
953 : /* ApplyFormats() */
954 : /* */
955 : /* This method parses the format string partially, and then */
956 : /* applies a subfield format string to each subfield object. */
957 : /* It in turn does final parsing of the subfield formats. */
958 : /************************************************************************/
959 :
960 13341 : int DDFFieldDefn::ApplyFormats()
961 :
962 : {
963 : /* -------------------------------------------------------------------- */
964 : /* Verify that the format string is contained within brackets. */
965 : /* -------------------------------------------------------------------- */
966 26682 : if (_formatControls.size() < 2 || _formatControls[0] != '(' ||
967 13341 : _formatControls.back() != ')')
968 : {
969 0 : CPLError(CE_Warning, static_cast<CPLErrorNum>(CPLE_DiscardedFormat),
970 : "Format controls for `%s' field missing brackets:%s",
971 : osTag.c_str(), _formatControls.c_str());
972 :
973 0 : return FALSE;
974 : }
975 :
976 : /* -------------------------------------------------------------------- */
977 : /* Duplicate the string, and strip off the brackets. */
978 : /* -------------------------------------------------------------------- */
979 :
980 26682 : const std::string osFormatList = ExpandFormat(_formatControls.c_str());
981 13341 : if (osFormatList.empty())
982 : {
983 0 : CPLError(CE_Warning, static_cast<CPLErrorNum>(CPLE_DiscardedFormat),
984 : "Invalid format controls for `%s': %s", osTag.c_str(),
985 : _formatControls.c_str());
986 0 : return FALSE;
987 : }
988 :
989 : /* -------------------------------------------------------------------- */
990 : /* Tokenize based on commas. */
991 : /* -------------------------------------------------------------------- */
992 : const CPLStringList aosFormatItems(
993 26682 : CSLTokenizeStringComplex(osFormatList.c_str(), ",", FALSE, FALSE));
994 :
995 : /* -------------------------------------------------------------------- */
996 : /* Apply the format items to subfields. */
997 : /* -------------------------------------------------------------------- */
998 13341 : int iFormatItem = 0; // Used after for.
999 :
1000 76147 : for (; iFormatItem < aosFormatItems.size(); iFormatItem++)
1001 : {
1002 62806 : const char *pszPastPrefix = aosFormatItems[iFormatItem];
1003 62806 : while (*pszPastPrefix >= '0' && *pszPastPrefix <= '9')
1004 0 : pszPastPrefix++;
1005 :
1006 : ///////////////////////////////////////////////////////////////
1007 : // Did we get too many formats for the subfields created
1008 : // by names? This may be legal by the 8211 specification, but
1009 : // isn't encountered in any formats we care about so we just
1010 : // blow.
1011 :
1012 62806 : if (iFormatItem >= GetSubfieldCount())
1013 : {
1014 0 : CPLError(CE_Warning, static_cast<CPLErrorNum>(CPLE_DiscardedFormat),
1015 : "Got more formats than subfields for field `%s'.",
1016 : osTag.c_str());
1017 0 : break;
1018 : }
1019 :
1020 62806 : if (!apoSubfields[iFormatItem]->SetFormat(pszPastPrefix))
1021 : {
1022 0 : return FALSE;
1023 : }
1024 : }
1025 :
1026 : /* -------------------------------------------------------------------- */
1027 : /* Verify that we got enough formats, cleanup and return. */
1028 : /* -------------------------------------------------------------------- */
1029 :
1030 13341 : if (iFormatItem < GetSubfieldCount())
1031 : {
1032 0 : CPLError(CE_Warning, static_cast<CPLErrorNum>(CPLE_DiscardedFormat),
1033 : "Got less formats than subfields for field `%s'.",
1034 : osTag.c_str());
1035 0 : return FALSE;
1036 : }
1037 :
1038 : /* -------------------------------------------------------------------- */
1039 : /* If all the fields are fixed width, then we are fixed width */
1040 : /* too. This is important for repeating fields. */
1041 : /* -------------------------------------------------------------------- */
1042 13341 : nFixedWidth = 0;
1043 56833 : for (auto &poSubfield : apoSubfields)
1044 : {
1045 48357 : if (poSubfield->GetWidth() == 0)
1046 : {
1047 4865 : nFixedWidth = 0;
1048 4865 : break;
1049 : }
1050 : else
1051 : {
1052 43492 : if (nFixedWidth > INT_MAX - poSubfield->GetWidth())
1053 : {
1054 0 : CPLError(CE_Warning,
1055 : static_cast<CPLErrorNum>(CPLE_DiscardedFormat),
1056 : "Invalid format controls for `%s': %s", osTag.c_str(),
1057 : _formatControls.c_str());
1058 0 : return FALSE;
1059 : }
1060 43492 : nFixedWidth += poSubfield->GetWidth();
1061 : }
1062 : }
1063 :
1064 13341 : return TRUE;
1065 : }
1066 :
1067 : /************************************************************************/
1068 : /* FindSubfieldDefn() */
1069 : /************************************************************************/
1070 :
1071 : /**
1072 : * Find a subfield definition by its mnemonic tag.
1073 : *
1074 : * @param pszMnemonic The name of the field.
1075 : *
1076 : * @return The subfield pointer, or NULL if there isn't any such subfield.
1077 : */
1078 :
1079 : const DDFSubfieldDefn *
1080 747797 : DDFFieldDefn::FindSubfieldDefn(const char *pszMnemonic) const
1081 :
1082 : {
1083 1555310 : for (const auto &poSubfield : apoSubfields)
1084 : {
1085 1553430 : if (EQUAL(poSubfield->GetName(), pszMnemonic))
1086 745909 : return poSubfield.get();
1087 : }
1088 :
1089 1888 : return nullptr;
1090 : }
1091 :
1092 : /************************************************************************/
1093 : /* GetDefaultValue() */
1094 : /************************************************************************/
1095 :
1096 : /**
1097 : * Return default data for field instance.
1098 : */
1099 :
1100 7277 : char *DDFFieldDefn::GetDefaultValue(int *pnSize) const
1101 :
1102 : {
1103 7277 : if (!apoFieldParts.empty())
1104 : {
1105 726 : std::string osData;
1106 726 : for (auto &poPartFieldDefn : apoFieldParts)
1107 : {
1108 726 : if (poPartFieldDefn->IsRepeating()) // only last part
1109 363 : break;
1110 363 : int nPartSize = 0;
1111 363 : char *pszVal = poPartFieldDefn->GetDefaultValue(&nPartSize);
1112 363 : if (!pszVal)
1113 0 : return nullptr;
1114 363 : osData.append(pszVal, nPartSize);
1115 363 : CPLFree(pszVal);
1116 : }
1117 363 : if (pnSize)
1118 363 : *pnSize = static_cast<int>(osData.size());
1119 363 : char *pabyRet = static_cast<char *>(CPLMalloc(osData.size()));
1120 363 : memcpy(pabyRet, osData.data(), osData.size());
1121 363 : return pabyRet;
1122 : }
1123 :
1124 : /* -------------------------------------------------------------------- */
1125 : /* Loop once collecting the sum of the subfield lengths. */
1126 : /* -------------------------------------------------------------------- */
1127 6914 : int nTotalSize = 0;
1128 32603 : for (auto &poSubfield : apoSubfields)
1129 : {
1130 25689 : int nSubfieldSize = 0;
1131 :
1132 25689 : if (!poSubfield->GetDefaultValue(nullptr, 0, &nSubfieldSize))
1133 0 : return nullptr;
1134 25689 : nTotalSize += nSubfieldSize;
1135 : }
1136 :
1137 : /* -------------------------------------------------------------------- */
1138 : /* Allocate buffer. */
1139 : /* -------------------------------------------------------------------- */
1140 6914 : char *pachData = static_cast<char *>(CPLMalloc(nTotalSize));
1141 :
1142 6914 : if (pnSize != nullptr)
1143 6914 : *pnSize = nTotalSize;
1144 :
1145 : /* -------------------------------------------------------------------- */
1146 : /* Loop again, collecting actual default values. */
1147 : /* -------------------------------------------------------------------- */
1148 6914 : int nOffset = 0;
1149 32603 : for (auto &poSubfield : apoSubfields)
1150 : {
1151 : int nSubfieldSize;
1152 :
1153 25689 : if (!poSubfield->GetDefaultValue(pachData + nOffset,
1154 : nTotalSize - nOffset, &nSubfieldSize))
1155 : {
1156 0 : CPLAssert(false);
1157 : return nullptr;
1158 : }
1159 :
1160 25689 : nOffset += nSubfieldSize;
1161 : }
1162 :
1163 6914 : CPLAssert(nOffset == nTotalSize);
1164 :
1165 6914 : return pachData;
1166 : }
|