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

Generated by: LCOV version 1.14