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

Generated by: LCOV version 1.14