LCOV - code coverage report
Current view: top level - frmts/iso8211 - ddfsubfielddefn.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 181 335 54.0 %
Date: 2024-11-21 22:18:42 Functions: 11 14 78.6 %

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

Generated by: LCOV version 1.14