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

Generated by: LCOV version 1.14