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