LCOV - code coverage report
Current view: top level - frmts/iso8211 - ddffield.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 63 103 61.2 %
Date: 2026-04-19 18:43:50 Functions: 4 5 80.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  ISO 8211 Access
       4             :  * Purpose:  Implements the DDFField 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 <cstdio>
      17             : #include <cstdlib>
      18             : 
      19             : #include <algorithm>
      20             : 
      21             : #include "cpl_conv.h"
      22             : 
      23             : // Note, we implement no constructor for this class to make instantiation
      24             : // cheaper.  It is required that the Initialize() be called before anything
      25             : // else.
      26             : 
      27             : /************************************************************************/
      28             : /*                             Initialize()                             */
      29             : /************************************************************************/
      30             : 
      31      226213 : void DDFField::Initialize(const DDFFieldDefn *poDefnIn, const char *pachDataIn,
      32             :                           int nDataSizeIn)
      33             : 
      34             : {
      35      226213 :     pachData = pachDataIn;
      36      226213 :     nDataSize = nDataSizeIn;
      37      226213 :     poDefn = poDefnIn;
      38      226213 : }
      39             : 
      40             : /************************************************************************/
      41             : /*                                Dump()                                */
      42             : /************************************************************************/
      43             : 
      44             : /**
      45             :  * Write out field contents to debugging file.
      46             :  *
      47             :  * A variety of information about this field, and all its
      48             :  * subfields is written to the given debugging file handle.  Note that
      49             :  * field definition information (ala DDFFieldDefn) isn't written.
      50             :  *
      51             :  * @param fp The standard IO file handle to write to.  i.e. stderr
      52             :  */
      53             : 
      54           0 : void DDFField::Dump(FILE *fp) const
      55             : 
      56             : {
      57           0 :     int nMaxRepeat = 8;
      58             : 
      59           0 :     const char *pszDDF_MAXDUMP = getenv("DDF_MAXDUMP");
      60           0 :     if (pszDDF_MAXDUMP != nullptr)
      61           0 :         nMaxRepeat = atoi(pszDDF_MAXDUMP);
      62             : 
      63           0 :     fprintf(fp, "  DDFField:\n");
      64           0 :     fprintf(fp, "      Tag = `%s'\n", poDefn->GetName());
      65           0 :     fprintf(fp, "      DataSize = %d\n", nDataSize);
      66             : 
      67           0 :     fprintf(fp, "      Data = `");
      68           0 :     for (int i = 0; i < std::min(nDataSize, 40); i++)
      69             :     {
      70           0 :         if (pachData[i] < 32 || pachData[i] > 126)
      71           0 :             fprintf(fp, "\\%02X",
      72           0 :                     reinterpret_cast<const unsigned char *>(pachData)[i]);
      73             :         else
      74           0 :             fprintf(fp, "%c", pachData[i]);
      75             :     }
      76             : 
      77           0 :     if (nDataSize > 40)
      78           0 :         fprintf(fp, "...");
      79           0 :     fprintf(fp, "'\n");
      80             : 
      81             :     /* -------------------------------------------------------------------- */
      82             :     /*      dump the data of the subfields.                                 */
      83             :     /* -------------------------------------------------------------------- */
      84           0 :     int iOffset = 0;
      85             : 
      86           0 :     for (int nLoopCount = 0; nLoopCount < GetRepeatCount(); nLoopCount++)
      87             :     {
      88           0 :         if (nLoopCount > nMaxRepeat)
      89             :         {
      90           0 :             fprintf(fp, "      ...\n");
      91           0 :             break;
      92             :         }
      93             : 
      94           0 :         for (const auto &poThisSFDefn : poDefn->GetSubfields())
      95             :         {
      96           0 :             poThisSFDefn->DumpData(pachData + iOffset, nDataSize - iOffset, fp);
      97             : 
      98           0 :             int nBytesConsumed = 0;
      99           0 :             poThisSFDefn->GetDataLength(pachData + iOffset, nDataSize - iOffset,
     100             :                                         &nBytesConsumed);
     101             : 
     102           0 :             iOffset += nBytesConsumed;
     103             :         }
     104             :     }
     105           0 : }
     106             : 
     107             : /************************************************************************/
     108             : /*                          GetSubfieldData()                           */
     109             : /************************************************************************/
     110             : 
     111             : /**
     112             :  * Fetch raw data pointer for a particular subfield of this field.
     113             :  *
     114             :  * The passed DDFSubfieldDefn (poSFDefn) should be acquired from the
     115             :  * DDFFieldDefn corresponding with this field.  This is normally done
     116             :  * once before reading any records.  This method involves a series of
     117             :  * calls to DDFSubfield::GetDataLength() in order to track through the
     118             :  * DDFField data to that belonging to the requested subfield.  This can
     119             :  * be relatively expensive.<p>
     120             :  *
     121             :  * @param poSFDefn The definition of the subfield for which the raw
     122             :  * data pointer is desired.
     123             :  * @param pnMaxBytes The maximum number of bytes that can be accessed from
     124             :  * the returned data pointer is placed in this int, unless it is NULL.
     125             :  * @param iSubfieldIndex The instance of this subfield to fetch.  Use zero
     126             :  * (the default) for the first instance.
     127             :  *
     128             :  * @return A pointer into the DDFField's data that belongs to the subfield.
     129             :  * This returned pointer is invalidated by the next record read
     130             :  * (DDFRecord::ReadRecord()) and the returned pointer should not be freed
     131             :  * by the application.
     132             :  */
     133             : 
     134      787575 : const char *DDFField::GetSubfieldData(const DDFSubfieldDefn *poSFDefn,
     135             :                                       int *pnMaxBytes, int iSubfieldIndex) const
     136             : 
     137             : {
     138      787575 :     if (poSFDefn == nullptr)
     139           0 :         return nullptr;
     140             : 
     141      787575 :     int iOffset = 0;
     142      787575 :     if (iSubfieldIndex > 0 && poDefn->GetFixedWidth() > 0)
     143             :     {
     144      350886 :         iOffset = poDefn->GetFixedWidth() * iSubfieldIndex;
     145      350886 :         iSubfieldIndex = 0;
     146             :     }
     147             : 
     148      853704 :     while (iSubfieldIndex >= 0)
     149             :     {
     150     1543720 :         for (const auto &poThisSFDefn : poDefn->GetSubfields())
     151             :         {
     152     1477590 :             if (nDataSize <= iOffset)
     153             :             {
     154           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     155             :                          "Invalid data size for subfield %s of %s",
     156           0 :                          poThisSFDefn->GetName(), poDefn->GetName());
     157      787575 :                 return nullptr;
     158             :             }
     159             : 
     160     1477590 :             if (poThisSFDefn.get() == poSFDefn && iSubfieldIndex == 0)
     161             :             {
     162      787575 :                 if (pnMaxBytes != nullptr)
     163      787575 :                     *pnMaxBytes = nDataSize - iOffset;
     164             : 
     165      787575 :                 return pachData + iOffset;
     166             :             }
     167             : 
     168      690013 :             int nBytesConsumed = 0;
     169      690013 :             poThisSFDefn->GetDataLength(pachData + iOffset, nDataSize - iOffset,
     170             :                                         &nBytesConsumed);
     171      690013 :             iOffset += nBytesConsumed;
     172             :         }
     173             : 
     174       66129 :         iSubfieldIndex--;
     175             :     }
     176             : 
     177             :     // We didn't find our target subfield or instance!
     178           0 :     return nullptr;
     179             : }
     180             : 
     181             : /************************************************************************/
     182             : /*                           GetRepeatCount()                           */
     183             : /************************************************************************/
     184             : 
     185             : /**
     186             :  * How many times do the subfields of this record repeat?  This
     187             :  * will always be one for non-repeating fields.
     188             :  *
     189             :  * @return The number of times that the subfields of this record occur
     190             :  * in this record.  This will be one for non-repeating fields.
     191             :  *
     192             :  * @see <a href="example.html">8211view example program</a>
     193             :  * for a demonstration of handling repeated fields properly.
     194             :  */
     195             : 
     196       90727 : int DDFField::GetRepeatCount() const
     197             : 
     198             : {
     199       90727 :     if (!poDefn->IsRepeating())
     200        1388 :         return 1;
     201             : 
     202             :     /* -------------------------------------------------------------------- */
     203             :     /*      The occurrence count depends on how many copies of this         */
     204             :     /*      field's list of subfields can fit into the data space.          */
     205             :     /* -------------------------------------------------------------------- */
     206       89339 :     if (poDefn->GetFixedWidth())
     207             :     {
     208       81078 :         return nDataSize / poDefn->GetFixedWidth();
     209             :     }
     210             : 
     211             :     /* -------------------------------------------------------------------- */
     212             :     /*      Note that it may be legal to have repeating variable width      */
     213             :     /*      subfields, but I don't have any samples, so I ignore it for     */
     214             :     /*      now.                                                            */
     215             :     /*                                                                      */
     216             :     /*      The file data/cape_royal_AZ_DEM/1183XREF.DDF has a repeating    */
     217             :     /*      variable length field, but the count is one, so it isn't        */
     218             :     /*      much value for testing.                                         */
     219             :     /* -------------------------------------------------------------------- */
     220        8261 :     int iOffset = 0;
     221        8261 :     int iRepeatCount = 1;
     222             : 
     223             :     while (true)
     224             :     {
     225       23833 :         const int iOffsetBefore = iOffset;
     226       71718 :         for (const auto &poThisSFDefn : poDefn->GetSubfields())
     227             :         {
     228       48088 :             int nBytesConsumed = 0;
     229       48088 :             if (poThisSFDefn->GetWidth() > nDataSize - iOffset)
     230         203 :                 nBytesConsumed = poThisSFDefn->GetWidth();
     231             :             else
     232       47885 :                 poThisSFDefn->GetDataLength(
     233       47885 :                     pachData + iOffset, nDataSize - iOffset, &nBytesConsumed);
     234             : 
     235       48088 :             iOffset += nBytesConsumed;
     236       48088 :             if (iOffset > nDataSize)
     237         203 :                 return iRepeatCount - 1;
     238             :         }
     239       23630 :         if (iOffset == iOffsetBefore)
     240             :         {
     241             :             // Should probably emit error
     242           0 :             return iRepeatCount - 1;
     243             :         }
     244             : 
     245       23630 :         if (iOffset > nDataSize - 2)
     246        8058 :             return iRepeatCount;
     247             : 
     248       15572 :         iRepeatCount++;
     249       15572 :     }
     250             : }
     251             : 
     252             : /************************************************************************/
     253             : /*                          GetInstanceData()                           */
     254             : /************************************************************************/
     255             : 
     256             : /**
     257             :  * Get field instance data and size.
     258             :  *
     259             :  * The returned data pointer and size values are suitable for use with
     260             :  * DDFRecord::SetFieldRaw().
     261             :  *
     262             :  * @param nInstance a value from 0 to GetRepeatCount()-1.
     263             :  * @param pnInstanceSize a location to put the size (in bytes) of the
     264             :  * field instance data returned.  This size will include the unit terminator
     265             :  * (if any), but not the field terminator.  This size pointer may be NULL
     266             :  * if not needed.
     267             :  *
     268             :  * @return the data pointer, or NULL on error.
     269             :  */
     270             : 
     271         366 : const char *DDFField::GetInstanceData(int nInstance, int *pnInstanceSize)
     272             : 
     273             : {
     274         366 :     int nRepeatCount = GetRepeatCount();
     275             : 
     276         366 :     if (nInstance < 0 || nInstance >= nRepeatCount)
     277           0 :         return nullptr;
     278             : 
     279             :     /* -------------------------------------------------------------------- */
     280             :     /*      Special case for fields without subfields (like "0001").  We    */
     281             :     /*      don't currently handle repeating simple fields.                 */
     282             :     /* -------------------------------------------------------------------- */
     283         366 :     if (poDefn->GetSubfieldCount() == 0)
     284             :     {
     285           0 :         const char *pachWrkData = GetData();
     286           0 :         if (pnInstanceSize != nullptr)
     287           0 :             *pnInstanceSize = GetDataSize();
     288           0 :         return pachWrkData;
     289             :     }
     290             : 
     291             :     /* -------------------------------------------------------------------- */
     292             :     /*      Get a pointer to the start of the existing data for this        */
     293             :     /*      iteration of the field.                                         */
     294             :     /* -------------------------------------------------------------------- */
     295         366 :     int nBytesRemaining1 = 0;
     296         366 :     int nBytesRemaining2 = 0;
     297             :     const DDFSubfieldDefn *poFirstSubfield =
     298         366 :         poDefn->GetSubfields().front().get();
     299             : 
     300             :     const char *pachWrkData =
     301         366 :         GetSubfieldData(poFirstSubfield, &nBytesRemaining1, nInstance);
     302         366 :     if (pachWrkData == nullptr)
     303           0 :         return nullptr;
     304             : 
     305             :     /* -------------------------------------------------------------------- */
     306             :     /*      Figure out the size of the entire field instance, including     */
     307             :     /*      unit terminators, but not any trailing field terminator.        */
     308             :     /* -------------------------------------------------------------------- */
     309         366 :     if (pnInstanceSize != nullptr)
     310             :     {
     311             :         const DDFSubfieldDefn *poLastSubfield =
     312         366 :             poDefn->GetSubfields().back().get();
     313             : 
     314             :         const char *pachLastData =
     315         366 :             GetSubfieldData(poLastSubfield, &nBytesRemaining2, nInstance);
     316         366 :         if (pachLastData == nullptr)
     317           0 :             return nullptr;
     318             : 
     319         366 :         int nLastSubfieldWidth = 0;
     320         366 :         poLastSubfield->GetDataLength(pachLastData, nBytesRemaining2,
     321             :                                       &nLastSubfieldWidth);
     322             : 
     323         366 :         *pnInstanceSize =
     324         366 :             nBytesRemaining1 - (nBytesRemaining2 - nLastSubfieldWidth);
     325             :     }
     326             : 
     327         366 :     return pachWrkData;
     328             : }

Generated by: LCOV version 1.14