LCOV - code coverage report
Current view: top level - frmts/iso8211 - ddffield.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 65 106 61.3 %
Date: 2024-11-21 22:18:42 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       17691 : void DDFField::Initialize(DDFFieldDefn *poDefnIn, const char *pachDataIn,
      32             :                           int nDataSizeIn)
      33             : 
      34             : {
      35       17691 :     pachData = pachDataIn;
      36       17691 :     nDataSize = nDataSizeIn;
      37       17691 :     poDefn = poDefnIn;
      38       17691 : }
      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)
      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", ((unsigned char *)pachData)[i]);
      72             :         else
      73           0 :             fprintf(fp, "%c", pachData[i]);
      74             :     }
      75             : 
      76           0 :     if (nDataSize > 40)
      77           0 :         fprintf(fp, "...");
      78           0 :     fprintf(fp, "'\n");
      79             : 
      80             :     /* -------------------------------------------------------------------- */
      81             :     /*      dump the data of the subfields.                                 */
      82             :     /* -------------------------------------------------------------------- */
      83           0 :     int iOffset = 0;
      84             : 
      85           0 :     for (int nLoopCount = 0; nLoopCount < GetRepeatCount(); nLoopCount++)
      86             :     {
      87           0 :         if (nLoopCount > nMaxRepeat)
      88             :         {
      89           0 :             fprintf(fp, "      ...\n");
      90           0 :             break;
      91             :         }
      92             : 
      93           0 :         for (int i = 0; i < poDefn->GetSubfieldCount(); i++)
      94             :         {
      95           0 :             poDefn->GetSubfield(i)->DumpData(pachData + iOffset,
      96           0 :                                              nDataSize - iOffset, fp);
      97             : 
      98           0 :             int nBytesConsumed = 0;
      99           0 :             poDefn->GetSubfield(i)->GetDataLength(
     100           0 :                 pachData + iOffset, nDataSize - iOffset, &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       46375 : const char *DDFField::GetSubfieldData(DDFSubfieldDefn *poSFDefn,
     135             :                                       int *pnMaxBytes, int iSubfieldIndex)
     136             : 
     137             : {
     138       46375 :     if (poSFDefn == nullptr)
     139           0 :         return nullptr;
     140             : 
     141       46375 :     int iOffset = 0;
     142       46375 :     if (iSubfieldIndex > 0 && poDefn->GetFixedWidth() > 0)
     143             :     {
     144        7932 :         iOffset = poDefn->GetFixedWidth() * iSubfieldIndex;
     145        7932 :         iSubfieldIndex = 0;
     146             :     }
     147             : 
     148       47453 :     while (iSubfieldIndex >= 0)
     149             :     {
     150      133528 :         for (int iSF = 0; iSF < poDefn->GetSubfieldCount(); iSF++)
     151             :         {
     152      132450 :             DDFSubfieldDefn *poThisSFDefn = poDefn->GetSubfield(iSF);
     153             : 
     154      132450 :             if (nDataSize <= iOffset)
     155             :             {
     156           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     157             :                          "Invalid data size for subfield %s of %s",
     158           0 :                          poThisSFDefn->GetName(), poDefn->GetName());
     159       46375 :                 return nullptr;
     160             :             }
     161             : 
     162      132450 :             if (poThisSFDefn == poSFDefn && iSubfieldIndex == 0)
     163             :             {
     164       46375 :                 if (pnMaxBytes != nullptr)
     165       46357 :                     *pnMaxBytes = nDataSize - iOffset;
     166             : 
     167       46375 :                 return pachData + iOffset;
     168             :             }
     169             : 
     170       86075 :             int nBytesConsumed = 0;
     171       86075 :             poThisSFDefn->GetDataLength(pachData + iOffset, nDataSize - iOffset,
     172             :                                         &nBytesConsumed);
     173       86075 :             iOffset += nBytesConsumed;
     174             :         }
     175             : 
     176        1078 :         iSubfieldIndex--;
     177             :     }
     178             : 
     179             :     // We didn't find our target subfield or instance!
     180           0 :     return nullptr;
     181             : }
     182             : 
     183             : /************************************************************************/
     184             : /*                           GetRepeatCount()                           */
     185             : /************************************************************************/
     186             : 
     187             : /**
     188             :  * How many times do the subfields of this record repeat?  This
     189             :  * will always be one for non-repeating fields.
     190             :  *
     191             :  * @return The number of times that the subfields of this record occur
     192             :  * in this record.  This will be one for non-repeating fields.
     193             :  *
     194             :  * @see <a href="example.html">8211view example program</a>
     195             :  * for a demonstration of handling repeated fields properly.
     196             :  */
     197             : 
     198        6907 : int DDFField::GetRepeatCount()
     199             : 
     200             : {
     201        6907 :     if (!poDefn->IsRepeating())
     202         566 :         return 1;
     203             : 
     204             :     /* -------------------------------------------------------------------- */
     205             :     /*      The occurrence count depends on how many copies of this         */
     206             :     /*      field's list of subfields can fit into the data space.          */
     207             :     /* -------------------------------------------------------------------- */
     208        6341 :     if (poDefn->GetFixedWidth())
     209             :     {
     210        5183 :         return nDataSize / poDefn->GetFixedWidth();
     211             :     }
     212             : 
     213             :     /* -------------------------------------------------------------------- */
     214             :     /*      Note that it may be legal to have repeating variable width      */
     215             :     /*      subfields, but I don't have any samples, so I ignore it for     */
     216             :     /*      now.                                                            */
     217             :     /*                                                                      */
     218             :     /*      The file data/cape_royal_AZ_DEM/1183XREF.DDF has a repeating    */
     219             :     /*      variable length field, but the count is one, so it isn't        */
     220             :     /*      much value for testing.                                         */
     221             :     /* -------------------------------------------------------------------- */
     222        1158 :     int iOffset = 0;
     223        1158 :     int iRepeatCount = 1;
     224             : 
     225             :     while (true)
     226             :     {
     227        1439 :         const int iOffsetBefore = iOffset;
     228        4581 :         for (int iSF = 0; iSF < poDefn->GetSubfieldCount(); iSF++)
     229             :         {
     230        3305 :             DDFSubfieldDefn *poThisSFDefn = poDefn->GetSubfield(iSF);
     231             : 
     232        3305 :             int nBytesConsumed = 0;
     233        3305 :             if (poThisSFDefn->GetWidth() > nDataSize - iOffset)
     234         163 :                 nBytesConsumed = poThisSFDefn->GetWidth();
     235             :             else
     236        3142 :                 poThisSFDefn->GetDataLength(
     237        3142 :                     pachData + iOffset, nDataSize - iOffset, &nBytesConsumed);
     238             : 
     239        3305 :             iOffset += nBytesConsumed;
     240        3305 :             if (iOffset > nDataSize)
     241         163 :                 return iRepeatCount - 1;
     242             :         }
     243        1276 :         if (iOffset == iOffsetBefore)
     244             :         {
     245             :             // Should probably emit error
     246           0 :             return iRepeatCount - 1;
     247             :         }
     248             : 
     249        1276 :         if (iOffset > nDataSize - 2)
     250         995 :             return iRepeatCount;
     251             : 
     252         281 :         iRepeatCount++;
     253         281 :     }
     254             : }
     255             : 
     256             : /************************************************************************/
     257             : /*                          GetInstanceData()                           */
     258             : /************************************************************************/
     259             : 
     260             : /**
     261             :  * Get field instance data and size.
     262             :  *
     263             :  * The returned data pointer and size values are suitable for use with
     264             :  * DDFRecord::SetFieldRaw().
     265             :  *
     266             :  * @param nInstance a value from 0 to GetRepeatCount()-1.
     267             :  * @param pnInstanceSize a location to put the size (in bytes) of the
     268             :  * field instance data returned.  This size will include the unit terminator
     269             :  * (if any), but not the field terminator.  This size pointer may be NULL
     270             :  * if not needed.
     271             :  *
     272             :  * @return the data pointer, or NULL on error.
     273             :  */
     274             : 
     275         257 : const char *DDFField::GetInstanceData(int nInstance, int *pnInstanceSize)
     276             : 
     277             : {
     278         257 :     int nRepeatCount = GetRepeatCount();
     279             : 
     280         257 :     if (nInstance < 0 || nInstance >= nRepeatCount)
     281           0 :         return nullptr;
     282             : 
     283             :     /* -------------------------------------------------------------------- */
     284             :     /*      Special case for fields without subfields (like "0001").  We    */
     285             :     /*      don't currently handle repeating simple fields.                 */
     286             :     /* -------------------------------------------------------------------- */
     287         257 :     if (poDefn->GetSubfieldCount() == 0)
     288             :     {
     289           0 :         const char *pachWrkData = GetData();
     290           0 :         if (pnInstanceSize != nullptr)
     291           0 :             *pnInstanceSize = GetDataSize();
     292           0 :         return pachWrkData;
     293             :     }
     294             : 
     295             :     /* -------------------------------------------------------------------- */
     296             :     /*      Get a pointer to the start of the existing data for this        */
     297             :     /*      iteration of the field.                                         */
     298             :     /* -------------------------------------------------------------------- */
     299         257 :     int nBytesRemaining1 = 0;
     300         257 :     int nBytesRemaining2 = 0;
     301         257 :     DDFSubfieldDefn *poFirstSubfield = poDefn->GetSubfield(0);
     302             : 
     303             :     const char *pachWrkData =
     304         257 :         GetSubfieldData(poFirstSubfield, &nBytesRemaining1, nInstance);
     305         257 :     if (pachWrkData == nullptr)
     306           0 :         return nullptr;
     307             : 
     308             :     /* -------------------------------------------------------------------- */
     309             :     /*      Figure out the size of the entire field instance, including     */
     310             :     /*      unit terminators, but not any trailing field terminator.        */
     311             :     /* -------------------------------------------------------------------- */
     312         257 :     if (pnInstanceSize != nullptr)
     313             :     {
     314             :         DDFSubfieldDefn *poLastSubfield =
     315         257 :             poDefn->GetSubfield(poDefn->GetSubfieldCount() - 1);
     316             : 
     317             :         const char *pachLastData =
     318         257 :             GetSubfieldData(poLastSubfield, &nBytesRemaining2, nInstance);
     319         257 :         if (pachLastData == nullptr)
     320           0 :             return nullptr;
     321             : 
     322         257 :         int nLastSubfieldWidth = 0;
     323         257 :         poLastSubfield->GetDataLength(pachLastData, nBytesRemaining2,
     324             :                                       &nLastSubfieldWidth);
     325             : 
     326         257 :         *pnInstanceSize =
     327         257 :             nBytesRemaining1 - (nBytesRemaining2 - nLastSubfieldWidth);
     328             :     }
     329             : 
     330         257 :     return pachWrkData;
     331             : }

Generated by: LCOV version 1.14