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

Generated by: LCOV version 1.14