LCOV - code coverage report
Current view: top level - frmts/iso8211 - ddffielddefn.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 285 407 70.0 %
Date: 2024-11-21 22:18:42 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             : 
     384           0 :     fprintf(fp, "  DDFFieldDefn:\n");
     385           0 :     fprintf(fp, "      Tag = `%s'\n", pszTag);
     386           0 :     fprintf(fp, "      _fieldName = `%s'\n", _fieldName);
     387           0 :     fprintf(fp, "      _arrayDescr = `%s'\n", _arrayDescr);
     388           0 :     fprintf(fp, "      _formatControls = `%s'\n", _formatControls);
     389             : 
     390           0 :     switch (_data_struct_code)
     391             :     {
     392           0 :         case dsc_elementary:
     393           0 :             pszValue = "elementary";
     394           0 :             break;
     395             : 
     396           0 :         case dsc_vector:
     397           0 :             pszValue = "vector";
     398           0 :             break;
     399             : 
     400           0 :         case dsc_array:
     401           0 :             pszValue = "array";
     402           0 :             break;
     403             : 
     404           0 :         case dsc_concatenated:
     405           0 :             pszValue = "concatenated";
     406           0 :             break;
     407             : 
     408           0 :         default:
     409           0 :             CPLAssert(false);
     410             :             pszValue = "(unknown)";
     411             :     }
     412             : 
     413           0 :     fprintf(fp, "      _data_struct_code = %s\n", pszValue);
     414             : 
     415           0 :     switch (_data_type_code)
     416             :     {
     417           0 :         case dtc_char_string:
     418           0 :             pszValue = "char_string";
     419           0 :             break;
     420             : 
     421           0 :         case dtc_implicit_point:
     422           0 :             pszValue = "implicit_point";
     423           0 :             break;
     424             : 
     425           0 :         case dtc_explicit_point:
     426           0 :             pszValue = "explicit_point";
     427           0 :             break;
     428             : 
     429           0 :         case dtc_explicit_point_scaled:
     430           0 :             pszValue = "explicit_point_scaled";
     431           0 :             break;
     432             : 
     433           0 :         case dtc_char_bit_string:
     434           0 :             pszValue = "char_bit_string";
     435           0 :             break;
     436             : 
     437           0 :         case dtc_bit_string:
     438           0 :             pszValue = "bit_string";
     439           0 :             break;
     440             : 
     441           0 :         case dtc_mixed_data_type:
     442           0 :             pszValue = "mixed_data_type";
     443           0 :             break;
     444             : 
     445           0 :         default:
     446           0 :             CPLAssert(false);
     447             :             pszValue = "(unknown)";
     448             :             break;
     449             :     }
     450             : 
     451           0 :     fprintf(fp, "      _data_type_code = %s\n", pszValue);
     452             : 
     453           0 :     for (int i = 0; i < nSubfieldCount; i++)
     454           0 :         papoSubfields[i]->Dump(fp);
     455           0 : }
     456             : 
     457             : /************************************************************************/
     458             : /*                           BuildSubfields()                           */
     459             : /*                                                                      */
     460             : /*      Based on the _arrayDescr build a set of subfields.              */
     461             : /************************************************************************/
     462             : 
     463        1694 : void DDFFieldDefn::BuildSubfields()
     464             : 
     465             : {
     466        1694 :     const char *pszSublist = _arrayDescr;
     467             : 
     468             :     /* -------------------------------------------------------------------- */
     469             :     /*      It is valid to define a field with _arrayDesc                   */
     470             :     /*      '*STPT!CTPT!ENPT*YCOO!XCOO' and formatControls '(2b24)'.        */
     471             :     /*      This basically indicates that there are 3 (YCOO,XCOO)           */
     472             :     /*      structures named STPT, CTPT and ENPT.  But we can't handle      */
     473             :     /*      such a case gracefully here, so we just ignore the              */
     474             :     /*      "structure names" and treat such a thing as a repeating         */
     475             :     /*      YCOO/XCOO array.  This occurs with the AR2D field of some       */
     476             :     /*      AML S-57 files for instance.                                    */
     477             :     /*                                                                      */
     478             :     /*      We accomplish this by ignoring everything before the last       */
     479             :     /*      '*' in the subfield list.                                       */
     480             :     /* -------------------------------------------------------------------- */
     481        1694 :     if (strrchr(pszSublist, '*') != nullptr)
     482         583 :         pszSublist = strrchr(pszSublist, '*');
     483             : 
     484             :     /* -------------------------------------------------------------------- */
     485             :     /*      Strip off the repeating marker, when it occurs, but mark our    */
     486             :     /*      field as repeating.                                             */
     487             :     /* -------------------------------------------------------------------- */
     488        1694 :     if (pszSublist[0] == '*')
     489             :     {
     490         583 :         bRepeatingSubfields = TRUE;
     491         583 :         pszSublist++;
     492             :     }
     493             : 
     494             :     /* -------------------------------------------------------------------- */
     495             :     /*      split list of fields .                                          */
     496             :     /* -------------------------------------------------------------------- */
     497             :     char **papszSubfieldNames =
     498        1694 :         CSLTokenizeStringComplex(pszSublist, "!", FALSE, FALSE);
     499             : 
     500             :     /* -------------------------------------------------------------------- */
     501             :     /*      minimally initialize the subfields.  More will be done later.   */
     502             :     /* -------------------------------------------------------------------- */
     503        1694 :     const int nSFCount = CSLCount(papszSubfieldNames);
     504       10642 :     for (int iSF = 0; iSF < nSFCount; iSF++)
     505             :     {
     506        8948 :         DDFSubfieldDefn *poSFDefn = new DDFSubfieldDefn;
     507             : 
     508        8948 :         poSFDefn->SetName(papszSubfieldNames[iSF]);
     509        8948 :         AddSubfield(poSFDefn, TRUE);
     510             :     }
     511             : 
     512        1694 :     CSLDestroy(papszSubfieldNames);
     513        1694 : }
     514             : 
     515             : /************************************************************************/
     516             : /*                          ExtractSubstring()                          */
     517             : /*                                                                      */
     518             : /*      Extract a substring terminated by a comma (or end of            */
     519             : /*      string).  Commas in brackets are ignored as terminated with     */
     520             : /*      bracket nesting understood gracefully.  If the returned         */
     521             : /*      string would being and end with a bracket then strip off the    */
     522             : /*      brackets.                                                       */
     523             : /*                                                                      */
     524             : /*      Given a string like "(A,3(B,C),D),X,Y)" return "A,3(B,C),D".    */
     525             : /*      Giveh a string like "3A,2C" return "3A".                        */
     526             : /*      Giveh a string like "(3A,2C" return NULL.                       */
     527             : /*      Giveh a string like "3A),2C" return NULL.                       */
     528             : /************************************************************************/
     529             : 
     530        2446 : char *DDFFieldDefn::ExtractSubstring(const char *pszSrc)
     531             : 
     532             : {
     533        2446 :     int nBracket = 0;
     534        2446 :     int i = 0;  // Used after for.
     535       39955 :     for (; pszSrc[i] != '\0' && (nBracket > 0 || pszSrc[i] != ','); i++)
     536             :     {
     537       37509 :         if (pszSrc[i] == '(')
     538        5424 :             nBracket++;
     539       32085 :         else if (pszSrc[i] == ')')
     540             :         {
     541        5424 :             nBracket--;
     542        5424 :             if (nBracket < 0)
     543           0 :                 return nullptr;
     544             :         }
     545             :     }
     546        2446 :     if (nBracket > 0)
     547           0 :         return nullptr;
     548             : 
     549        2446 :     char *pszReturn = nullptr;
     550        2446 :     if (pszSrc[0] == '(')
     551             :     {
     552        1695 :         CPLAssert(i >= 2);
     553        1695 :         pszReturn = CPLStrdup(pszSrc + 1);
     554        1695 :         pszReturn[i - 2] = '\0';
     555             :     }
     556             :     else
     557             :     {
     558         751 :         pszReturn = CPLStrdup(pszSrc);
     559         751 :         pszReturn[i] = '\0';
     560             :     }
     561             : 
     562        2446 :     return pszReturn;
     563             : }
     564             : 
     565             : /************************************************************************/
     566             : /*                            ExpandFormat()                            */
     567             : /************************************************************************/
     568             : 
     569        4140 : char *DDFFieldDefn::ExpandFormat(const char *pszSrc)
     570             : 
     571             : {
     572        4140 :     size_t nDestMax = 32;
     573        4140 :     char *pszDest = static_cast<char *>(CPLMalloc(nDestMax + 1));
     574             : 
     575        4140 :     size_t iSrc = 0;
     576        4140 :     size_t iDst = 0;
     577        4140 :     pszDest[0] = '\0';
     578             : 
     579       37229 :     while (pszSrc[iSrc] != '\0')
     580             :     {
     581             :         // This is presumably an extra level of brackets around some
     582             :         // binary stuff related to rescanning which we don't care to do
     583             :         // (see 6.4.3.3 of the standard.  We just strip off the extra
     584             :         // layer of brackets.
     585       33089 :         if ((iSrc == 0 || pszSrc[iSrc - 1] == ',') && pszSrc[iSrc] == '(')
     586             :         {
     587        1695 :             char *pszContents = ExtractSubstring(pszSrc + iSrc);
     588        1695 :             if (pszContents == nullptr)
     589             :             {
     590           0 :                 pszDest[0] = '\0';
     591           0 :                 return pszDest;
     592             :             }
     593        1695 :             char *pszExpandedContents = ExpandFormat(pszContents);
     594        1695 :             if (pszExpandedContents[0] == '\0')
     595             :             {
     596           0 :                 CPLFree(pszContents);
     597           0 :                 CPLFree(pszExpandedContents);
     598           0 :                 pszDest[0] = '\0';
     599           0 :                 return pszDest;
     600             :             }
     601             : 
     602        1695 :             const size_t nExpandedContentsLen = strlen(pszExpandedContents);
     603        1695 :             if (nExpandedContentsLen + iDst + 1 > nDestMax)
     604             :             {
     605         340 :                 nDestMax = 2 * (nExpandedContentsLen + iDst);
     606         340 :                 if (nDestMax > 1024 * 1024)
     607             :                 {
     608           0 :                     CPLFree(pszContents);
     609           0 :                     CPLFree(pszExpandedContents);
     610           0 :                     pszDest[0] = '\0';
     611           0 :                     return pszDest;
     612             :                 }
     613             :                 pszDest =
     614         340 :                     static_cast<char *>(CPLRealloc(pszDest, nDestMax + 1));
     615             :             }
     616             : 
     617        1695 :             strcat(pszDest + iDst, pszExpandedContents);
     618        1695 :             iDst += nExpandedContentsLen;
     619             : 
     620        1695 :             iSrc = iSrc + strlen(pszContents) + 2;
     621             : 
     622        1695 :             CPLFree(pszContents);
     623        1695 :             CPLFree(pszExpandedContents);
     624             :         }
     625             : 
     626             :         // This is a repeated subclause.
     627       31394 :         else if ((iSrc == 0 || pszSrc[iSrc - 1] == ',') &&
     628        8200 :                  isdigit(static_cast<unsigned char>(pszSrc[iSrc])))
     629             :         {
     630         751 :             const int nRepeat = atoi(pszSrc + iSrc);
     631             :             // 100: arbitrary number. Higher values might cause performance
     632             :             // problems in the below loop
     633         751 :             if (nRepeat < 0 || nRepeat > 100)
     634             :             {
     635           0 :                 pszDest[0] = '\0';
     636           0 :                 return pszDest;
     637             :             }
     638             : 
     639             :             // Skip over repeat count.
     640         751 :             const char *pszNext = pszSrc + iSrc;  // Used after for.
     641        1505 :             for (; isdigit(static_cast<unsigned char>(*pszNext)); pszNext++)
     642         754 :                 iSrc++;
     643             : 
     644         751 :             char *pszContents = ExtractSubstring(pszNext);
     645         751 :             if (pszContents == nullptr)
     646             :             {
     647           0 :                 pszDest[0] = '\0';
     648           0 :                 return pszDest;
     649             :             }
     650         751 :             char *pszExpandedContents = ExpandFormat(pszContents);
     651         751 :             if (pszExpandedContents[0] == '\0')
     652             :             {
     653           0 :                 CPLFree(pszContents);
     654           0 :                 CPLFree(pszExpandedContents);
     655           0 :                 pszDest[0] = '\0';
     656           0 :                 return pszDest;
     657             :             }
     658             : 
     659         751 :             const size_t nExpandedContentsLen = strlen(pszExpandedContents);
     660        3001 :             for (int i = 0; i < nRepeat; i++)
     661             :             {
     662        2250 :                 if (nExpandedContentsLen + iDst + 1 + 1 > nDestMax)
     663             :                 {
     664         145 :                     nDestMax = 2 * (nExpandedContentsLen + iDst + 1);
     665         145 :                     if (nDestMax > 1024 * 1024)
     666             :                     {
     667           0 :                         CPLFree(pszContents);
     668           0 :                         CPLFree(pszExpandedContents);
     669           0 :                         pszDest[0] = '\0';
     670           0 :                         return pszDest;
     671             :                     }
     672             :                     pszDest =
     673         145 :                         static_cast<char *>(CPLRealloc(pszDest, nDestMax + 1));
     674             :                 }
     675             : 
     676        2250 :                 strcat(pszDest + iDst, pszExpandedContents);
     677        2250 :                 iDst += nExpandedContentsLen;
     678        2250 :                 if (i < nRepeat - 1)
     679             :                 {
     680        1499 :                     strcat(pszDest + iDst, ",");
     681        1499 :                     iDst++;
     682             :                 }
     683             :             }
     684             : 
     685         751 :             if (pszNext[0] == '(')
     686           0 :                 iSrc = iSrc + strlen(pszContents) + 2;
     687             :             else
     688         751 :                 iSrc = iSrc + strlen(pszContents);
     689             : 
     690         751 :             CPLFree(pszContents);
     691         751 :             CPLFree(pszExpandedContents);
     692             :         }
     693             :         else
     694             :         {
     695       30643 :             if (iDst + 1 >= nDestMax)
     696             :             {
     697         321 :                 nDestMax = 2 * iDst;
     698         321 :                 pszDest = static_cast<char *>(CPLRealloc(pszDest, nDestMax));
     699             :             }
     700             : 
     701       30643 :             pszDest[iDst++] = pszSrc[iSrc++];
     702       30643 :             pszDest[iDst] = '\0';
     703             :         }
     704             :     }
     705             : 
     706        4140 :     return pszDest;
     707             : }
     708             : 
     709             : /************************************************************************/
     710             : /*                            ApplyFormats()                            */
     711             : /*                                                                      */
     712             : /*      This method parses the format string partially, and then        */
     713             : /*      applies a subfield format string to each subfield object.       */
     714             : /*      It in turn does final parsing of the subfield formats.          */
     715             : /************************************************************************/
     716             : 
     717        1694 : int DDFFieldDefn::ApplyFormats()
     718             : 
     719             : {
     720             :     /* -------------------------------------------------------------------- */
     721             :     /*      Verify that the format string is contained within brackets.     */
     722             :     /* -------------------------------------------------------------------- */
     723        1694 :     if (strlen(_formatControls) < 2 || _formatControls[0] != '(' ||
     724        1694 :         _formatControls[strlen(_formatControls) - 1] != ')')
     725             :     {
     726           0 :         CPLError(CE_Warning, static_cast<CPLErrorNum>(CPLE_DiscardedFormat),
     727             :                  "Format controls for `%s' field missing brackets:%s", pszTag,
     728             :                  _formatControls);
     729             : 
     730           0 :         return FALSE;
     731             :     }
     732             : 
     733             :     /* -------------------------------------------------------------------- */
     734             :     /*      Duplicate the string, and strip off the brackets.               */
     735             :     /* -------------------------------------------------------------------- */
     736             : 
     737        1694 :     char *pszFormatList = ExpandFormat(_formatControls);
     738        1694 :     if (pszFormatList[0] == '\0')
     739             :     {
     740           0 :         CPLError(CE_Warning, static_cast<CPLErrorNum>(CPLE_DiscardedFormat),
     741             :                  "Invalid format controls for `%s': %s", pszTag,
     742             :                  _formatControls);
     743           0 :         CPLFree(pszFormatList);
     744           0 :         return FALSE;
     745             :     }
     746             : 
     747             :     /* -------------------------------------------------------------------- */
     748             :     /*      Tokenize based on commas.                                       */
     749             :     /* -------------------------------------------------------------------- */
     750             :     char **papszFormatItems =
     751        1694 :         CSLTokenizeStringComplex(pszFormatList, ",", FALSE, FALSE);
     752             : 
     753        1694 :     CPLFree(pszFormatList);
     754             : 
     755             :     /* -------------------------------------------------------------------- */
     756             :     /*      Apply the format items to subfields.                            */
     757             :     /* -------------------------------------------------------------------- */
     758        1694 :     int iFormatItem = 0;  // Used after for.
     759             : 
     760       10642 :     for (; papszFormatItems[iFormatItem] != nullptr; iFormatItem++)
     761             :     {
     762        8948 :         const char *pszPastPrefix = papszFormatItems[iFormatItem];
     763        8948 :         while (*pszPastPrefix >= '0' && *pszPastPrefix <= '9')
     764           0 :             pszPastPrefix++;
     765             : 
     766             :         ///////////////////////////////////////////////////////////////
     767             :         // Did we get too many formats for the subfields created
     768             :         // by names?  This may be legal by the 8211 specification, but
     769             :         // isn't encountered in any formats we care about so we just
     770             :         // blow.
     771             : 
     772        8948 :         if (iFormatItem >= nSubfieldCount)
     773             :         {
     774           0 :             CPLError(CE_Warning, static_cast<CPLErrorNum>(CPLE_DiscardedFormat),
     775             :                      "Got more formats than subfields for field `%s'.", pszTag);
     776           0 :             break;
     777             :         }
     778             : 
     779        8948 :         if (!papoSubfields[iFormatItem]->SetFormat(pszPastPrefix))
     780             :         {
     781           0 :             CSLDestroy(papszFormatItems);
     782           0 :             return FALSE;
     783             :         }
     784             :     }
     785             : 
     786             :     /* -------------------------------------------------------------------- */
     787             :     /*      Verify that we got enough formats, cleanup and return.          */
     788             :     /* -------------------------------------------------------------------- */
     789        1694 :     CSLDestroy(papszFormatItems);
     790             : 
     791        1694 :     if (iFormatItem < nSubfieldCount)
     792             :     {
     793           0 :         CPLError(CE_Warning, static_cast<CPLErrorNum>(CPLE_DiscardedFormat),
     794             :                  "Got less formats than subfields for field `%s'.", pszTag);
     795           0 :         return FALSE;
     796             :     }
     797             : 
     798             :     /* -------------------------------------------------------------------- */
     799             :     /*      If all the fields are fixed width, then we are fixed width      */
     800             :     /*      too.  This is important for repeating fields.                   */
     801             :     /* -------------------------------------------------------------------- */
     802        1694 :     nFixedWidth = 0;
     803        9044 :     for (int i = 0; i < nSubfieldCount; i++)
     804             :     {
     805        7882 :         if (papoSubfields[i]->GetWidth() == 0)
     806             :         {
     807         532 :             nFixedWidth = 0;
     808         532 :             break;
     809             :         }
     810             :         else
     811             :         {
     812        7350 :             if (nFixedWidth > INT_MAX - papoSubfields[i]->GetWidth())
     813             :             {
     814           0 :                 CPLError(CE_Warning,
     815             :                          static_cast<CPLErrorNum>(CPLE_DiscardedFormat),
     816             :                          "Invalid format controls for `%s': %s", pszTag,
     817             :                          _formatControls);
     818           0 :                 return FALSE;
     819             :             }
     820        7350 :             nFixedWidth += papoSubfields[i]->GetWidth();
     821             :         }
     822             :     }
     823             : 
     824        1694 :     return TRUE;
     825             : }
     826             : 
     827             : /************************************************************************/
     828             : /*                          FindSubfieldDefn()                          */
     829             : /************************************************************************/
     830             : 
     831             : /**
     832             :  * Find a subfield definition by its mnemonic tag.
     833             :  *
     834             :  * @param pszMnemonic The name of the field.
     835             :  *
     836             :  * @return The subfield pointer, or NULL if there isn't any such subfield.
     837             :  */
     838             : 
     839       42454 : DDFSubfieldDefn *DDFFieldDefn::FindSubfieldDefn(const char *pszMnemonic)
     840             : 
     841             : {
     842      101037 :     for (int i = 0; i < nSubfieldCount; i++)
     843             :     {
     844      100951 :         if (EQUAL(papoSubfields[i]->GetName(), pszMnemonic))
     845       42368 :             return papoSubfields[i];
     846             :     }
     847             : 
     848          86 :     return nullptr;
     849             : }
     850             : 
     851             : /************************************************************************/
     852             : /*                            GetSubfield()                             */
     853             : /*                                                                      */
     854             : /*      Fetch a subfield by its index.                                 */
     855             : /************************************************************************/
     856             : 
     857             : /**
     858             :  * Fetch a subfield by index.
     859             :  *
     860             :  * @param i The index subfield index. (Between 0 and GetSubfieldCount()-1)
     861             :  *
     862             :  * @return The subfield pointer, or NULL if the index is out of range.
     863             :  */
     864             : 
     865      140007 : DDFSubfieldDefn *DDFFieldDefn::GetSubfield(int i)
     866             : 
     867             : {
     868      140007 :     if (i < 0 || i >= nSubfieldCount)
     869             :     {
     870           0 :         CPLAssert(false);
     871             :         return nullptr;
     872             :     }
     873             : 
     874      140007 :     return papoSubfields[i];
     875             : }
     876             : 
     877             : /************************************************************************/
     878             : /*                          GetDefaultValue()                           */
     879             : /************************************************************************/
     880             : 
     881             : /**
     882             :  * Return default data for field instance.
     883             :  */
     884             : 
     885         563 : char *DDFFieldDefn::GetDefaultValue(int *pnSize)
     886             : 
     887             : {
     888             :     /* -------------------------------------------------------------------- */
     889             :     /*      Loop once collecting the sum of the subfield lengths.           */
     890             :     /* -------------------------------------------------------------------- */
     891         563 :     int nTotalSize = 0;
     892             : 
     893        2677 :     for (int iSubfield = 0; iSubfield < nSubfieldCount; iSubfield++)
     894             :     {
     895        2114 :         int nSubfieldSize = 0;
     896             : 
     897        2114 :         if (!papoSubfields[iSubfield]->GetDefaultValue(nullptr, 0,
     898             :                                                        &nSubfieldSize))
     899           0 :             return nullptr;
     900        2114 :         nTotalSize += nSubfieldSize;
     901             :     }
     902             : 
     903             :     /* -------------------------------------------------------------------- */
     904             :     /*      Allocate buffer.                                                */
     905             :     /* -------------------------------------------------------------------- */
     906         563 :     char *pachData = static_cast<char *>(CPLMalloc(nTotalSize));
     907             : 
     908         563 :     if (pnSize != nullptr)
     909         563 :         *pnSize = nTotalSize;
     910             : 
     911             :     /* -------------------------------------------------------------------- */
     912             :     /*      Loop again, collecting actual default values.                   */
     913             :     /* -------------------------------------------------------------------- */
     914         563 :     int nOffset = 0;
     915        2677 :     for (int iSubfield = 0; iSubfield < nSubfieldCount; iSubfield++)
     916             :     {
     917             :         int nSubfieldSize;
     918             : 
     919        2114 :         if (!papoSubfields[iSubfield]->GetDefaultValue(
     920        2114 :                 pachData + nOffset, nTotalSize - nOffset, &nSubfieldSize))
     921             :         {
     922           0 :             CPLAssert(false);
     923             :             return nullptr;
     924             :         }
     925             : 
     926        2114 :         nOffset += nSubfieldSize;
     927             :     }
     928             : 
     929         563 :     CPLAssert(nOffset == nTotalSize);
     930             : 
     931         563 :     return pachData;
     932             : }

Generated by: LCOV version 1.14