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

Generated by: LCOV version 1.14