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 : if (_data_struct_code == dsc_concatenated)
453 : {
454 : // Split on two consecutive backslashes.
455 1266 : std::vector<std::string> aosPartDescr;
456 : {
457 2532 : std::string osCur;
458 80576 : for (size_t i = 0; i < _arrayDescr.size(); ++i)
459 : {
460 79310 : const char c = _arrayDescr[i];
461 79310 : if (c == '\\' && _arrayDescr[i + 1] == '\\')
462 : {
463 1266 : aosPartDescr.push_back(osCur);
464 1266 : osCur.clear();
465 1266 : ++i;
466 : }
467 : else
468 : {
469 78044 : osCur += c;
470 : }
471 : }
472 1266 : aosPartDescr.push_back(std::move(osCur));
473 : }
474 2532 : if (aosPartDescr.size() > 1 && !_formatControls.empty() &&
475 2532 : _formatControls.front() == '(' && _formatControls.back() == ')')
476 : {
477 1266 : const char *pszFormatCur = _formatControls.c_str() + 1;
478 3798 : for (size_t i = 0; i < aosPartDescr.size(); ++i)
479 : {
480 2532 : const std::string &osPartDescr = aosPartDescr[i];
481 : // Check there are no repeated subfields but in the last part
482 3798 : if (i < aosPartDescr.size() - 1 &&
483 1266 : osPartDescr.find('*') != std::string::npos)
484 : {
485 0 : CPLError(CE_Failure, CPLE_NotSupported,
486 : "Tag %s: repeated fields found in a part that is "
487 : "not the last one: %s",
488 : osTag.c_str(), _arrayDescr.c_str());
489 0 : return false;
490 : }
491 :
492 : const int nSubfieldsInPart = static_cast<int>(
493 2532 : std::count(osPartDescr.begin(), osPartDescr.end(), '!') +
494 2532 : 1);
495 2532 : int nSubFieldCounter = 0;
496 2532 : const char *pszFormatStart = pszFormatCur;
497 2532 : bool justAfterFieldFormat = true;
498 2532 : int nParenthesisLevel = 0;
499 19206 : while (i < aosPartDescr.size() - 1 && *pszFormatCur != '\0')
500 : {
501 17940 : if (justAfterFieldFormat && *pszFormatCur >= '1' &&
502 5838 : *pszFormatCur <= '9')
503 : {
504 2077 : char *pszNext = nullptr;
505 : const int nRepeat = static_cast<int>(
506 2077 : strtol(pszFormatCur, &pszNext, 10));
507 2077 : if (!(*pszNext) || nRepeat <= 0 || nRepeat > 1000)
508 : {
509 0 : CPLError(CE_Failure, CPLE_AppDefined,
510 : "Tag %s: invalid formatControls: %s",
511 : osTag.c_str(), _formatControls.c_str());
512 0 : return false;
513 : }
514 2077 : if (*pszNext == '(')
515 : {
516 0 : pszFormatCur = pszNext + 1;
517 0 : int nGroupSubFieldCount = 0;
518 0 : while (*pszFormatCur)
519 : {
520 0 : if (*pszFormatCur == '(')
521 : {
522 : // Implementation limitation. Perhaps OK per the standard
523 0 : CPLError(CE_Failure, CPLE_AppDefined,
524 : "Tag %s: unsupported "
525 : "formatControls: %s",
526 : osTag.c_str(),
527 : _formatControls.c_str());
528 0 : return false;
529 : }
530 0 : else if (*pszFormatCur >= '1' &&
531 0 : *pszFormatCur <= '9')
532 : {
533 : const long nIncrement =
534 0 : strtol(pszFormatCur, &pszNext, 10);
535 0 : if (!(*pszNext) ||
536 : nIncrement >
537 0 : INT_MAX - nGroupSubFieldCount)
538 : {
539 0 : CPLError(CE_Failure, CPLE_AppDefined,
540 : "Tag %s: invalid "
541 : "formatControls: %s",
542 : osTag.c_str(),
543 : _formatControls.c_str());
544 0 : return false;
545 : }
546 0 : nGroupSubFieldCount +=
547 : static_cast<int>(nIncrement);
548 0 : pszFormatCur = pszNext;
549 : }
550 0 : else if (*pszFormatCur == ',')
551 : {
552 0 : if (nGroupSubFieldCount == INT_MAX)
553 : {
554 0 : CPLError(CE_Failure, CPLE_AppDefined,
555 : "Tag %s: invalid "
556 : "formatControls: %s",
557 : osTag.c_str(),
558 : _formatControls.c_str());
559 0 : return false;
560 : }
561 0 : nGroupSubFieldCount++;
562 0 : ++pszFormatCur;
563 : }
564 0 : else if (*pszFormatCur == ')')
565 : {
566 0 : if (nGroupSubFieldCount == INT_MAX)
567 : {
568 0 : CPLError(CE_Failure, CPLE_AppDefined,
569 : "Tag %s: invalid "
570 : "formatControls: %s",
571 : osTag.c_str(),
572 : _formatControls.c_str());
573 0 : return false;
574 : }
575 0 : nGroupSubFieldCount++;
576 0 : break;
577 : }
578 : else
579 : {
580 0 : ++pszFormatCur;
581 : }
582 : }
583 0 : if (!*pszFormatCur)
584 : {
585 0 : CPLError(CE_Failure, CPLE_AppDefined,
586 : "Tag %s: invalid formatControls: %s",
587 : osTag.c_str(),
588 : _formatControls.c_str());
589 0 : return false;
590 : }
591 0 : ++pszFormatCur;
592 0 : if (nGroupSubFieldCount < 0 ||
593 0 : nGroupSubFieldCount > INT_MAX / nRepeat ||
594 : nSubFieldCounter >
595 0 : INT_MAX - nGroupSubFieldCount * nRepeat)
596 : {
597 0 : CPLError(CE_Failure, CPLE_AppDefined,
598 : "Tag %s: invalid "
599 : "formatControls: %s",
600 : osTag.c_str(),
601 : _formatControls.c_str());
602 0 : return false;
603 : }
604 0 : nSubFieldCounter += nGroupSubFieldCount * nRepeat;
605 0 : if (*pszFormatCur == ')')
606 0 : break;
607 0 : if (*pszFormatCur != ',')
608 : {
609 0 : CPLError(CE_Failure, CPLE_AppDefined,
610 : "Tag %s: invalid formatControls: %s",
611 : osTag.c_str(),
612 : _formatControls.c_str());
613 0 : return false;
614 : }
615 0 : ++pszFormatCur;
616 : }
617 : else
618 : {
619 2077 : nSubFieldCounter += nRepeat;
620 2077 : pszFormatCur = pszNext;
621 4970 : while (*pszFormatCur && *pszFormatCur != ',' &&
622 2893 : *pszFormatCur != ')')
623 : {
624 2893 : ++pszFormatCur;
625 : }
626 2077 : if (*pszFormatCur == ')')
627 0 : break;
628 2077 : if (*pszFormatCur != ',')
629 : {
630 0 : CPLError(CE_Failure, CPLE_AppDefined,
631 : "Tag %s: invalid formatControls: %s",
632 : osTag.c_str(),
633 : _formatControls.c_str());
634 0 : return false;
635 : }
636 2077 : ++pszFormatCur;
637 : }
638 2077 : justAfterFieldFormat = true;
639 : }
640 15863 : else if (*pszFormatCur == ',')
641 : {
642 3761 : ++nSubFieldCounter;
643 3761 : ++pszFormatCur;
644 3761 : justAfterFieldFormat = true;
645 : }
646 12102 : else if (*pszFormatCur == '(')
647 : {
648 837 : ++nParenthesisLevel;
649 837 : ++pszFormatCur;
650 837 : justAfterFieldFormat = false;
651 : }
652 11265 : else if (*pszFormatCur == ')')
653 : {
654 837 : if (--nParenthesisLevel < 0)
655 : {
656 0 : ++nSubFieldCounter;
657 0 : break;
658 : }
659 837 : ++pszFormatCur;
660 837 : justAfterFieldFormat = false;
661 : }
662 : else
663 : {
664 10428 : ++pszFormatCur;
665 10428 : justAfterFieldFormat = false;
666 : }
667 :
668 17940 : if (nSubFieldCounter > nSubfieldsInPart)
669 : {
670 0 : CPLError(CE_Failure, CPLE_AppDefined,
671 : "Tag %s: mismatch between arrayDescr:%s and "
672 : "formatControls: %s",
673 : osTag.c_str(), _arrayDescr.c_str(),
674 : _formatControls.c_str());
675 0 : return false;
676 : }
677 17940 : else if (nSubFieldCounter == nSubfieldsInPart)
678 : {
679 1266 : break;
680 : }
681 : }
682 2532 : if (i < aosPartDescr.size() - 1)
683 : {
684 1266 : if (*pszFormatCur == 0 || pszFormatCur[-1] != ',' ||
685 : nParenthesisLevel > 0)
686 : {
687 0 : CPLError(CE_Failure, CPLE_AppDefined,
688 : "Tag %s: invalid formatControls: %s",
689 : osTag.c_str(), _formatControls.c_str());
690 0 : return false;
691 : }
692 1266 : if (nSubFieldCounter != nSubfieldsInPart)
693 : {
694 0 : CPLError(CE_Failure, CPLE_AppDefined,
695 : "Tag %s: mismatch between arrayDescr:%s and "
696 : "formatControls: %s",
697 : osTag.c_str(), _arrayDescr.c_str(),
698 : _formatControls.c_str());
699 0 : return false;
700 : }
701 : }
702 :
703 2532 : std::string osPartFormatControls;
704 2532 : if (i < aosPartDescr.size() - 1)
705 : {
706 1266 : if (pszFormatCur == pszFormatStart)
707 : {
708 0 : CPLError(CE_Failure, CPLE_AppDefined,
709 : "Tag %s: mismatch between arrayDescr:%s and "
710 : "formatControls or invalid formatControls: %s",
711 : osTag.c_str(), _arrayDescr.c_str(),
712 : _formatControls.c_str());
713 0 : return false;
714 : }
715 1266 : osPartFormatControls = '(';
716 : osPartFormatControls.append(
717 1266 : pszFormatStart, pszFormatCur - pszFormatStart - 1);
718 1266 : osPartFormatControls += ')';
719 : }
720 : else
721 : {
722 2532 : if (*pszFormatStart == '(' && _formatControls.size() > 2 &&
723 1266 : _formatControls[_formatControls.size() - 2] == ')')
724 : {
725 : // S101 2.0
726 : osPartFormatControls.append(pszFormatStart,
727 1266 : strlen(pszFormatStart) - 1);
728 : }
729 : else
730 : {
731 : // Earlier versions
732 0 : osPartFormatControls = '(';
733 0 : osPartFormatControls += pszFormatStart;
734 : }
735 : }
736 :
737 2532 : auto poPartFieldDefn = std::make_unique<DDFFieldDefn>();
738 2532 : poPartFieldDefn->poModule = poModule;
739 : // poPartFieldDefn->osTag: not set on purpose
740 : // poPartFieldDefn->_fieldName: not set on purpose
741 2532 : poPartFieldDefn->_arrayDescr = osPartDescr;
742 2532 : poPartFieldDefn->_formatControls =
743 5064 : std::move(osPartFormatControls);
744 2532 : poPartFieldDefn->_data_struct_code =
745 : dsc_vector; // not necessarily exact, but good enough
746 2532 : poPartFieldDefn->_data_type_code = _data_type_code;
747 2532 : poPartFieldDefn->bRepeatingSubfields =
748 2532 : !osPartDescr.empty() && osPartDescr.front() == '*';
749 :
750 5064 : if (!poPartFieldDefn->BuildSubfields() ||
751 2532 : !poPartFieldDefn->ApplyFormats())
752 0 : return false;
753 :
754 2532 : apoFieldParts.push_back(std::move(poPartFieldDefn));
755 : }
756 :
757 1266 : return true;
758 : }
759 : }
760 :
761 : /* -------------------------------------------------------------------- */
762 : /* It is valid to define a field with _arrayDesc */
763 : /* '*STPT!CTPT!ENPT*YCOO!XCOO' and formatControls '(2b24)'. */
764 : /* This basically indicates that there are 3 (YCOO,XCOO) */
765 : /* structures named STPT, CTPT and ENPT. But we can't handle */
766 : /* such a case gracefully here, so we just ignore the */
767 : /* "structure names" and treat such a thing as a repeating */
768 : /* YCOO/XCOO array. This occurs with the AR2D field of some */
769 : /* AML S-57 files for instance. */
770 : /* */
771 : /* We accomplish this by ignoring everything before the last */
772 : /* '*' in the subfield list. */
773 : /* -------------------------------------------------------------------- */
774 13341 : const char *pszSublist = _arrayDescr.c_str();
775 13341 : if (strrchr(pszSublist, '*') != nullptr)
776 5735 : pszSublist = strrchr(pszSublist, '*');
777 :
778 : /* -------------------------------------------------------------------- */
779 : /* Strip off the repeating marker, when it occurs, but mark our */
780 : /* field as repeating. */
781 : /* -------------------------------------------------------------------- */
782 13341 : if (pszSublist[0] == '*')
783 : {
784 5735 : bRepeatingSubfields = TRUE;
785 5735 : pszSublist++;
786 : }
787 :
788 : /* -------------------------------------------------------------------- */
789 : /* split list of fields . */
790 : /* -------------------------------------------------------------------- */
791 : const CPLStringList aosSubfieldNames(
792 13341 : CSLTokenizeStringComplex(pszSublist, "!", FALSE, FALSE));
793 :
794 : /* -------------------------------------------------------------------- */
795 : /* minimally initialize the subfields. More will be done later. */
796 : /* -------------------------------------------------------------------- */
797 76147 : for (const char *pszSubfieldName : cpl::Iterate(aosSubfieldNames))
798 : {
799 62806 : auto poSFDefn = std::make_unique<DDFSubfieldDefn>();
800 :
801 62806 : poSFDefn->SetName(pszSubfieldName);
802 62806 : AddSubfield(std::move(poSFDefn), true);
803 : }
804 :
805 13341 : return true;
806 : }
807 :
808 : /************************************************************************/
809 : /* ExtractSubstring() */
810 : /* */
811 : /* Extract a substring terminated by a comma (or end of */
812 : /* string). Commas in brackets are ignored as terminated with */
813 : /* bracket nesting understood gracefully. If the returned */
814 : /* string would begin and end with a bracket then strip off the */
815 : /* brackets. */
816 : /* */
817 : /* Given a string like "(A,3(B,C),D),X,Y)" return "A,3(B,C),D". */
818 : /* Giveh a string like "3A,2C" return "3A". */
819 : /* Giveh a string like "(3A,2C" return an empty string */
820 : /* Giveh a string like "3A),2C" return an empty string */
821 : /************************************************************************/
822 :
823 23049 : std::string DDFFieldDefn::ExtractSubstring(const char *pszSrc)
824 :
825 : {
826 23049 : int nBracket = 0;
827 23049 : int i = 0; // Used after for.
828 212423 : for (; pszSrc[i] != '\0' && (nBracket > 0 || pszSrc[i] != ','); i++)
829 : {
830 189374 : if (pszSrc[i] == '(')
831 16296 : nBracket++;
832 173078 : else if (pszSrc[i] == ')')
833 : {
834 16296 : nBracket--;
835 16296 : if (nBracket < 0)
836 0 : return std::string();
837 : }
838 : }
839 23049 : if (nBracket > 0)
840 0 : return std::string();
841 :
842 23049 : if (pszSrc[0] == '(')
843 : {
844 13341 : CPLAssert(i >= 2);
845 13341 : return std::string(pszSrc + 1, i - 2);
846 : }
847 : else
848 : {
849 9708 : return std::string(pszSrc, i);
850 : }
851 : }
852 :
853 : /************************************************************************/
854 : /* ExpandFormat() */
855 : /************************************************************************/
856 :
857 36390 : std::string DDFFieldDefn::ExpandFormat(const char *pszSrc)
858 :
859 : {
860 72780 : std::string osDest;
861 36390 : size_t iSrc = 0;
862 :
863 187991 : while (pszSrc[iSrc] != '\0')
864 : {
865 : // This is presumably an extra level of brackets around some
866 : // binary stuff related to rescanning which we don't care to do
867 : // (see 6.4.3.3 of the standard. We just strip off the extra
868 : // layer of brackets.
869 151601 : if ((iSrc == 0 || pszSrc[iSrc - 1] == ',') && pszSrc[iSrc] == '(')
870 : {
871 13341 : const std::string osContents = ExtractSubstring(pszSrc + iSrc);
872 13341 : if (osContents.empty())
873 : {
874 0 : return std::string();
875 : }
876 : const std::string osExpandedContents =
877 13341 : ExpandFormat(osContents.c_str());
878 13341 : if (osExpandedContents.empty())
879 : {
880 0 : return std::string();
881 : }
882 :
883 13341 : if (osDest.size() + osExpandedContents.size() > 1024 * 1024)
884 : {
885 0 : return std::string();
886 : }
887 :
888 13341 : osDest += osExpandedContents;
889 :
890 26682 : iSrc += osContents.size() + 2;
891 : }
892 :
893 : // This is a repeated subclause.
894 138260 : else if ((iSrc == 0 || pszSrc[iSrc - 1] == ',') &&
895 47960 : isdigit(static_cast<unsigned char>(pszSrc[iSrc])))
896 : {
897 9708 : const int nRepeat = atoi(pszSrc + iSrc);
898 : // 100: arbitrary number. Higher values might cause performance
899 : // problems in the below loop
900 9708 : if (nRepeat < 0 || nRepeat > 100)
901 : {
902 0 : CPLError(CE_Failure, CPLE_AppDefined,
903 : "Too large repeat count: %d", nRepeat);
904 0 : return std::string();
905 : }
906 :
907 : // Skip over repeat count.
908 9708 : const char *pszNext = pszSrc + iSrc; // Used after for.
909 20251 : for (; isdigit(static_cast<unsigned char>(*pszNext)); pszNext++)
910 10543 : iSrc++;
911 :
912 9708 : const std::string osContents = ExtractSubstring(pszNext);
913 9708 : if (osContents.empty())
914 : {
915 0 : return std::string();
916 : }
917 : const std::string osExpandedContents =
918 9708 : ExpandFormat(osContents.c_str());
919 9708 : if (osExpandedContents.empty())
920 : {
921 0 : return std::string();
922 : }
923 :
924 9708 : const size_t nExpandedContentsLen = osExpandedContents.size();
925 9708 : if (osDest.size() + nExpandedContentsLen * nRepeat > 1024 * 1024)
926 : {
927 0 : return std::string();
928 : }
929 :
930 43970 : for (int i = 0; i < nRepeat; i++)
931 : {
932 34262 : if (i > 0)
933 24554 : osDest += ',';
934 34262 : osDest += osExpandedContents;
935 : }
936 :
937 9708 : if (pszNext[0] == '(')
938 0 : iSrc += osContents.size() + 2;
939 : else
940 19416 : iSrc += osContents.size();
941 : }
942 : else
943 : {
944 128552 : osDest += pszSrc[iSrc++];
945 : }
946 : }
947 :
948 36390 : return osDest;
949 : }
950 :
951 : /************************************************************************/
952 : /* ApplyFormats() */
953 : /* */
954 : /* This method parses the format string partially, and then */
955 : /* applies a subfield format string to each subfield object. */
956 : /* It in turn does final parsing of the subfield formats. */
957 : /************************************************************************/
958 :
959 13341 : int DDFFieldDefn::ApplyFormats()
960 :
961 : {
962 : /* -------------------------------------------------------------------- */
963 : /* Verify that the format string is contained within brackets. */
964 : /* -------------------------------------------------------------------- */
965 26682 : if (_formatControls.size() < 2 || _formatControls[0] != '(' ||
966 13341 : _formatControls.back() != ')')
967 : {
968 0 : CPLError(CE_Warning, static_cast<CPLErrorNum>(CPLE_DiscardedFormat),
969 : "Format controls for `%s' field missing brackets:%s",
970 : osTag.c_str(), _formatControls.c_str());
971 :
972 0 : return FALSE;
973 : }
974 :
975 : /* -------------------------------------------------------------------- */
976 : /* Duplicate the string, and strip off the brackets. */
977 : /* -------------------------------------------------------------------- */
978 :
979 26682 : const std::string osFormatList = ExpandFormat(_formatControls.c_str());
980 13341 : if (osFormatList.empty())
981 : {
982 0 : CPLError(CE_Warning, static_cast<CPLErrorNum>(CPLE_DiscardedFormat),
983 : "Invalid format controls for `%s': %s", osTag.c_str(),
984 : _formatControls.c_str());
985 0 : return FALSE;
986 : }
987 :
988 : /* -------------------------------------------------------------------- */
989 : /* Tokenize based on commas. */
990 : /* -------------------------------------------------------------------- */
991 : const CPLStringList aosFormatItems(
992 26682 : CSLTokenizeStringComplex(osFormatList.c_str(), ",", FALSE, FALSE));
993 :
994 : /* -------------------------------------------------------------------- */
995 : /* Apply the format items to subfields. */
996 : /* -------------------------------------------------------------------- */
997 13341 : int iFormatItem = 0; // Used after for.
998 :
999 76147 : for (; iFormatItem < aosFormatItems.size(); iFormatItem++)
1000 : {
1001 62806 : const char *pszPastPrefix = aosFormatItems[iFormatItem];
1002 62806 : while (*pszPastPrefix >= '0' && *pszPastPrefix <= '9')
1003 0 : pszPastPrefix++;
1004 :
1005 : ///////////////////////////////////////////////////////////////
1006 : // Did we get too many formats for the subfields created
1007 : // by names? This may be legal by the 8211 specification, but
1008 : // isn't encountered in any formats we care about so we just
1009 : // blow.
1010 :
1011 62806 : if (iFormatItem >= GetSubfieldCount())
1012 : {
1013 0 : CPLError(CE_Warning, static_cast<CPLErrorNum>(CPLE_DiscardedFormat),
1014 : "Got more formats than subfields for field `%s'.",
1015 : osTag.c_str());
1016 0 : break;
1017 : }
1018 :
1019 62806 : if (!apoSubfields[iFormatItem]->SetFormat(pszPastPrefix))
1020 : {
1021 0 : return FALSE;
1022 : }
1023 : }
1024 :
1025 : /* -------------------------------------------------------------------- */
1026 : /* Verify that we got enough formats, cleanup and return. */
1027 : /* -------------------------------------------------------------------- */
1028 :
1029 13341 : if (iFormatItem < GetSubfieldCount())
1030 : {
1031 0 : CPLError(CE_Warning, static_cast<CPLErrorNum>(CPLE_DiscardedFormat),
1032 : "Got less formats than subfields for field `%s'.",
1033 : osTag.c_str());
1034 0 : return FALSE;
1035 : }
1036 :
1037 : /* -------------------------------------------------------------------- */
1038 : /* If all the fields are fixed width, then we are fixed width */
1039 : /* too. This is important for repeating fields. */
1040 : /* -------------------------------------------------------------------- */
1041 13341 : nFixedWidth = 0;
1042 56833 : for (auto &poSubfield : apoSubfields)
1043 : {
1044 48357 : if (poSubfield->GetWidth() == 0)
1045 : {
1046 4865 : nFixedWidth = 0;
1047 4865 : break;
1048 : }
1049 : else
1050 : {
1051 43492 : if (nFixedWidth > INT_MAX - poSubfield->GetWidth())
1052 : {
1053 0 : CPLError(CE_Warning,
1054 : static_cast<CPLErrorNum>(CPLE_DiscardedFormat),
1055 : "Invalid format controls for `%s': %s", osTag.c_str(),
1056 : _formatControls.c_str());
1057 0 : return FALSE;
1058 : }
1059 43492 : nFixedWidth += poSubfield->GetWidth();
1060 : }
1061 : }
1062 :
1063 13341 : return TRUE;
1064 : }
1065 :
1066 : /************************************************************************/
1067 : /* FindSubfieldDefn() */
1068 : /************************************************************************/
1069 :
1070 : /**
1071 : * Find a subfield definition by its mnemonic tag.
1072 : *
1073 : * @param pszMnemonic The name of the field.
1074 : *
1075 : * @return The subfield pointer, or NULL if there isn't any such subfield.
1076 : */
1077 :
1078 : const DDFSubfieldDefn *
1079 747797 : DDFFieldDefn::FindSubfieldDefn(const char *pszMnemonic) const
1080 :
1081 : {
1082 1555310 : for (const auto &poSubfield : apoSubfields)
1083 : {
1084 1553430 : if (EQUAL(poSubfield->GetName(), pszMnemonic))
1085 745909 : return poSubfield.get();
1086 : }
1087 :
1088 1888 : return nullptr;
1089 : }
1090 :
1091 : /************************************************************************/
1092 : /* GetDefaultValue() */
1093 : /************************************************************************/
1094 :
1095 : /**
1096 : * Return default data for field instance.
1097 : */
1098 :
1099 7277 : char *DDFFieldDefn::GetDefaultValue(int *pnSize) const
1100 :
1101 : {
1102 7277 : if (!apoFieldParts.empty())
1103 : {
1104 726 : std::string osData;
1105 726 : for (auto &poPartFieldDefn : apoFieldParts)
1106 : {
1107 726 : if (poPartFieldDefn->IsRepeating()) // only last part
1108 363 : break;
1109 363 : int nPartSize = 0;
1110 363 : char *pszVal = poPartFieldDefn->GetDefaultValue(&nPartSize);
1111 363 : if (!pszVal)
1112 0 : return nullptr;
1113 363 : osData.append(pszVal, nPartSize);
1114 363 : CPLFree(pszVal);
1115 : }
1116 363 : if (pnSize)
1117 363 : *pnSize = static_cast<int>(osData.size());
1118 363 : char *pabyRet = static_cast<char *>(CPLMalloc(osData.size()));
1119 363 : memcpy(pabyRet, osData.data(), osData.size());
1120 363 : return pabyRet;
1121 : }
1122 :
1123 : /* -------------------------------------------------------------------- */
1124 : /* Loop once collecting the sum of the subfield lengths. */
1125 : /* -------------------------------------------------------------------- */
1126 6914 : int nTotalSize = 0;
1127 32603 : for (auto &poSubfield : apoSubfields)
1128 : {
1129 25689 : int nSubfieldSize = 0;
1130 :
1131 25689 : if (!poSubfield->GetDefaultValue(nullptr, 0, &nSubfieldSize))
1132 0 : return nullptr;
1133 25689 : nTotalSize += nSubfieldSize;
1134 : }
1135 :
1136 : /* -------------------------------------------------------------------- */
1137 : /* Allocate buffer. */
1138 : /* -------------------------------------------------------------------- */
1139 6914 : char *pachData = static_cast<char *>(CPLMalloc(nTotalSize));
1140 :
1141 6914 : if (pnSize != nullptr)
1142 6914 : *pnSize = nTotalSize;
1143 :
1144 : /* -------------------------------------------------------------------- */
1145 : /* Loop again, collecting actual default values. */
1146 : /* -------------------------------------------------------------------- */
1147 6914 : int nOffset = 0;
1148 32603 : for (auto &poSubfield : apoSubfields)
1149 : {
1150 : int nSubfieldSize;
1151 :
1152 25689 : if (!poSubfield->GetDefaultValue(pachData + nOffset,
1153 : nTotalSize - nOffset, &nSubfieldSize))
1154 : {
1155 0 : CPLAssert(false);
1156 : return nullptr;
1157 : }
1158 :
1159 25689 : nOffset += nSubfieldSize;
1160 : }
1161 :
1162 6914 : CPLAssert(nOffset == nTotalSize);
1163 :
1164 6914 : return pachData;
1165 : }
|