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