LCOV - code coverage report
Current view: top level - frmts/iso8211 - ddfsubfielddefn.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 184 329 55.9 %
Date: 2026-04-19 18:43:50 Functions: 10 12 83.3 %

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

Generated by: LCOV version 1.14