LCOV - code coverage report
Current view: top level - frmts/iso8211 - ddffielddefn.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 285 408 69.9 %
Date: 2025-01-18 12:42:00 Functions: 14 16 87.5 %

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

Generated by: LCOV version 1.14