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 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "cpl_port.h"
14 : #include "iso8211.h"
15 :
16 : #include <cctype>
17 : #include <cstddef>
18 : #include <cstdio>
19 : #include <cstdlib>
20 : #include <cstring>
21 :
22 : #include "cpl_conv.h"
23 : #include "cpl_error.h"
24 : #include "cpl_string.h"
25 :
26 : #define CPLE_DiscardedFormat 1301
27 :
28 : /************************************************************************/
29 : /* DDFFieldDefn() */
30 : /************************************************************************/
31 :
32 : DDFFieldDefn::DDFFieldDefn() = default;
33 :
34 : /************************************************************************/
35 : /* ~DDFFieldDefn() */
36 : /************************************************************************/
37 :
38 : DDFFieldDefn::~DDFFieldDefn() = default;
39 :
40 : /************************************************************************/
41 : /* AddSubfield() */
42 : /************************************************************************/
43 :
44 1691 : void DDFFieldDefn::AddSubfield(const char *pszName, const char *pszFormat)
45 :
46 : {
47 1691 : auto poSFDefn = std::make_unique<DDFSubfieldDefn>();
48 :
49 1691 : poSFDefn->SetName(pszName);
50 1691 : poSFDefn->SetFormat(pszFormat);
51 1691 : AddSubfield(std::move(poSFDefn));
52 1691 : }
53 :
54 : /************************************************************************/
55 : /* AddSubfield() */
56 : /************************************************************************/
57 :
58 8056 : void DDFFieldDefn::AddSubfield(std::unique_ptr<DDFSubfieldDefn> poNewSFDefn,
59 : bool bDontAddToFormat)
60 :
61 : {
62 8056 : if (bDontAddToFormat)
63 : {
64 6365 : apoSubfields.push_back(std::move(poNewSFDefn));
65 6365 : return;
66 : }
67 :
68 : /* -------------------------------------------------------------------- */
69 : /* Add this format to the format list. We don't bother */
70 : /* aggregating formats here. */
71 : /* -------------------------------------------------------------------- */
72 1691 : if (_formatControls.empty())
73 : {
74 342 : _formatControls = "()";
75 : }
76 :
77 3382 : std::string osNewFormatControls = _formatControls;
78 1691 : osNewFormatControls.pop_back();
79 1691 : if (!osNewFormatControls.empty() && osNewFormatControls.back() != '(')
80 1349 : osNewFormatControls += ',';
81 1691 : osNewFormatControls += poNewSFDefn->GetFormat();
82 1691 : osNewFormatControls += ')';
83 :
84 1691 : _formatControls = std::move(osNewFormatControls);
85 :
86 : /* -------------------------------------------------------------------- */
87 : /* Add the subfield name to the list. */
88 : /* -------------------------------------------------------------------- */
89 3192 : if (!_arrayDescr.empty() &&
90 1501 : (_arrayDescr[0] != '*' || _arrayDescr.size() > 1))
91 1349 : _arrayDescr += '!';
92 1691 : _arrayDescr += poNewSFDefn->GetName();
93 :
94 1691 : apoSubfields.push_back(std::move(poNewSFDefn));
95 : }
96 :
97 : /************************************************************************/
98 : /* Create() */
99 : /* */
100 : /* Initialize a new field defn from application input, instead */
101 : /* of from an existing file. */
102 : /************************************************************************/
103 :
104 400 : int DDFFieldDefn::Create(const char *pszTagIn, const char *pszFieldName,
105 : const char *pszDescription,
106 : DDF_data_struct_code eDataStructCode,
107 : DDF_data_type_code eDataTypeCode,
108 : const char *pszFormat)
109 :
110 : {
111 400 : CPLAssert(osTag.empty());
112 400 : poModule = nullptr;
113 400 : osTag = pszTagIn;
114 400 : _fieldName = pszFieldName;
115 400 : _arrayDescr = pszDescription ? pszDescription : "";
116 :
117 400 : _data_struct_code = eDataStructCode;
118 400 : _data_type_code = eDataTypeCode;
119 :
120 400 : _formatControls = pszFormat ? pszFormat : "";
121 :
122 400 : bRepeatingSubfields = (pszDescription != nullptr && *pszDescription == '*');
123 :
124 400 : if (!_formatControls.empty() && _data_struct_code != dsc_elementary)
125 : {
126 18 : BuildSubfields();
127 :
128 18 : if (!ApplyFormats())
129 0 : return FALSE;
130 : }
131 :
132 400 : return TRUE;
133 : }
134 :
135 : /************************************************************************/
136 : /* SetFormatControls() */
137 : /************************************************************************/
138 :
139 0 : void DDFFieldDefn::SetFormatControls(const char *pszVal)
140 : {
141 0 : _formatControls = pszVal ? pszVal : "";
142 0 : }
143 :
144 : /************************************************************************/
145 : /* GenerateDDREntry() */
146 : /************************************************************************/
147 :
148 1140 : int DDFFieldDefn::GenerateDDREntry(DDFModule *poModuleIn, char **ppachData,
149 : int *pnLength)
150 :
151 : {
152 1140 : const int iFDOffset = poModuleIn->GetFieldControlLength();
153 1140 : CPLAssert(iFDOffset >= 6 && iFDOffset <= 9);
154 1140 : *pnLength = static_cast<int>(iFDOffset + _fieldName.size() + 1 +
155 1140 : _arrayDescr.size() + 1);
156 1140 : if (!_formatControls.empty())
157 : {
158 1083 : *pnLength += static_cast<int>(_formatControls.size() + 1);
159 : }
160 :
161 1140 : if (ppachData == nullptr)
162 760 : return TRUE;
163 :
164 380 : *ppachData = static_cast<char *>(CPLMalloc(*pnLength + 1));
165 380 : (*ppachData)[*pnLength] = 0;
166 :
167 380 : if (_data_struct_code == dsc_elementary)
168 38 : (*ppachData)[0] = '0';
169 342 : else if (_data_struct_code == dsc_vector)
170 190 : (*ppachData)[0] = '1';
171 152 : else if (_data_struct_code == dsc_array)
172 152 : (*ppachData)[0] = '2';
173 0 : else if (_data_struct_code == dsc_concatenated)
174 0 : (*ppachData)[0] = '3';
175 :
176 380 : if (_data_type_code == dtc_char_string)
177 19 : (*ppachData)[1] = '0';
178 361 : else if (_data_type_code == dtc_implicit_point)
179 0 : (*ppachData)[1] = '1';
180 361 : else if (_data_type_code == dtc_explicit_point)
181 0 : (*ppachData)[1] = '2';
182 361 : else if (_data_type_code == dtc_explicit_point_scaled)
183 0 : (*ppachData)[1] = '3';
184 361 : else if (_data_type_code == dtc_char_bit_string)
185 0 : (*ppachData)[1] = '4';
186 361 : else if (_data_type_code == dtc_bit_string)
187 57 : (*ppachData)[1] = '5';
188 304 : else if (_data_type_code == dtc_mixed_data_type)
189 304 : (*ppachData)[1] = '6';
190 :
191 380 : (*ppachData)[2] = '0';
192 380 : (*ppachData)[3] = '0';
193 380 : (*ppachData)[4] = ';';
194 380 : (*ppachData)[5] = '&';
195 380 : if (iFDOffset > 6)
196 380 : (*ppachData)[6] = ' ';
197 380 : if (iFDOffset > 7)
198 380 : (*ppachData)[7] = ' ';
199 380 : if (iFDOffset > 8)
200 380 : (*ppachData)[8] = ' ';
201 380 : snprintf(*ppachData + iFDOffset, *pnLength + 1 - iFDOffset, "%s",
202 : _fieldName.c_str());
203 380 : snprintf(*ppachData + strlen(*ppachData),
204 380 : *pnLength + 1 - strlen(*ppachData), "%c%s", DDF_UNIT_TERMINATOR,
205 : _arrayDescr.c_str());
206 380 : if (!_formatControls.empty())
207 : {
208 : // empty for '0000' of S-57 & S-111
209 361 : snprintf(*ppachData + strlen(*ppachData),
210 361 : *pnLength + 1 - strlen(*ppachData), "%c%s",
211 : DDF_UNIT_TERMINATOR, _formatControls.c_str());
212 : }
213 380 : snprintf(*ppachData + strlen(*ppachData),
214 380 : *pnLength + 1 - strlen(*ppachData), "%c", DDF_FIELD_TERMINATOR);
215 :
216 380 : return TRUE;
217 : }
218 :
219 : /************************************************************************/
220 : /* Initialize() */
221 : /* */
222 : /* Initialize the field definition from the information in the */
223 : /* DDR record. This is called by DDFModule::Open(). */
224 : /************************************************************************/
225 :
226 1354 : int DDFFieldDefn::Initialize(DDFModule *poModuleIn, const char *pszTagIn,
227 : int nFieldEntrySize, const char *pachFieldArea)
228 :
229 : {
230 1354 : int iFDOffset = poModuleIn->GetFieldControlLength();
231 :
232 1354 : poModule = poModuleIn;
233 :
234 1354 : osTag = pszTagIn;
235 :
236 : /* -------------------------------------------------------------------- */
237 : /* Set the data struct and type codes. */
238 : /* -------------------------------------------------------------------- */
239 1354 : switch (pachFieldArea[0])
240 : {
241 148 : case ' ': /* for ADRG, DIGEST USRP, DIGEST ASRP files */
242 : case '0':
243 148 : _data_struct_code = dsc_elementary;
244 148 : break;
245 :
246 762 : case '1':
247 762 : _data_struct_code = dsc_vector;
248 762 : break;
249 :
250 444 : case '2':
251 444 : _data_struct_code = dsc_array;
252 444 : break;
253 :
254 0 : case '3':
255 0 : _data_struct_code = dsc_concatenated;
256 0 : break;
257 :
258 0 : default:
259 0 : CPLError(CE_Failure, CPLE_AppDefined,
260 : "Unrecognized data_struct_code value %c.\n"
261 : "Field %s initialization incorrect.",
262 0 : pachFieldArea[0], osTag.c_str());
263 0 : _data_struct_code = dsc_elementary;
264 : }
265 :
266 1354 : switch (pachFieldArea[1])
267 : {
268 209 : case ' ': /* for ADRG, DIGEST USRP, DIGEST ASRP files */
269 : case '0':
270 209 : _data_type_code = dtc_char_string;
271 209 : break;
272 :
273 64 : case '1':
274 64 : _data_type_code = dtc_implicit_point;
275 64 : break;
276 :
277 16 : case '2':
278 16 : _data_type_code = dtc_explicit_point;
279 16 : break;
280 :
281 0 : case '3':
282 0 : _data_type_code = dtc_explicit_point_scaled;
283 0 : break;
284 :
285 0 : case '4':
286 0 : _data_type_code = dtc_char_bit_string;
287 0 : break;
288 :
289 128 : case '5':
290 128 : _data_type_code = dtc_bit_string;
291 128 : break;
292 :
293 937 : case '6':
294 937 : _data_type_code = dtc_mixed_data_type;
295 937 : break;
296 :
297 0 : default:
298 0 : CPLError(CE_Failure, CPLE_AppDefined,
299 : "Unrecognized data_type_code value %c.\n"
300 : "Field %s initialization incorrect.",
301 0 : pachFieldArea[1], osTag.c_str());
302 0 : _data_type_code = dtc_char_string;
303 : }
304 :
305 : /* -------------------------------------------------------------------- */
306 : /* Capture the field name, description (sub field names), and */
307 : /* format statements. */
308 : /* -------------------------------------------------------------------- */
309 :
310 1354 : int nCharsConsumed = 0;
311 1354 : _fieldName = DDFFetchVariable(
312 1354 : pachFieldArea + iFDOffset, nFieldEntrySize - iFDOffset,
313 1354 : DDF_UNIT_TERMINATOR, DDF_FIELD_TERMINATOR, &nCharsConsumed);
314 1354 : iFDOffset += nCharsConsumed;
315 :
316 1354 : _arrayDescr = DDFFetchVariable(
317 1354 : pachFieldArea + iFDOffset, nFieldEntrySize - iFDOffset,
318 1354 : DDF_UNIT_TERMINATOR, DDF_FIELD_TERMINATOR, &nCharsConsumed);
319 1354 : iFDOffset += nCharsConsumed;
320 :
321 1354 : _formatControls = DDFFetchVariable(
322 1354 : pachFieldArea + iFDOffset, nFieldEntrySize - iFDOffset,
323 1354 : DDF_UNIT_TERMINATOR, DDF_FIELD_TERMINATOR, &nCharsConsumed);
324 :
325 : /* -------------------------------------------------------------------- */
326 : /* Parse the subfield info. */
327 : /* -------------------------------------------------------------------- */
328 1354 : if (_data_struct_code != dsc_elementary)
329 : {
330 1206 : BuildSubfields();
331 :
332 1206 : if (!ApplyFormats())
333 0 : return FALSE;
334 : }
335 :
336 1354 : return TRUE;
337 : }
338 :
339 : /************************************************************************/
340 : /* Dump() */
341 : /************************************************************************/
342 :
343 : /**
344 : * Write out field definition info to debugging file.
345 : *
346 : * A variety of information about this field definition, and all its
347 : * subfields is written to the give debugging file handle.
348 : *
349 : * @param fp The standard IO file handle to write to. i.e. stderr
350 : */
351 :
352 0 : void DDFFieldDefn::Dump(FILE *fp) const
353 :
354 : {
355 0 : const char *pszValue = "";
356 0 : CPL_IGNORE_RET_VAL(pszValue); // Make CSA happy
357 :
358 0 : fprintf(fp, " DDFFieldDefn:\n");
359 0 : fprintf(fp, " Tag = `%s'\n", osTag.c_str());
360 0 : fprintf(fp, " _fieldName = `%s'\n", _fieldName.c_str());
361 0 : fprintf(fp, " _arrayDescr = `%s'\n", _arrayDescr.c_str());
362 0 : fprintf(fp, " _formatControls = `%s'\n", _formatControls.c_str());
363 :
364 0 : switch (_data_struct_code)
365 : {
366 0 : case dsc_elementary:
367 0 : pszValue = "elementary";
368 0 : break;
369 :
370 0 : case dsc_vector:
371 0 : pszValue = "vector";
372 0 : break;
373 :
374 0 : case dsc_array:
375 0 : pszValue = "array";
376 0 : break;
377 :
378 0 : case dsc_concatenated:
379 0 : pszValue = "concatenated";
380 0 : break;
381 : }
382 :
383 0 : fprintf(fp, " _data_struct_code = %s\n", pszValue);
384 :
385 0 : switch (_data_type_code)
386 : {
387 0 : case dtc_char_string:
388 0 : pszValue = "char_string";
389 0 : break;
390 :
391 0 : case dtc_implicit_point:
392 0 : pszValue = "implicit_point";
393 0 : break;
394 :
395 0 : case dtc_explicit_point:
396 0 : pszValue = "explicit_point";
397 0 : break;
398 :
399 0 : case dtc_explicit_point_scaled:
400 0 : pszValue = "explicit_point_scaled";
401 0 : break;
402 :
403 0 : case dtc_char_bit_string:
404 0 : pszValue = "char_bit_string";
405 0 : break;
406 :
407 0 : case dtc_bit_string:
408 0 : pszValue = "bit_string";
409 0 : break;
410 :
411 0 : case dtc_mixed_data_type:
412 0 : pszValue = "mixed_data_type";
413 0 : break;
414 : }
415 :
416 0 : fprintf(fp, " _data_type_code = %s\n", pszValue);
417 :
418 0 : for (const auto &poSubfield : apoSubfields)
419 0 : poSubfield->Dump(fp);
420 0 : }
421 :
422 : /************************************************************************/
423 : /* BuildSubfields() */
424 : /* */
425 : /* Based on the _arrayDescr build a set of subfields. */
426 : /************************************************************************/
427 :
428 1224 : void DDFFieldDefn::BuildSubfields()
429 :
430 : {
431 1224 : const char *pszSublist = _arrayDescr.c_str();
432 :
433 : /* -------------------------------------------------------------------- */
434 : /* It is valid to define a field with _arrayDesc */
435 : /* '*STPT!CTPT!ENPT*YCOO!XCOO' and formatControls '(2b24)'. */
436 : /* This basically indicates that there are 3 (YCOO,XCOO) */
437 : /* structures named STPT, CTPT and ENPT. But we can't handle */
438 : /* such a case gracefully here, so we just ignore the */
439 : /* "structure names" and treat such a thing as a repeating */
440 : /* YCOO/XCOO array. This occurs with the AR2D field of some */
441 : /* AML S-57 files for instance. */
442 : /* */
443 : /* We accomplish this by ignoring everything before the last */
444 : /* '*' in the subfield list. */
445 : /* -------------------------------------------------------------------- */
446 1224 : if (strrchr(pszSublist, '*') != nullptr)
447 470 : pszSublist = strrchr(pszSublist, '*');
448 :
449 : /* -------------------------------------------------------------------- */
450 : /* Strip off the repeating marker, when it occurs, but mark our */
451 : /* field as repeating. */
452 : /* -------------------------------------------------------------------- */
453 1224 : if (pszSublist[0] == '*')
454 : {
455 470 : bRepeatingSubfields = TRUE;
456 470 : pszSublist++;
457 : }
458 :
459 : /* -------------------------------------------------------------------- */
460 : /* split list of fields . */
461 : /* -------------------------------------------------------------------- */
462 : const CPLStringList aosSubfieldNames(
463 2448 : CSLTokenizeStringComplex(pszSublist, "!", FALSE, FALSE));
464 :
465 : /* -------------------------------------------------------------------- */
466 : /* minimally initialize the subfields. More will be done later. */
467 : /* -------------------------------------------------------------------- */
468 7589 : for (const char *pszSubfieldName : cpl::Iterate(aosSubfieldNames))
469 : {
470 6365 : auto poSFDefn = std::make_unique<DDFSubfieldDefn>();
471 :
472 6365 : poSFDefn->SetName(pszSubfieldName);
473 6365 : AddSubfield(std::move(poSFDefn), true);
474 : }
475 1224 : }
476 :
477 : /************************************************************************/
478 : /* ExtractSubstring() */
479 : /* */
480 : /* Extract a substring terminated by a comma (or end of */
481 : /* string). Commas in brackets are ignored as terminated with */
482 : /* bracket nesting understood gracefully. If the returned */
483 : /* string would begin and end with a bracket then strip off the */
484 : /* brackets. */
485 : /* */
486 : /* Given a string like "(A,3(B,C),D),X,Y)" return "A,3(B,C),D". */
487 : /* Giveh a string like "3A,2C" return "3A". */
488 : /* Giveh a string like "(3A,2C" return an empty string */
489 : /* Giveh a string like "3A),2C" return an empty string */
490 : /************************************************************************/
491 :
492 1956 : std::string DDFFieldDefn::ExtractSubstring(const char *pszSrc)
493 :
494 : {
495 1956 : int nBracket = 0;
496 1956 : int i = 0; // Used after for.
497 27535 : for (; pszSrc[i] != '\0' && (nBracket > 0 || pszSrc[i] != ','); i++)
498 : {
499 25579 : if (pszSrc[i] == '(')
500 3342 : nBracket++;
501 22237 : else if (pszSrc[i] == ')')
502 : {
503 3342 : nBracket--;
504 3342 : if (nBracket < 0)
505 0 : return std::string();
506 : }
507 : }
508 1956 : if (nBracket > 0)
509 0 : return std::string();
510 :
511 1956 : if (pszSrc[0] == '(')
512 : {
513 1224 : CPLAssert(i >= 2);
514 1224 : return std::string(pszSrc + 1, i - 2);
515 : }
516 : else
517 : {
518 732 : return std::string(pszSrc, i);
519 : }
520 : }
521 :
522 : /************************************************************************/
523 : /* ExpandFormat() */
524 : /************************************************************************/
525 :
526 3180 : std::string DDFFieldDefn::ExpandFormat(const char *pszSrc)
527 :
528 : {
529 6360 : std::string osDest;
530 3180 : size_t iSrc = 0;
531 :
532 25030 : while (pszSrc[iSrc] != '\0')
533 : {
534 : // This is presumably an extra level of brackets around some
535 : // binary stuff related to rescanning which we don't care to do
536 : // (see 6.4.3.3 of the standard. We just strip off the extra
537 : // layer of brackets.
538 21850 : if ((iSrc == 0 || pszSrc[iSrc - 1] == ',') && pszSrc[iSrc] == '(')
539 : {
540 1224 : const std::string osContents = ExtractSubstring(pszSrc + iSrc);
541 1224 : if (osContents.empty())
542 : {
543 0 : return std::string();
544 : }
545 : const std::string osExpandedContents =
546 1224 : ExpandFormat(osContents.c_str());
547 1224 : if (osExpandedContents.empty())
548 : {
549 0 : return std::string();
550 : }
551 :
552 1224 : if (osDest.size() + osExpandedContents.size() > 1024 * 1024)
553 : {
554 0 : return std::string();
555 : }
556 :
557 1224 : osDest += osExpandedContents;
558 :
559 2448 : iSrc += osContents.size() + 2;
560 : }
561 :
562 : // This is a repeated subclause.
563 20626 : else if ((iSrc == 0 || pszSrc[iSrc - 1] == ',') &&
564 5734 : isdigit(static_cast<unsigned char>(pszSrc[iSrc])))
565 : {
566 732 : const int nRepeat = atoi(pszSrc + iSrc);
567 : // 100: arbitrary number. Higher values might cause performance
568 : // problems in the below loop
569 732 : if (nRepeat < 0 || nRepeat > 100)
570 : {
571 0 : CPLError(CE_Failure, CPLE_AppDefined,
572 : "Too large repeat count: %d", nRepeat);
573 0 : return std::string();
574 : }
575 :
576 : // Skip over repeat count.
577 732 : const char *pszNext = pszSrc + iSrc; // Used after for.
578 1464 : for (; isdigit(static_cast<unsigned char>(*pszNext)); pszNext++)
579 732 : iSrc++;
580 :
581 732 : const std::string osContents = ExtractSubstring(pszNext);
582 732 : if (osContents.empty())
583 : {
584 0 : return std::string();
585 : }
586 : const std::string osExpandedContents =
587 732 : ExpandFormat(osContents.c_str());
588 732 : if (osExpandedContents.empty())
589 : {
590 0 : return std::string();
591 : }
592 :
593 732 : const size_t nExpandedContentsLen = osExpandedContents.size();
594 732 : if (osDest.size() + nExpandedContentsLen * nRepeat > 1024 * 1024)
595 : {
596 0 : return std::string();
597 : }
598 :
599 2827 : for (int i = 0; i < nRepeat; i++)
600 : {
601 2095 : if (i > 0)
602 1363 : osDest += ',';
603 2095 : osDest += osExpandedContents;
604 : }
605 :
606 732 : if (pszNext[0] == '(')
607 0 : iSrc += osContents.size() + 2;
608 : else
609 1464 : iSrc += osContents.size();
610 : }
611 : else
612 : {
613 19894 : osDest += pszSrc[iSrc++];
614 : }
615 : }
616 :
617 3180 : return osDest;
618 : }
619 :
620 : /************************************************************************/
621 : /* ApplyFormats() */
622 : /* */
623 : /* This method parses the format string partially, and then */
624 : /* applies a subfield format string to each subfield object. */
625 : /* It in turn does final parsing of the subfield formats. */
626 : /************************************************************************/
627 :
628 1224 : int DDFFieldDefn::ApplyFormats()
629 :
630 : {
631 : /* -------------------------------------------------------------------- */
632 : /* Verify that the format string is contained within brackets. */
633 : /* -------------------------------------------------------------------- */
634 2448 : if (_formatControls.size() < 2 || _formatControls[0] != '(' ||
635 1224 : _formatControls.back() != ')')
636 : {
637 0 : CPLError(CE_Warning, static_cast<CPLErrorNum>(CPLE_DiscardedFormat),
638 : "Format controls for `%s' field missing brackets:%s",
639 : osTag.c_str(), _formatControls.c_str());
640 :
641 0 : return FALSE;
642 : }
643 :
644 : /* -------------------------------------------------------------------- */
645 : /* Duplicate the string, and strip off the brackets. */
646 : /* -------------------------------------------------------------------- */
647 :
648 2448 : const std::string osFormatList = ExpandFormat(_formatControls.c_str());
649 1224 : if (osFormatList.empty())
650 : {
651 0 : CPLError(CE_Warning, static_cast<CPLErrorNum>(CPLE_DiscardedFormat),
652 : "Invalid format controls for `%s': %s", osTag.c_str(),
653 : _formatControls.c_str());
654 0 : return FALSE;
655 : }
656 :
657 : /* -------------------------------------------------------------------- */
658 : /* Tokenize based on commas. */
659 : /* -------------------------------------------------------------------- */
660 : const CPLStringList aosFormatItems(
661 2448 : CSLTokenizeStringComplex(osFormatList.c_str(), ",", FALSE, FALSE));
662 :
663 : /* -------------------------------------------------------------------- */
664 : /* Apply the format items to subfields. */
665 : /* -------------------------------------------------------------------- */
666 1224 : int iFormatItem = 0; // Used after for.
667 :
668 7589 : for (; iFormatItem < aosFormatItems.size(); iFormatItem++)
669 : {
670 6365 : const char *pszPastPrefix = aosFormatItems[iFormatItem];
671 6365 : while (*pszPastPrefix >= '0' && *pszPastPrefix <= '9')
672 0 : pszPastPrefix++;
673 :
674 : ///////////////////////////////////////////////////////////////
675 : // Did we get too many formats for the subfields created
676 : // by names? This may be legal by the 8211 specification, but
677 : // isn't encountered in any formats we care about so we just
678 : // blow.
679 :
680 6365 : if (iFormatItem >= GetSubfieldCount())
681 : {
682 0 : CPLError(CE_Warning, static_cast<CPLErrorNum>(CPLE_DiscardedFormat),
683 : "Got more formats than subfields for field `%s'.",
684 : osTag.c_str());
685 0 : break;
686 : }
687 :
688 6365 : if (!apoSubfields[iFormatItem]->SetFormat(pszPastPrefix))
689 : {
690 0 : return FALSE;
691 : }
692 : }
693 :
694 : /* -------------------------------------------------------------------- */
695 : /* Verify that we got enough formats, cleanup and return. */
696 : /* -------------------------------------------------------------------- */
697 :
698 1224 : if (iFormatItem < GetSubfieldCount())
699 : {
700 0 : CPLError(CE_Warning, static_cast<CPLErrorNum>(CPLE_DiscardedFormat),
701 : "Got less formats than subfields for field `%s'.",
702 : osTag.c_str());
703 0 : return FALSE;
704 : }
705 :
706 : /* -------------------------------------------------------------------- */
707 : /* If all the fields are fixed width, then we are fixed width */
708 : /* too. This is important for repeating fields. */
709 : /* -------------------------------------------------------------------- */
710 1224 : nFixedWidth = 0;
711 6391 : for (auto &poSubfield : apoSubfields)
712 : {
713 5591 : if (poSubfield->GetWidth() == 0)
714 : {
715 424 : nFixedWidth = 0;
716 424 : break;
717 : }
718 : else
719 : {
720 5167 : if (nFixedWidth > INT_MAX - poSubfield->GetWidth())
721 : {
722 0 : CPLError(CE_Warning,
723 : static_cast<CPLErrorNum>(CPLE_DiscardedFormat),
724 : "Invalid format controls for `%s': %s", osTag.c_str(),
725 : _formatControls.c_str());
726 0 : return FALSE;
727 : }
728 5167 : nFixedWidth += poSubfield->GetWidth();
729 : }
730 : }
731 :
732 1224 : return TRUE;
733 : }
734 :
735 : /************************************************************************/
736 : /* FindSubfieldDefn() */
737 : /************************************************************************/
738 :
739 : /**
740 : * Find a subfield definition by its mnemonic tag.
741 : *
742 : * @param pszMnemonic The name of the field.
743 : *
744 : * @return The subfield pointer, or NULL if there isn't any such subfield.
745 : */
746 :
747 : const DDFSubfieldDefn *
748 539756 : DDFFieldDefn::FindSubfieldDefn(const char *pszMnemonic) const
749 :
750 : {
751 983340 : for (const auto &poSubfield : apoSubfields)
752 : {
753 983254 : if (EQUAL(poSubfield->GetName(), pszMnemonic))
754 539670 : return poSubfield.get();
755 : }
756 :
757 86 : return nullptr;
758 : }
759 :
760 : /************************************************************************/
761 : /* GetDefaultValue() */
762 : /************************************************************************/
763 :
764 : /**
765 : * Return default data for field instance.
766 : */
767 :
768 999 : char *DDFFieldDefn::GetDefaultValue(int *pnSize) const
769 :
770 : {
771 : /* -------------------------------------------------------------------- */
772 : /* Loop once collecting the sum of the subfield lengths. */
773 : /* -------------------------------------------------------------------- */
774 999 : int nTotalSize = 0;
775 :
776 4430 : for (auto &poSubfield : apoSubfields)
777 : {
778 3431 : int nSubfieldSize = 0;
779 :
780 3431 : if (!poSubfield->GetDefaultValue(nullptr, 0, &nSubfieldSize))
781 0 : return nullptr;
782 3431 : nTotalSize += nSubfieldSize;
783 : }
784 :
785 : /* -------------------------------------------------------------------- */
786 : /* Allocate buffer. */
787 : /* -------------------------------------------------------------------- */
788 999 : char *pachData = static_cast<char *>(CPLMalloc(nTotalSize));
789 :
790 999 : if (pnSize != nullptr)
791 999 : *pnSize = nTotalSize;
792 :
793 : /* -------------------------------------------------------------------- */
794 : /* Loop again, collecting actual default values. */
795 : /* -------------------------------------------------------------------- */
796 999 : int nOffset = 0;
797 4430 : for (auto &poSubfield : apoSubfields)
798 : {
799 : int nSubfieldSize;
800 :
801 3431 : if (!poSubfield->GetDefaultValue(pachData + nOffset,
802 : nTotalSize - nOffset, &nSubfieldSize))
803 : {
804 0 : CPLAssert(false);
805 : return nullptr;
806 : }
807 :
808 3431 : nOffset += nSubfieldSize;
809 : }
810 :
811 999 : CPLAssert(nOffset == nTotalSize);
812 :
813 999 : return pachData;
814 : }
|