LCOV - code coverage report
Current view: top level - frmts/iso8211 - ddfsubfielddefn.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 179 339 52.8 %
Date: 2025-05-31 00:00:17 Functions: 11 14 78.6 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  ISO 8211 Access
       4             :  * Purpose:  Implements the DDFSubfieldDefn class.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1999, Frank Warmerdam
       9             :  * Copyright (c) 2011-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_port.h"
      15             : #include "iso8211.h"
      16             : 
      17             : #include <cstdio>
      18             : #include <cstdlib>
      19             : #include <cstring>
      20             : 
      21             : #include <algorithm>
      22             : 
      23             : #include "cpl_conv.h"
      24             : #include "cpl_error.h"
      25             : #include "cpl_string.h"
      26             : 
      27             : /************************************************************************/
      28             : /*                          DDFSubfieldDefn()                           */
      29             : /************************************************************************/
      30             : 
      31        7089 : DDFSubfieldDefn::DDFSubfieldDefn()
      32       14178 :     : pszName(nullptr), pszFormatString(CPLStrdup("")), eType(DDFString),
      33             :       eBinaryFormat(NotBinary), bIsVariable(TRUE),
      34             :       chFormatDelimiter(DDF_UNIT_TERMINATOR), nFormatWidth(0), nMaxBufChars(0),
      35        7089 :       pachBuffer(nullptr)
      36             : {
      37        7089 : }
      38             : 
      39             : /************************************************************************/
      40             : /*                          ~DDFSubfieldDefn()                          */
      41             : /************************************************************************/
      42             : 
      43       14178 : DDFSubfieldDefn::~DDFSubfieldDefn()
      44             : 
      45             : {
      46        7089 :     CPLFree(pszName);
      47        7089 :     CPLFree(pszFormatString);
      48        7089 :     CPLFree(pachBuffer);
      49        7089 : }
      50             : 
      51             : /************************************************************************/
      52             : /*                              SetName()                               */
      53             : /************************************************************************/
      54             : 
      55        7089 : void DDFSubfieldDefn::SetName(const char *pszNewName)
      56             : 
      57             : {
      58             :     int i;
      59             : 
      60        7089 :     CPLFree(pszName);
      61             : 
      62        7089 :     pszName = CPLStrdup(pszNewName);
      63             : 
      64        7089 :     for (i = static_cast<int>(strlen(pszName)) - 1; i > 0 && pszName[i] == ' ';
      65             :          i--)
      66           0 :         pszName[i] = '\0';
      67        7089 : }
      68             : 
      69             : /************************************************************************/
      70             : /*                             SetFormat()                              */
      71             : /*                                                                      */
      72             : /*      While interpreting the format string we don't support:          */
      73             : /*                                                                      */
      74             : /*       o Passing an explicit terminator for variable length field.    */
      75             : /*       o 'X' for unused data ... this should really be filtered       */
      76             : /*         out by DDFFieldDefn::ApplyFormats(), but isn't.              */
      77             : /*       o 'B' bitstrings that aren't a multiple of eight.              */
      78             : /************************************************************************/
      79             : 
      80        7089 : int DDFSubfieldDefn::SetFormat(const char *pszFormat)
      81             : 
      82             : {
      83        7089 :     CPLFree(pszFormatString);
      84        7089 :     pszFormatString = CPLStrdup(pszFormat);
      85             : 
      86             :     /* -------------------------------------------------------------------- */
      87             :     /*      These values will likely be used.                               */
      88             :     /* -------------------------------------------------------------------- */
      89        7089 :     if (pszFormatString[1] == '(')
      90             :     {
      91        2470 :         nFormatWidth = atoi(pszFormatString + 2);
      92        2470 :         if (nFormatWidth < 0)
      93             :         {
      94           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Format width %s is invalid.",
      95           0 :                      pszFormatString + 2);
      96           0 :             return FALSE;
      97             :         }
      98        2470 :         bIsVariable = nFormatWidth == 0;
      99             :     }
     100             :     else
     101        4619 :         bIsVariable = TRUE;
     102             : 
     103             :     /* -------------------------------------------------------------------- */
     104             :     /*      Interpret the format string.                                    */
     105             :     /* -------------------------------------------------------------------- */
     106        7089 :     switch (pszFormatString[0])
     107             :     {
     108        1638 :         case 'A':
     109             :         case 'C':  // It isn't clear to me how this is different than 'A'
     110        1638 :             eType = DDFString;
     111        1638 :             break;
     112             : 
     113         317 :         case 'R':
     114         317 :             eType = DDFFloat;
     115         317 :             break;
     116             : 
     117        1151 :         case 'I':
     118             :         case 'S':
     119        1151 :             eType = DDFInt;
     120        1151 :             break;
     121             : 
     122        3983 :         case 'B':
     123             :         case 'b':
     124             :             // Is the width expressed in bits? (is it a bitstring)
     125        3983 :             bIsVariable = FALSE;
     126        3983 :             if (pszFormatString[1] == '\0')
     127           0 :                 return FALSE;
     128             : 
     129        3983 :             if (pszFormatString[1] == '(')
     130             :             {
     131         159 :                 nFormatWidth = atoi(pszFormatString + 2);
     132         159 :                 if (nFormatWidth < 0 || nFormatWidth % 8 != 0)
     133             :                 {
     134           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
     135             :                              "Format width %s is invalid.",
     136           0 :                              pszFormatString + 2);
     137           0 :                     return FALSE;
     138             :                 }
     139             : 
     140         159 :                 nFormatWidth = nFormatWidth / 8;
     141         159 :                 eBinaryFormat = SInt;  // good default, works for SDTS.
     142             : 
     143         159 :                 if (nFormatWidth < 5)
     144           0 :                     eType = DDFInt;
     145             :                 else
     146         159 :                     eType = DDFBinaryString;
     147             :             }
     148             : 
     149             :             // or do we have a binary type indicator? (is it binary)
     150             :             else
     151             :             {
     152        3824 :                 if (pszFormatString[1] < '0' || pszFormatString[1] > '5')
     153             :                 {
     154           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
     155             :                              "Binary format = %c is invalid.",
     156           0 :                              pszFormatString[1]);
     157           0 :                     return FALSE;
     158             :                 }
     159        3824 :                 eBinaryFormat = (DDFBinaryFormat)(pszFormatString[1] - '0');
     160        3824 :                 nFormatWidth = atoi(pszFormatString + 2);
     161        3824 :                 if (nFormatWidth < 0)
     162             :                 {
     163           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
     164             :                              "Format width %s is invalid.",
     165           0 :                              pszFormatString + 2);
     166           0 :                     return FALSE;
     167             :                 }
     168             : 
     169        3824 :                 if (eBinaryFormat == SInt || eBinaryFormat == UInt)
     170        3824 :                     eType = DDFInt;
     171             :                 else
     172           0 :                     eType = DDFFloat;
     173             :             }
     174        3983 :             break;
     175             : 
     176           0 :         case 'X':
     177             :             // 'X' is extra space, and should not be directly assigned to a
     178             :             // subfield ... I have not encountered it in use yet though.
     179           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     180             :                      "Format type of `%c' not supported.\n",
     181           0 :                      pszFormatString[0]);
     182             : 
     183           0 :             return FALSE;
     184             : 
     185           0 :         default:
     186           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     187             :                      "Format type of `%c' not recognised.\n",
     188           0 :                      pszFormatString[0]);
     189             : 
     190           0 :             return FALSE;
     191             :     }
     192             : 
     193        7089 :     return TRUE;
     194             : }
     195             : 
     196             : /************************************************************************/
     197             : /*                                Dump()                                */
     198             : /************************************************************************/
     199             : 
     200             : /**
     201             :  * Write out subfield definition info to debugging file.
     202             :  *
     203             :  * A variety of information about this field definition is written to the
     204             :  * give debugging file handle.
     205             :  *
     206             :  * @param fp The standard IO file handle to write to.  i.e. stderr
     207             :  */
     208             : 
     209           0 : void DDFSubfieldDefn::Dump(FILE *fp)
     210             : 
     211             : {
     212           0 :     fprintf(fp, "    DDFSubfieldDefn:\n");
     213           0 :     fprintf(fp, "        Label = `%s'\n", pszName);
     214           0 :     fprintf(fp, "        FormatString = `%s'\n", pszFormatString);
     215           0 : }
     216             : 
     217             : /************************************************************************/
     218             : /*                           GetDataLength()                            */
     219             : /*                                                                      */
     220             : /*      This method will scan for the end of a variable field.          */
     221             : /************************************************************************/
     222             : 
     223             : /**
     224             :  * Scan for the end of variable length data.  Given a pointer to the data
     225             :  * for this subfield (from within a DDFRecord) this method will return the
     226             :  * number of bytes which are data for this subfield.  The number of bytes
     227             :  * consumed as part of this field can also be fetched.  This number may
     228             :  * be one longer than the length if there is a terminator character
     229             :  * used.<p>
     230             :  *
     231             :  * This method is mainly for internal use, or for applications which
     232             :  * want the raw binary data to interpret themselves.  Otherwise use one
     233             :  * of ExtractStringData(), ExtractIntData() or ExtractFloatData().
     234             :  *
     235             :  * @param pachSourceData The pointer to the raw data for this field.  This
     236             :  * may have come from DDFRecord::GetData(), taking into account skip factors
     237             :  * over previous subfields data.
     238             :  * @param nMaxBytes The maximum number of bytes that are accessible after
     239             :  * pachSourceData.
     240             :  * @param pnConsumedBytes Pointer to an integer into which the number of
     241             :  * bytes consumed by this field should be written.  May be NULL to ignore.
     242             :  *
     243             :  * @return The number of bytes at pachSourceData which are actual data for
     244             :  * this record (not including unit, or field terminator).
     245             :  */
     246             : 
     247       69083 : int DDFSubfieldDefn::GetDataLength(const char *pachSourceData, int nMaxBytes,
     248             :                                    int *pnConsumedBytes) const
     249             : 
     250             : {
     251       69083 :     if (!bIsVariable)
     252             :     {
     253       62056 :         if (nFormatWidth > nMaxBytes)
     254             :         {
     255           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     256             :                      "Only %d bytes available for subfield %s with\n"
     257             :                      "format string %s ... returning shortened data.",
     258           0 :                      nMaxBytes, pszName, pszFormatString);
     259             : 
     260           0 :             if (pnConsumedBytes != nullptr)
     261           0 :                 *pnConsumedBytes = nMaxBytes;
     262             : 
     263           0 :             return nMaxBytes;
     264             :         }
     265             :         else
     266             :         {
     267       62056 :             if (pnConsumedBytes != nullptr)
     268       61754 :                 *pnConsumedBytes = nFormatWidth;
     269             : 
     270       62056 :             return nFormatWidth;
     271             :         }
     272             :     }
     273             :     else
     274             :     {
     275        7027 :         int nLength = 0;
     276        7027 :         int bAsciiField = TRUE;
     277        7027 :         int extraConsumedBytes = 0;
     278             : 
     279             :         /* We only check for the field terminator because of some buggy
     280             :          * datasets with missing format terminators.  However, we have found
     281             :          * the field terminator and unit terminators are legal characters
     282             :          * within the fields of some extended datasets (such as JP34NC94.000).
     283             :          * So we don't check for the field terminator and unit terminators as
     284             :          * a single byte if the field appears to be multi-byte which we
     285             :          * establish by checking for the buffer ending with 0x1e 0x00 (a
     286             :          * two byte field terminator).
     287             :          *
     288             :          * In the case of S57, the subfield ATVL of the NATF field can be
     289             :          * encoded in lexical level 2 (see S57 specification, Edition 3.1,
     290             :          * paragraph 2.4 and 2.5). In that case the Unit Terminator and Field
     291             :          * Terminator are followed by the NULL character.
     292             :          * A better fix would be to read the NALL tag in the DSSI to check
     293             :          * that the lexical level is 2, instead of relying on the value of
     294             :          * the first byte as we are doing - but that is not information
     295             :          * that is available at the libiso8211 level (bug #1526)
     296             :          */
     297             : 
     298             :         // If the whole field ends with 0x1e 0x00 then we assume this
     299             :         // field is a double byte character set.
     300        7027 :         if (nMaxBytes > 1 &&
     301        7027 :             (pachSourceData[nMaxBytes - 2] == chFormatDelimiter ||
     302        1041 :              pachSourceData[nMaxBytes - 2] == DDF_FIELD_TERMINATOR) &&
     303        5988 :             pachSourceData[nMaxBytes - 1] == 0x00)
     304           2 :             bAsciiField = FALSE;
     305             : 
     306             :         //        if( !bAsciiField )
     307             :         //            CPLDebug( "ISO8211", "Non-ASCII field detected." );
     308             : 
     309       25841 :         while (nLength < nMaxBytes)
     310             :         {
     311       25841 :             if (bAsciiField)
     312             :             {
     313       25581 :                 if (pachSourceData[nLength] == chFormatDelimiter ||
     314       18556 :                     pachSourceData[nLength] == DDF_FIELD_TERMINATOR)
     315             :                     break;
     316             :             }
     317             :             else
     318             :             {
     319         260 :                 if (nLength > 0 &&
     320         258 :                     (pachSourceData[nLength - 1] == chFormatDelimiter ||
     321         254 :                      pachSourceData[nLength - 1] == DDF_FIELD_TERMINATOR) &&
     322           4 :                     pachSourceData[nLength] == 0)
     323             :                 {
     324             :                     // Suck up the field terminator if one follows
     325             :                     // or else it will be interpreted as a new subfield.
     326             :                     // This is a pretty ugly counter-intuitive hack!
     327           2 :                     if (nLength + 1 < nMaxBytes &&
     328           2 :                         pachSourceData[nLength + 1] == DDF_FIELD_TERMINATOR)
     329           2 :                         extraConsumedBytes++;
     330           2 :                     break;
     331             :                 }
     332             :             }
     333             : 
     334       18814 :             nLength++;
     335             :         }
     336             : 
     337        7027 :         if (pnConsumedBytes != nullptr)
     338             :         {
     339        5816 :             if (nMaxBytes == 0)
     340           0 :                 *pnConsumedBytes = nLength + extraConsumedBytes;
     341             :             else
     342        5816 :                 *pnConsumedBytes = nLength + extraConsumedBytes + 1;
     343             :         }
     344             : 
     345        7027 :         return nLength;
     346             :     }
     347             : }
     348             : 
     349             : /************************************************************************/
     350             : /*                         ExtractStringData()                          */
     351             : /************************************************************************/
     352             : 
     353             : /**
     354             :  * Extract a zero terminated string containing the data for this subfield.
     355             :  * Given a pointer to the data
     356             :  * for this subfield (from within a DDFRecord) this method will return the
     357             :  * data for this subfield.  The number of bytes
     358             :  * consumed as part of this field can also be fetched.  This number may
     359             :  * be one longer than the string length if there is a terminator character
     360             :  * used.<p>
     361             :  *
     362             :  * This function will return the raw binary data of a subfield for
     363             :  * types other than DDFString, including data past zero chars.  This is
     364             :  * the standard way of extracting DDFBinaryString subfields for instance.<p>
     365             :  *
     366             :  * CAUTION: this method is not thread safe as it updates mutable member
     367             :  * variables.
     368             :  *
     369             :  * @param pachSourceData The pointer to the raw data for this field.  This
     370             :  * may have come from DDFRecord::GetData(), taking into account skip factors
     371             :  * over previous subfields data.
     372             :  * @param nMaxBytes The maximum number of bytes that are accessible after
     373             :  * pachSourceData.
     374             :  * @param pnConsumedBytes Pointer to an integer into which the number of
     375             :  * bytes consumed by this field should be written.  May be NULL to ignore.
     376             :  * This is used as a skip factor to increment pachSourceData to point to the
     377             :  * next subfields data.
     378             :  *
     379             :  * @return A pointer to a buffer containing the data for this field.  The
     380             :  * returned pointer is to an internal buffer which is invalidated on the
     381             :  * next ExtractStringData() call on this DDFSubfieldDefn().  It should not
     382             :  * be freed by the application.
     383             :  *
     384             :  * @see ExtractIntData(), ExtractFloatData()
     385             :  */
     386             : 
     387        2053 : const char *DDFSubfieldDefn::ExtractStringData(const char *pachSourceData,
     388             :                                                int nMaxBytes,
     389             :                                                int *pnConsumedBytes) const
     390             : 
     391             : {
     392        2053 :     int nLength = GetDataLength(pachSourceData, nMaxBytes, pnConsumedBytes);
     393             : 
     394             :     /* -------------------------------------------------------------------- */
     395             :     /*      Do we need to grow the buffer.                                  */
     396             :     /* -------------------------------------------------------------------- */
     397        2053 :     if (nMaxBufChars < nLength + 1)
     398             :     {
     399         722 :         CPLFree(pachBuffer);
     400             : 
     401         722 :         nMaxBufChars = nLength + 1;
     402         722 :         pachBuffer = (char *)CPLMalloc(nMaxBufChars);
     403             :     }
     404             : 
     405             :     /* -------------------------------------------------------------------- */
     406             :     /*      Copy the data to the buffer.  We use memcpy() so that it        */
     407             :     /*      will work for binary data.                                      */
     408             :     /* -------------------------------------------------------------------- */
     409        2053 :     memcpy(pachBuffer, pachSourceData, nLength);
     410        2053 :     pachBuffer[nLength] = '\0';
     411             : 
     412        2053 :     return pachBuffer;
     413             : }
     414             : 
     415             : /************************************************************************/
     416             : /*                          ExtractFloatData()                          */
     417             : /************************************************************************/
     418             : 
     419             : /**
     420             :  * Extract a subfield value as a float.  Given a pointer to the data
     421             :  * for this subfield (from within a DDFRecord) this method will return the
     422             :  * floating point data for this subfield.  The number of bytes
     423             :  * consumed as part of this field can also be fetched.  This method may be
     424             :  * called for any type of subfield, and will return zero if the subfield is
     425             :  * not numeric.
     426             :  *
     427             :  * @param pachSourceData The pointer to the raw data for this field.  This
     428             :  * may have come from DDFRecord::GetData(), taking into account skip factors
     429             :  * over previous subfields data.
     430             :  * @param nMaxBytes The maximum number of bytes that are accessible after
     431             :  * pachSourceData.
     432             :  * @param pnConsumedBytes Pointer to an integer into which the number of
     433             :  * bytes consumed by this field should be written.  May be NULL to ignore.
     434             :  * This is used as a skip factor to increment pachSourceData to point to the
     435             :  * next subfields data.
     436             :  *
     437             :  * @return The subfield's numeric value (or zero if it isn't numeric).
     438             :  *
     439             :  * @see ExtractIntData(), ExtractStringData()
     440             :  */
     441             : 
     442         113 : double DDFSubfieldDefn::ExtractFloatData(const char *pachSourceData,
     443             :                                          int nMaxBytes,
     444             :                                          int *pnConsumedBytes) const
     445             : 
     446             : {
     447         113 :     switch (pszFormatString[0])
     448             :     {
     449         113 :         case 'A':
     450             :         case 'I':
     451             :         case 'R':
     452             :         case 'S':
     453             :         case 'C':
     454         113 :             return CPLAtof(
     455         113 :                 ExtractStringData(pachSourceData, nMaxBytes, pnConsumedBytes));
     456             : 
     457           0 :         case 'B':
     458             :         case 'b':
     459             :         {
     460             :             unsigned char abyData[8];
     461           0 :             void *pabyData = abyData;
     462             : 
     463           0 :             if (nFormatWidth > nMaxBytes)
     464             :             {
     465           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
     466             :                          "Attempt to extract float subfield %s with format %s\n"
     467             :                          "failed as only %d bytes available.  Using zero.",
     468           0 :                          pszName, pszFormatString, nMaxBytes);
     469           0 :                 return 0;
     470             :             }
     471           0 :             if (nFormatWidth > static_cast<int>(sizeof(abyData)))
     472             :             {
     473           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     474           0 :                          "Format width %d too large", nFormatWidth);
     475           0 :                 return 0;
     476             :             }
     477             : 
     478           0 :             if (pnConsumedBytes != nullptr)
     479           0 :                 *pnConsumedBytes = nFormatWidth;
     480             : 
     481             :                 // Byte swap the data if it isn't in machine native format.
     482             :                 // In any event we copy it into our buffer to ensure it is
     483             :                 // word aligned.
     484             : #ifdef CPL_LSB
     485           0 :             if (pszFormatString[0] == 'B')
     486             : #else
     487             :             if (pszFormatString[0] == 'b')
     488             : #endif
     489             :             {
     490           0 :                 for (int i = 0; i < nFormatWidth; i++)
     491           0 :                     abyData[nFormatWidth - i - 1] = pachSourceData[i];
     492             :             }
     493             :             else
     494             :             {
     495           0 :                 memcpy(abyData, pachSourceData, nFormatWidth);
     496             :             }
     497             : 
     498             :             // Interpret the bytes of data.
     499           0 :             switch (eBinaryFormat)
     500             :             {
     501           0 :                 case UInt:
     502           0 :                     if (nFormatWidth == 1)
     503           0 :                         return abyData[0];
     504           0 :                     else if (nFormatWidth == 2)
     505           0 :                         return *((GUInt16 *)pabyData);
     506           0 :                     else if (nFormatWidth == 4)
     507           0 :                         return *((GUInt32 *)pabyData);
     508             :                     else
     509             :                     {
     510             :                         // CPLAssert( false );
     511           0 :                         return 0.0;
     512             :                     }
     513             : 
     514           0 :                 case SInt:
     515           0 :                     if (nFormatWidth == 1)
     516           0 :                         return *((signed char *)abyData);
     517           0 :                     else if (nFormatWidth == 2)
     518           0 :                         return *((GInt16 *)pabyData);
     519           0 :                     else if (nFormatWidth == 4)
     520           0 :                         return *((GInt32 *)pabyData);
     521             :                     else
     522             :                     {
     523             :                         // CPLAssert( false );
     524           0 :                         return 0.0;
     525             :                     }
     526             : 
     527           0 :                 case FloatReal:
     528           0 :                     if (nFormatWidth == 4)
     529           0 :                         return *((float *)pabyData);
     530           0 :                     else if (nFormatWidth == 8)
     531           0 :                         return *((double *)pabyData);
     532             :                     else
     533             :                     {
     534             :                         // CPLAssert( false );
     535           0 :                         return 0.0;
     536             :                     }
     537             : 
     538           0 :                 case NotBinary:
     539             :                 case FPReal:
     540             :                 case FloatComplex:
     541             :                     // CPLAssert( false );
     542           0 :                     return 0.0;
     543             :             }
     544           0 :             break;
     545             :             // end of 'b'/'B' case.
     546             :         }
     547             : 
     548           0 :         default:
     549             :             // CPLAssert( false );
     550           0 :             return 0.0;
     551             :     }
     552             : 
     553             :     // CPLAssert( false );
     554           0 :     return 0.0;
     555             : }
     556             : 
     557             : /************************************************************************/
     558             : /*                           ExtractIntData()                           */
     559             : /************************************************************************/
     560             : 
     561             : /**
     562             :  * Extract a subfield value as an integer.  Given a pointer to the data
     563             :  * for this subfield (from within a DDFRecord) this method will return the
     564             :  * int data for this subfield.  The number of bytes
     565             :  * consumed as part of this field can also be fetched.  This method may be
     566             :  * called for any type of subfield, and will return zero if the subfield is
     567             :  * not numeric.
     568             :  *
     569             :  * @param pachSourceData The pointer to the raw data for this field.  This
     570             :  * may have come from DDFRecord::GetData(), taking into account skip factors
     571             :  * over previous subfields data.
     572             :  * @param nMaxBytes The maximum number of bytes that are accessible after
     573             :  * pachSourceData.
     574             :  * @param pnConsumedBytes Pointer to an integer into which the number of
     575             :  * bytes consumed by this field should be written.  May be NULL to ignore.
     576             :  * This is used as a skip factor to increment pachSourceData to point to the
     577             :  * next subfields data.
     578             :  *
     579             :  * @return The subfield's numeric value (or zero if it isn't numeric).
     580             :  *
     581             :  * @see ExtractFloatData(), ExtractStringData()
     582             :  */
     583             : 
     584       29672 : int DDFSubfieldDefn::ExtractIntData(const char *pachSourceData, int nMaxBytes,
     585             :                                     int *pnConsumedBytes) const
     586             : 
     587             : {
     588       29672 :     switch (pszFormatString[0])
     589             :     {
     590         427 :         case 'A':
     591             :         case 'I':
     592             :         case 'R':
     593             :         case 'S':
     594             :         case 'C':
     595         427 :             return atoi(
     596         427 :                 ExtractStringData(pachSourceData, nMaxBytes, pnConsumedBytes));
     597             : 
     598       29245 :         case 'B':
     599             :         case 'b':
     600             :         {
     601             :             unsigned char abyData[8];
     602       29245 :             void *pabyData = abyData;
     603             : 
     604       29245 :             if (nFormatWidth > nMaxBytes ||
     605       29245 :                 nFormatWidth >= (int)sizeof(abyData))
     606             :             {
     607           0 :                 CPLError(
     608             :                     CE_Warning, CPLE_AppDefined,
     609             :                     "Attempt to extract int subfield %s with format %s\n"
     610             :                     "failed as only %d bytes available.  Using zero.",
     611           0 :                     pszName, pszFormatString,
     612           0 :                     std::min(nMaxBytes, static_cast<int>(sizeof(abyData))));
     613       29245 :                 return 0;
     614             :             }
     615             : 
     616       29245 :             if (pnConsumedBytes != nullptr)
     617       26489 :                 *pnConsumedBytes = nFormatWidth;
     618             : 
     619             :                 // Byte swap the data if it isn't in machine native format.
     620             :                 // In any event we copy it into our buffer to ensure it is
     621             :                 // word aligned.
     622             : #ifdef CPL_LSB
     623       29245 :             if (pszFormatString[0] == 'B')
     624             : #else
     625             :             if (pszFormatString[0] == 'b')
     626             : #endif
     627             :             {
     628           0 :                 for (int i = 0; i < nFormatWidth; i++)
     629           0 :                     abyData[nFormatWidth - i - 1] = pachSourceData[i];
     630             :             }
     631             :             else
     632             :             {
     633       29245 :                 memcpy(abyData, pachSourceData, nFormatWidth);
     634             :             }
     635             : 
     636             :             // Interpret the bytes of data.
     637       29245 :             switch (eBinaryFormat)
     638             :             {
     639       13630 :                 case UInt:
     640       13630 :                     if (nFormatWidth == 4)
     641        3405 :                         return (int)*((GUInt32 *)pabyData);
     642       10225 :                     else if (nFormatWidth == 1)
     643        4887 :                         return abyData[0];
     644        5338 :                     else if (nFormatWidth == 2)
     645        5338 :                         return *((GUInt16 *)pabyData);
     646             :                     else
     647             :                     {
     648             :                         // CPLAssert( false );
     649           0 :                         return 0;
     650             :                     }
     651             : 
     652       15615 :                 case SInt:
     653       15615 :                     if (nFormatWidth == 4)
     654       15615 :                         return *((GInt32 *)pabyData);
     655           0 :                     else if (nFormatWidth == 1)
     656           0 :                         return *((signed char *)abyData);
     657           0 :                     else if (nFormatWidth == 2)
     658           0 :                         return *((GInt16 *)pabyData);
     659             :                     else
     660             :                     {
     661             :                         // CPLAssert( false );
     662           0 :                         return 0;
     663             :                     }
     664             : 
     665           0 :                 case FloatReal:
     666           0 :                     if (nFormatWidth == 4)
     667           0 :                         return (int)*((float *)pabyData);
     668           0 :                     else if (nFormatWidth == 8)
     669           0 :                         return (int)*((double *)pabyData);
     670             :                     else
     671             :                     {
     672             :                         // CPLAssert( false );
     673           0 :                         return 0;
     674             :                     }
     675             : 
     676           0 :                 case NotBinary:
     677             :                 case FPReal:
     678             :                 case FloatComplex:
     679             :                     // CPLAssert( false );
     680           0 :                     return 0;
     681             :             }
     682           0 :             break;
     683             :             // end of 'b'/'B' case.
     684             :         }
     685             : 
     686           0 :         default:
     687             :             // CPLAssert( false );
     688           0 :             return 0;
     689             :     }
     690             : 
     691             :     // CPLAssert( false );
     692           0 :     return 0;
     693             : }
     694             : 
     695             : /************************************************************************/
     696             : /*                              DumpData()                              */
     697             : /*                                                                      */
     698             : /*      Dump the instance data for this subfield from a data            */
     699             : /*      record.  This fits into the output dump stream of a DDFField.   */
     700             : /************************************************************************/
     701             : 
     702             : /**
     703             :  * Dump subfield value to debugging file.
     704             :  *
     705             :  * @param pachData Pointer to data for this subfield.
     706             :  * @param nMaxBytes Maximum number of bytes available in pachData.
     707             :  * @param fp File to write report to.
     708             :  */
     709             : 
     710           0 : void DDFSubfieldDefn::DumpData(const char *pachData, int nMaxBytes,
     711             :                                FILE *fp) const
     712             : 
     713             : {
     714           0 :     if (nMaxBytes < 0)
     715             :     {
     716           0 :         fprintf(fp, "      Subfield `%s' = {invalid length}\n", pszName);
     717           0 :         return;
     718             :     }
     719           0 :     if (eType == DDFFloat)
     720           0 :         fprintf(fp, "      Subfield `%s' = %f\n", pszName,
     721             :                 ExtractFloatData(pachData, nMaxBytes, nullptr));
     722           0 :     else if (eType == DDFInt)
     723           0 :         fprintf(fp, "      Subfield `%s' = %d\n", pszName,
     724             :                 ExtractIntData(pachData, nMaxBytes, nullptr));
     725           0 :     else if (eType == DDFBinaryString)
     726             :     {
     727           0 :         int nBytes = 0;
     728             :         GByte *pabyBString =
     729           0 :             (GByte *)ExtractStringData(pachData, nMaxBytes, &nBytes);
     730             : 
     731           0 :         fprintf(fp, "      Subfield `%s' = 0x", pszName);
     732           0 :         for (int i = 0; i < std::min(nBytes, 24); i++)
     733           0 :             fprintf(fp, "%02X", pabyBString[i]);
     734             : 
     735           0 :         if (nBytes > 24)
     736           0 :             fprintf(fp, "%s", "...");
     737             : 
     738           0 :         fprintf(fp, "\n");
     739             :     }
     740             :     else
     741           0 :         fprintf(fp, "      Subfield `%s' = `%s'\n", pszName,
     742             :                 ExtractStringData(pachData, nMaxBytes, nullptr));
     743             : }
     744             : 
     745             : /************************************************************************/
     746             : /*                          GetDefaultValue()                           */
     747             : /************************************************************************/
     748             : 
     749             : /**
     750             :  * Get default data.
     751             :  *
     752             :  * Returns the default subfield data contents for this subfield definition.
     753             :  * For variable length numbers this will normally be "0<unit-terminator>".
     754             :  * For variable length strings it will be "<unit-terminator>".  For fixed
     755             :  * length numbers it is zero filled.  For fixed length strings it is space
     756             :  * filled.  For binary numbers it is binary zero filled.
     757             :  *
     758             :  * @param pachData the buffer into which the returned default will be placed.
     759             :  * May be NULL if just querying default size.
     760             :  * @param nBytesAvailable the size of pachData in bytes.
     761             :  * @param pnBytesUsed will receive the size of the subfield default data in
     762             :  * bytes.
     763             :  *
     764             :  * @return TRUE on success or FALSE on failure or if the passed buffer is too
     765             :  * small to hold the default.
     766             :  */
     767             : 
     768        4228 : int DDFSubfieldDefn::GetDefaultValue(char *pachData, int nBytesAvailable,
     769             :                                      int *pnBytesUsed) const
     770             : 
     771             : {
     772             :     int nDefaultSize;
     773             : 
     774        4228 :     if (!bIsVariable)
     775        3938 :         nDefaultSize = nFormatWidth;
     776             :     else
     777         290 :         nDefaultSize = 1;
     778             : 
     779        4228 :     if (pnBytesUsed != nullptr)
     780        4228 :         *pnBytesUsed = nDefaultSize;
     781             : 
     782        4228 :     if (pachData == nullptr)
     783        2114 :         return TRUE;
     784             : 
     785        2114 :     if (nBytesAvailable < nDefaultSize)
     786           0 :         return FALSE;
     787             : 
     788        2114 :     if (bIsVariable)
     789             :     {
     790         145 :         pachData[0] = DDF_UNIT_TERMINATOR;
     791             :     }
     792             :     else
     793             :     {
     794             :         char chFillChar;
     795        1969 :         if (GetBinaryFormat() == NotBinary)
     796             :         {
     797          54 :             if (GetType() == DDFInt || GetType() == DDFFloat)
     798          18 :                 chFillChar = '0'; /* ASCII zero intended */
     799             :             else
     800          36 :                 chFillChar = ' ';
     801             :         }
     802             :         else
     803        1915 :             chFillChar = 0;
     804        1969 :         memset(pachData, chFillChar, nDefaultSize);
     805             :     }
     806             : 
     807        2114 :     return TRUE;
     808             : }
     809             : 
     810             : /************************************************************************/
     811             : /*                         FormatStringValue()                          */
     812             : /************************************************************************/
     813             : 
     814             : /**
     815             :  * Format string subfield value.
     816             :  *
     817             :  * Returns a buffer with the passed in string value reformatted in a way
     818             :  * suitable for storage in a DDFField for this subfield.
     819             :  */
     820             : 
     821         524 : int DDFSubfieldDefn::FormatStringValue(char *pachData, int nBytesAvailable,
     822             :                                        int *pnBytesUsed, const char *pszValue,
     823             :                                        int nValueLength) const
     824             : 
     825             : {
     826             :     int nSize;
     827             : 
     828         524 :     if (nValueLength == -1)
     829         324 :         nValueLength = static_cast<int>(strlen(pszValue));
     830             : 
     831         524 :     if (bIsVariable)
     832             :     {
     833         216 :         nSize = nValueLength + 1;
     834             :     }
     835             :     else
     836             :     {
     837         308 :         nSize = nFormatWidth;
     838             :     }
     839             : 
     840         524 :     if (pnBytesUsed != nullptr)
     841         262 :         *pnBytesUsed = nSize;
     842             : 
     843         524 :     if (pachData == nullptr)
     844         262 :         return TRUE;
     845             : 
     846         262 :     if (nBytesAvailable < nSize)
     847           0 :         return FALSE;
     848             : 
     849         262 :     if (bIsVariable)
     850             :     {
     851         108 :         strncpy(pachData, pszValue, nSize - 1);
     852         108 :         pachData[nSize - 1] = DDF_UNIT_TERMINATOR;
     853             :     }
     854             :     else
     855             :     {
     856         154 :         if (GetBinaryFormat() == NotBinary)
     857             :         {
     858          54 :             memset(pachData, ' ', nSize);
     859             :             // cppcheck-suppress redundantCopy
     860          54 :             memcpy(pachData, pszValue, std::min(nValueLength, nSize));
     861             :         }
     862             :         else
     863             :         {
     864         100 :             memset(pachData, 0, nSize);
     865             :             // cppcheck-suppress redundantCopy
     866         100 :             memcpy(pachData, pszValue, std::min(nValueLength, nSize));
     867             :         }
     868             :     }
     869             : 
     870         262 :     return TRUE;
     871             : }
     872             : 
     873             : /************************************************************************/
     874             : /*                           FormatIntValue()                           */
     875             : /************************************************************************/
     876             : 
     877             : /**
     878             :  * Format int subfield value.
     879             :  *
     880             :  * Returns a buffer with the passed in int value reformatted in a way
     881             :  * suitable for storage in a DDFField for this subfield.
     882             :  */
     883             : 
     884        3112 : int DDFSubfieldDefn::FormatIntValue(char *pachData, int nBytesAvailable,
     885             :                                     int *pnBytesUsed, int nNewValue) const
     886             : 
     887             : {
     888             :     int nSize;
     889             :     char szWork[30];
     890             : 
     891        3112 :     snprintf(szWork, sizeof(szWork), "%d", nNewValue);
     892             : 
     893        3112 :     if (bIsVariable)
     894             :     {
     895           0 :         nSize = static_cast<int>(strlen(szWork)) + 1;
     896             :     }
     897             :     else
     898             :     {
     899        3112 :         nSize = nFormatWidth;
     900             : 
     901        3112 :         if (GetBinaryFormat() == NotBinary && (int)strlen(szWork) > nSize)
     902           0 :             return FALSE;
     903             :     }
     904             : 
     905        3112 :     if (pnBytesUsed != nullptr)
     906        1556 :         *pnBytesUsed = nSize;
     907             : 
     908        3112 :     if (pachData == nullptr)
     909        1556 :         return TRUE;
     910             : 
     911        1556 :     if (nBytesAvailable < nSize)
     912           0 :         return FALSE;
     913             : 
     914        1556 :     if (bIsVariable)
     915             :     {
     916           0 :         strncpy(pachData, szWork, nSize - 1);
     917           0 :         pachData[nSize - 1] = DDF_UNIT_TERMINATOR;
     918             :     }
     919             :     else
     920             :     {
     921        1556 :         GUInt32 nMask = 0xff;
     922             :         int i;
     923             : 
     924        1556 :         switch (GetBinaryFormat())
     925             :         {
     926           0 :             case NotBinary:
     927             :             {
     928           0 :                 char chFillChar = '0'; /* ASCII zero intended */
     929           0 :                 memset(pachData, chFillChar, nSize);
     930           0 :                 memcpy(pachData + nSize - strlen(szWork), szWork,
     931             :                        strlen(szWork));
     932           0 :                 break;
     933             :             }
     934             : 
     935        1556 :             case UInt:
     936             :             case SInt:
     937        4448 :                 for (i = 0; i < nFormatWidth; i++)
     938             :                 {
     939             :                     int iOut;
     940             : 
     941             :                     // big endian required?
     942        2892 :                     if (pszFormatString[0] == 'B')
     943           0 :                         iOut = nFormatWidth - i - 1;
     944             :                     else
     945        2892 :                         iOut = i;
     946             : 
     947        2892 :                     pachData[iOut] = (char)((nNewValue & nMask) >> (i * 8));
     948        2892 :                     nMask <<= 8;
     949             :                 }
     950        1556 :                 break;
     951             : 
     952           0 :             case FloatReal:
     953           0 :                 CPLAssert(false);
     954             :                 break;
     955             : 
     956           0 :             default:
     957           0 :                 CPLAssert(false);
     958             :                 break;
     959             :         }
     960             :     }
     961             : 
     962        1556 :     return TRUE;
     963             : }
     964             : 
     965             : /************************************************************************/
     966             : /*                          FormatFloatValue()                          */
     967             : /************************************************************************/
     968             : 
     969             : /**
     970             :  * Format float subfield value.
     971             :  *
     972             :  * Returns a buffer with the passed in float value reformatted in a way
     973             :  * suitable for storage in a DDFField for this subfield.
     974             :  */
     975             : 
     976           0 : int DDFSubfieldDefn::FormatFloatValue(char *pachData, int nBytesAvailable,
     977             :                                       int *pnBytesUsed, double dfNewValue) const
     978             : 
     979             : {
     980             :     int nSize;
     981             :     char szWork[120];
     982             : 
     983           0 :     CPLsnprintf(szWork, sizeof(szWork), "%.16g", dfNewValue);
     984             : 
     985           0 :     if (bIsVariable)
     986             :     {
     987           0 :         nSize = static_cast<int>(strlen(szWork)) + 1;
     988             :     }
     989             :     else
     990             :     {
     991           0 :         nSize = nFormatWidth;
     992             : 
     993           0 :         if (GetBinaryFormat() == NotBinary && (int)strlen(szWork) > nSize)
     994           0 :             return FALSE;
     995             :     }
     996             : 
     997           0 :     if (pnBytesUsed != nullptr)
     998           0 :         *pnBytesUsed = nSize;
     999             : 
    1000           0 :     if (pachData == nullptr)
    1001           0 :         return TRUE;
    1002             : 
    1003           0 :     if (nBytesAvailable < nSize)
    1004           0 :         return FALSE;
    1005             : 
    1006           0 :     if (bIsVariable)
    1007             :     {
    1008           0 :         strncpy(pachData, szWork, nSize - 1);
    1009           0 :         pachData[nSize - 1] = DDF_UNIT_TERMINATOR;
    1010             :     }
    1011             :     else
    1012             :     {
    1013           0 :         if (GetBinaryFormat() == NotBinary)
    1014             :         {
    1015           0 :             const char chFillZeroASCII = '0'; /* ASCII zero intended */
    1016             :             /* coverity[bad_memset] */
    1017           0 :             memset(pachData, chFillZeroASCII, nSize);
    1018           0 :             memcpy(pachData + nSize - strlen(szWork), szWork, strlen(szWork));
    1019             :         }
    1020             :         else
    1021             :         {
    1022           0 :             CPLAssert(false);
    1023             :             /* implement me */
    1024             :         }
    1025             :     }
    1026             : 
    1027           0 :     return TRUE;
    1028             : }

Generated by: LCOV version 1.14