LCOV - code coverage report
Current view: top level - frmts/iso8211 - ddffielddefn.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 339 503 67.4 %
Date: 2026-06-19 21:24:00 Functions: 12 13 92.3 %

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

Generated by: LCOV version 1.14