LCOV - code coverage report
Current view: directory - frmts/iso8211 - ddfrecord.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 497 196 39.4 %
Date: 2012-12-26 Functions: 26 14 53.8 %

       1                 : /******************************************************************************
       2                 :  * $Id: ddfrecord.cpp 24956 2012-09-22 20:52:24Z rouault $
       3                 :  *
       4                 :  * Project:  ISO 8211 Access
       5                 :  * Purpose:  Implements the DDFRecord class.
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 1999, Frank Warmerdam
      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 "iso8211.h"
      31                 : #include "cpl_conv.h"
      32                 : 
      33                 : CPL_CVSID("$Id: ddfrecord.cpp 24956 2012-09-22 20:52:24Z rouault $");
      34                 : 
      35                 : static const int nLeaderSize = 24;
      36                 : 
      37                 : /************************************************************************/
      38                 : /*                             DDFRecord()                              */
      39                 : /************************************************************************/
      40                 : 
      41           24017 : DDFRecord::DDFRecord( DDFModule * poModuleIn )
      42                 : 
      43                 : {
      44           24017 :     poModule = poModuleIn;
      45                 : 
      46           24017 :     nReuseHeader = FALSE;
      47                 : 
      48           24017 :     nFieldOffset = 0;
      49                 : 
      50           24017 :     nDataSize = 0;
      51           24017 :     pachData = NULL;
      52                 : 
      53           24017 :     nFieldCount = 0;
      54           24017 :     paoFields = NULL;
      55                 : 
      56           24017 :     bIsClone = FALSE;
      57                 : 
      58           24017 :     _sizeFieldTag = 4;
      59           24017 :     _sizeFieldPos = 0;
      60           24017 :     _sizeFieldLength = 0;
      61           24017 : }
      62                 : 
      63                 : /************************************************************************/
      64                 : /*                             ~DDFRecord()                             */
      65                 : /************************************************************************/
      66                 : 
      67           24017 : DDFRecord::~DDFRecord()
      68                 : 
      69                 : {
      70           24017 :     Clear();
      71                 : 
      72           24017 :     if( bIsClone )
      73           23949 :         poModule->RemoveCloneRecord( this );
      74           24017 : }
      75                 : 
      76                 : /************************************************************************/
      77                 : /*                                Dump()                                */
      78                 : /************************************************************************/
      79                 : 
      80                 : /**
      81                 :  * Write out record contents to debugging file.
      82                 :  *
      83                 :  * A variety of information about this record, and all it's fields and
      84                 :  * subfields is written to the given debugging file handle.  Note that
      85                 :  * field definition information (ala DDFFieldDefn) isn't written.
      86                 :  *
      87                 :  * @param fp The standard io file handle to write to.  ie. stderr
      88                 :  */
      89                 : 
      90               0 : void DDFRecord::Dump( FILE * fp )
      91                 : 
      92                 : {
      93               0 :     fprintf( fp, "DDFRecord:\n" );
      94               0 :     fprintf( fp, "    nReuseHeader = %d\n", nReuseHeader );
      95               0 :     fprintf( fp, "    nDataSize = %d\n", nDataSize );
      96                 :     fprintf( fp, 
      97                 :              "    _sizeFieldLength=%d, _sizeFieldPos=%d, _sizeFieldTag=%d\n",
      98               0 :              _sizeFieldLength, _sizeFieldPos, _sizeFieldTag );
      99                 : 
     100               0 :     for( int i = 0; i < nFieldCount; i++ )
     101                 :     {
     102               0 :         paoFields[i].Dump( fp );
     103                 :     }
     104               0 : }
     105                 : 
     106                 : /************************************************************************/
     107                 : /*                                Read()                                */
     108                 : /*                                                                      */
     109                 : /*      Read a record of data from the file, and parse the header to    */
     110                 : /*      build a field list for the record (or reuse the existing one    */
     111                 : /*      if reusing headers).  It is expected that the file pointer      */
     112                 : /*      will be positioned at the beginning of a data record.  It is    */
     113                 : /*      the DDFModule's responsibility to do so.                        */
     114                 : /*                                                                      */
     115                 : /*      This method should only be called by the DDFModule class.       */
     116                 : /************************************************************************/
     117                 : 
     118           24554 : int DDFRecord::Read()
     119                 : 
     120                 : {
     121                 : /* -------------------------------------------------------------------- */
     122                 : /*      Redefine the record on the basis of the header if needed.       */
     123                 : /*      As a side effect this will read the data for the record as well.*/
     124                 : /* -------------------------------------------------------------------- */
     125           24554 :     if( !nReuseHeader )
     126                 :     {
     127           24118 :         return( ReadHeader() );
     128                 :     }
     129                 : 
     130                 : /* -------------------------------------------------------------------- */
     131                 : /*      Otherwise we read just the data and carefully overlay it on     */
     132                 : /*      the previous records data without disturbing the rest of the    */
     133                 : /*      record.                                                         */
     134                 : /* -------------------------------------------------------------------- */
     135                 :     size_t      nReadBytes;
     136                 : 
     137                 :     nReadBytes = VSIFReadL( pachData + nFieldOffset, 1,
     138                 :                             nDataSize - nFieldOffset,
     139             436 :                             poModule->GetFP() );
     140             436 :     if( nReadBytes != (size_t) (nDataSize - nFieldOffset)
     141                 :         && nReadBytes == 0
     142                 :         && VSIFEofL( poModule->GetFP() ) )
     143                 :     {
     144               7 :         return FALSE;
     145                 :     }
     146             429 :     else if( nReadBytes != (size_t) (nDataSize - nFieldOffset) )
     147                 :     {
     148                 :         CPLError( CE_Failure, CPLE_FileIO,
     149               0 :                   "Data record is short on DDF file.\n" );
     150                 :         
     151               0 :         return FALSE;
     152                 :     }
     153                 : 
     154                 :     // notdef: eventually we may have to do something at this point to 
     155                 :     // notify the DDFField's that their data values have changed. 
     156                 :     
     157             429 :     return TRUE;
     158                 : }
     159                 : 
     160                 : /************************************************************************/
     161                 : /*                               Write()                                */
     162                 : /************************************************************************/
     163                 : 
     164                 : /**
     165                 :  * Write record out to module.
     166                 :  *
     167                 :  * This method writes the current record to the module to which it is 
     168                 :  * attached.  Normally this would be at the end of the file, and only used
     169                 :  * for modules newly created with DDFModule::Create().  Rewriting existing
     170                 :  * records is not supported at this time.  Calling Write() multiple times
     171                 :  * on a DDFRecord will result it multiple copies being written at the end of
     172                 :  * the module.
     173                 :  *
     174                 :  * @return TRUE on success or FALSE on failure.
     175                 :  */
     176                 : 
     177               0 : int DDFRecord::Write()
     178                 : 
     179                 : {
     180               0 :     if( !ResetDirectory() )
     181               0 :         return FALSE;
     182                 :     
     183                 : /* -------------------------------------------------------------------- */
     184                 : /*      Prepare leader.                                                 */
     185                 : /* -------------------------------------------------------------------- */
     186                 :     char szLeader[nLeaderSize+1];
     187                 : 
     188               0 :     memset( szLeader, ' ', nLeaderSize );
     189                 : 
     190               0 :     sprintf( szLeader+0, "%05d", (int) (nDataSize + nLeaderSize) );
     191               0 :     szLeader[5] = ' ';
     192               0 :     szLeader[6] = 'D';
     193                 :     
     194               0 :     sprintf( szLeader + 12, "%05d", (int) (nFieldOffset + nLeaderSize) );
     195               0 :     szLeader[17] = ' ';
     196                 : 
     197               0 :     szLeader[20] = (char) ('0' + _sizeFieldLength);
     198               0 :     szLeader[21] = (char) ('0' + _sizeFieldPos);
     199               0 :     szLeader[22] = '0';
     200               0 :     szLeader[23] = (char) ('0' + _sizeFieldTag);
     201                 : 
     202                 :     /* notdef: lots of stuff missing */
     203                 : 
     204                 : /* -------------------------------------------------------------------- */
     205                 : /*      Write the leader.                                               */
     206                 : /* -------------------------------------------------------------------- */
     207               0 :     VSIFWriteL( szLeader, nLeaderSize, 1, poModule->GetFP() );
     208                 : 
     209                 : /* -------------------------------------------------------------------- */
     210                 : /*      Write the remainder of the record.                              */
     211                 : /* -------------------------------------------------------------------- */
     212               0 :     VSIFWriteL( pachData, nDataSize, 1, poModule->GetFP() );
     213                 :     
     214               0 :     return TRUE;
     215                 : }
     216                 : 
     217                 : /************************************************************************/
     218                 : /*                               Clear()                                */
     219                 : /*                                                                      */
     220                 : /*      Clear any information associated with the last header in        */
     221                 : /*      preparation for reading a new header.                           */
     222                 : /************************************************************************/
     223                 : 
     224           48151 : void DDFRecord::Clear()
     225                 : 
     226                 : {
     227           48151 :     if( paoFields != NULL )
     228           48039 :         delete[] paoFields;
     229                 : 
     230           48151 :     paoFields = NULL;
     231           48151 :     nFieldCount = 0;
     232                 : 
     233           48151 :     if( pachData != NULL )
     234           48039 :         CPLFree( pachData );
     235                 : 
     236           48151 :     pachData = NULL;
     237           48151 :     nDataSize = 0;
     238           48151 :     nReuseHeader = FALSE;
     239           48151 : }
     240                 : 
     241                 : /************************************************************************/
     242                 : /*                             ReadHeader()                             */
     243                 : /*                                                                      */
     244                 : /*      This perform the header reading and parsing job for the         */
     245                 : /*      Read() method.  It reads the header, and builds a field         */
     246                 : /*      list.                                                           */
     247                 : /************************************************************************/
     248                 : 
     249           24118 : int DDFRecord::ReadHeader()
     250                 : 
     251                 : {
     252                 : /* -------------------------------------------------------------------- */
     253                 : /*      Clear any existing information.                                 */
     254                 : /* -------------------------------------------------------------------- */
     255           24118 :     Clear();
     256                 :     
     257                 : /* -------------------------------------------------------------------- */
     258                 : /*      Read the 24 byte leader.                                        */
     259                 : /* -------------------------------------------------------------------- */
     260                 :     char        achLeader[nLeaderSize];
     261                 :     int         nReadBytes;
     262                 : 
     263           24118 :     nReadBytes = VSIFReadL(achLeader,1,nLeaderSize,poModule->GetFP());
     264           24118 :     if( nReadBytes == 0 && VSIFEofL( poModule->GetFP() ) )
     265                 :     {
     266              28 :         return FALSE;
     267                 :     }
     268           24090 :     else if( nReadBytes != (int) nLeaderSize )
     269                 :     {
     270                 :         CPLError( CE_Failure, CPLE_FileIO,
     271               0 :                   "Leader is short on DDF file." );
     272                 :         
     273               0 :         return FALSE;
     274                 :     }
     275                 : 
     276                 : /* -------------------------------------------------------------------- */
     277                 : /*      Extract information from leader.                                */
     278                 : /* -------------------------------------------------------------------- */
     279                 :     int         _recLength, _fieldAreaStart;
     280                 :     char        _leaderIden;
     281                 :     
     282           24090 :     _recLength                    = DDFScanInt( achLeader+0, 5 );
     283           24090 :     _leaderIden                   = achLeader[6];
     284           24090 :     _fieldAreaStart               = DDFScanInt(achLeader+12,5);
     285                 :     
     286           24090 :     _sizeFieldLength = achLeader[20] - '0';
     287           24090 :     _sizeFieldPos = achLeader[21] - '0';
     288           24090 :     _sizeFieldTag = achLeader[23] - '0';
     289                 : 
     290           24090 :     if( _sizeFieldLength < 0 || _sizeFieldLength > 9 
     291                 :         || _sizeFieldPos < 0 || _sizeFieldPos > 9
     292                 :         || _sizeFieldTag < 0 || _sizeFieldTag > 9 )
     293                 :     {
     294                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     295               0 :                   "ISO8211 record leader appears to be corrupt." );
     296               0 :         return FALSE;
     297                 :     }
     298                 : 
     299           24090 :     if( _leaderIden == 'R' )
     300              13 :         nReuseHeader = TRUE;
     301                 : 
     302           24090 :     nFieldOffset = _fieldAreaStart - nLeaderSize;
     303                 : 
     304                 : /* -------------------------------------------------------------------- */
     305                 : /*      Is there anything seemly screwy about this record?              */
     306                 : /* -------------------------------------------------------------------- */
     307           24090 :     if(( _recLength < 24 || _recLength > 100000000
     308                 :          || _fieldAreaStart < 24 || _fieldAreaStart > 100000 )
     309                 :        && (_recLength != 0))
     310                 :     {
     311                 :         CPLError( CE_Failure, CPLE_FileIO, 
     312                 :                   "Data record appears to be corrupt on DDF file.\n"
     313                 :                   " -- ensure that the files were uncompressed without modifying\n"
     314               0 :                   "carriage return/linefeeds (by default WINZIP does this)." );
     315                 :         
     316               0 :         return FALSE;
     317                 :     }
     318                 : 
     319                 : /* ==================================================================== */
     320                 : /*      Handle the normal case with the record length available.        */
     321                 : /* ==================================================================== */
     322           24090 :     if(_recLength != 0) {
     323                 : /* -------------------------------------------------------------------- */
     324                 : /*      Read the remainder of the record.                               */
     325                 : /* -------------------------------------------------------------------- */
     326           24090 :         nDataSize = _recLength - nLeaderSize;
     327           24090 :         pachData = (char *) CPLMalloc(nDataSize);
     328                 : 
     329           24090 :         if( VSIFReadL( pachData, 1, nDataSize, poModule->GetFP()) !=
     330                 :             (size_t) nDataSize )
     331                 :         {
     332                 :             CPLError( CE_Failure, CPLE_FileIO, 
     333               0 :                       "Data record is short on DDF file." );
     334                 :           
     335               0 :             return FALSE;
     336                 :         }
     337                 : 
     338                 : /* -------------------------------------------------------------------- */
     339                 : /*      If we don't find a field terminator at the end of the record    */
     340                 : /*      we will read extra bytes till we get to it.                     */
     341                 : /* -------------------------------------------------------------------- */
     342           48181 :         while( pachData[nDataSize-1] != DDF_FIELD_TERMINATOR 
     343               1 :                && (nDataSize == 0 || pachData[nDataSize-2] != DDF_FIELD_TERMINATOR) )
     344                 :         {
     345               0 :             nDataSize++;
     346               0 :             pachData = (char *) CPLRealloc(pachData,nDataSize);
     347                 :             
     348               0 :             if( VSIFReadL( pachData + nDataSize - 1, 1, 1, poModule->GetFP() )
     349                 :                 != 1 )
     350                 :             {
     351                 :                 CPLError( CE_Failure, CPLE_FileIO, 
     352               0 :                           "Data record is short on DDF file." );
     353                 :                 
     354               0 :                 return FALSE;
     355                 :             }
     356                 :             CPLDebug( "ISO8211", 
     357               0 :                       "Didn't find field terminator, read one more byte." );
     358                 :         }
     359                 : 
     360                 : /* -------------------------------------------------------------------- */
     361                 : /*      Loop over the directory entries, making a pass counting them.   */
     362                 : /* -------------------------------------------------------------------- */
     363                 :         int         i;
     364                 :         int         nFieldEntryWidth;
     365                 :       
     366           24090 :         nFieldEntryWidth = _sizeFieldLength + _sizeFieldPos + _sizeFieldTag;
     367           24090 :         nFieldCount = 0;
     368          113865 :         for( i = 0; i < nDataSize; i += nFieldEntryWidth )
     369                 :         {
     370          113865 :             if( pachData[i] == DDF_FIELD_TERMINATOR )
     371           24090 :                 break;
     372                 :           
     373           89775 :             nFieldCount++;
     374                 :         }
     375                 :     
     376                 : /* -------------------------------------------------------------------- */
     377                 : /*      Allocate, and read field definitions.                           */
     378                 : /* -------------------------------------------------------------------- */
     379           24090 :         paoFields = new DDFField[nFieldCount];
     380                 :     
     381          113865 :         for( i = 0; i < nFieldCount; i++ )
     382                 :         {
     383                 :             char    szTag[128];
     384           89775 :             int     nEntryOffset = i*nFieldEntryWidth;
     385                 :             int     nFieldLength, nFieldPos;
     386                 :           
     387                 : /* -------------------------------------------------------------------- */
     388                 : /*      Read the position information and tag.                          */
     389                 : /* -------------------------------------------------------------------- */
     390           89775 :             strncpy( szTag, pachData+nEntryOffset, _sizeFieldTag );
     391           89775 :             szTag[_sizeFieldTag] = '\0';
     392                 :           
     393           89775 :             nEntryOffset += _sizeFieldTag;
     394           89775 :             nFieldLength = DDFScanInt( pachData+nEntryOffset, _sizeFieldLength );
     395                 :           
     396           89775 :             nEntryOffset += _sizeFieldLength;
     397           89775 :             nFieldPos = DDFScanInt( pachData+nEntryOffset, _sizeFieldPos );
     398                 :           
     399                 : /* -------------------------------------------------------------------- */
     400                 : /*      Find the corresponding field in the module directory.           */
     401                 : /* -------------------------------------------------------------------- */
     402           89775 :             DDFFieldDefn    *poFieldDefn = poModule->FindFieldDefn( szTag );
     403                 :           
     404           89775 :             if( poFieldDefn == NULL )
     405                 :             {
     406                 :                 CPLError( CE_Failure, CPLE_AppDefined,
     407                 :                           "Undefined field `%s' encountered in data record.",
     408               0 :                           szTag );
     409               0 :                 return FALSE;
     410                 :             }
     411                 : 
     412           89775 :             if (_fieldAreaStart + nFieldPos - nLeaderSize < 0 ||
     413                 :                 nDataSize - (_fieldAreaStart + nFieldPos - nLeaderSize) < nFieldLength)
     414                 :             {
     415                 :                 CPLError( CE_Failure, CPLE_AppDefined,
     416                 :                           "Not enough byte to initialize field `%s'.",
     417               0 :                           szTag );
     418               0 :                 return FALSE;
     419                 :             }
     420                 : 
     421                 : /* -------------------------------------------------------------------- */
     422                 : /*      Assign info the DDFField.                                       */
     423                 : /* -------------------------------------------------------------------- */
     424                 :             paoFields[i].Initialize( poFieldDefn, 
     425                 :                                      pachData + _fieldAreaStart + nFieldPos - nLeaderSize,
     426           89775 :                                      nFieldLength );
     427                 :         }
     428                 :       
     429           24090 :         return TRUE;
     430                 :     }
     431                 : /* ==================================================================== */
     432                 : /*      Handle the exceptional case where the record length is          */
     433                 : /*      zero.  In this case we have to read all the data based on       */
     434                 : /*      the size of data items as per ISO8211 spec Annex C, 1.5.1.      */
     435                 : /*                                                                      */
     436                 : /*      See Bugzilla bug 181 and test with file US4CN21M.000.           */
     437                 : /* ==================================================================== */
     438                 :     else {
     439                 :         CPLDebug( "ISO8211", 
     440               0 :                   "Record with zero length, use variant (C.1.5.1) logic." );
     441                 : 
     442                 :         /* ----------------------------------------------------------------- */
     443                 :         /*   _recLength == 0, handle the large record.                       */
     444                 :         /*                                                                   */
     445                 :         /*   Read the remainder of the record.                               */
     446                 :         /* ----------------------------------------------------------------- */
     447               0 :         nDataSize = 0;
     448               0 :         pachData = NULL;
     449                 : 
     450                 :         /* ----------------------------------------------------------------- */
     451                 :         /*   Loop over the directory entries, making a pass counting them.   */
     452                 :         /* ----------------------------------------------------------------- */
     453               0 :         int nFieldEntryWidth = _sizeFieldLength + _sizeFieldPos + _sizeFieldTag;
     454               0 :         nFieldCount = 0;
     455               0 :         int i=0;
     456                 : 
     457               0 :         if (nFieldEntryWidth == 0)
     458                 :         {
     459                 :             CPLError( CE_Failure, CPLE_OutOfMemory,
     460                 :                       "Invalid record buffer size : %d.",
     461               0 :                       nFieldEntryWidth );
     462               0 :             return FALSE;
     463                 :         }
     464                 :         
     465               0 :         char *tmpBuf = (char*)VSIMalloc(nFieldEntryWidth);
     466                 : 
     467               0 :         if( tmpBuf == NULL )
     468                 :         {
     469                 :             CPLError( CE_Failure, CPLE_OutOfMemory, 
     470                 :                       "Attempt to allocate %d byte ISO8211 record buffer failed.", 
     471               0 :                       nFieldEntryWidth );
     472               0 :             return FALSE;
     473                 :         }
     474                 :       
     475                 :         // while we're not at the end, store this entry,
     476                 :         // and keep on reading...
     477               0 :         do {
     478                 :             // read an Entry:
     479               0 :             if(nFieldEntryWidth != 
     480                 :                (int) VSIFReadL(tmpBuf, 1, nFieldEntryWidth, poModule->GetFP())) {
     481                 :                 CPLError(CE_Failure, CPLE_FileIO,
     482               0 :                          "Data record is short on DDF file.");
     483               0 :                 CPLFree(tmpBuf);
     484               0 :                 return FALSE;
     485                 :             }
     486                 :       
     487                 :             // move this temp buffer into more permanent storage:
     488               0 :             char *newBuf = (char*)CPLMalloc(nDataSize+nFieldEntryWidth);
     489               0 :             if(pachData!=NULL) {
     490               0 :                 memcpy(newBuf, pachData, nDataSize);
     491               0 :                 CPLFree(pachData);
     492                 :             }
     493               0 :             memcpy(&newBuf[nDataSize], tmpBuf, nFieldEntryWidth);
     494               0 :             pachData = newBuf;
     495               0 :             nDataSize += nFieldEntryWidth;
     496                 : 
     497               0 :             if(DDF_FIELD_TERMINATOR != tmpBuf[0]) {
     498               0 :                 nFieldCount++;
     499                 :             }
     500                 :         }
     501               0 :         while(DDF_FIELD_TERMINATOR != tmpBuf[0]);
     502                 : 
     503               0 :         CPLFree(tmpBuf);
     504               0 :         tmpBuf = NULL;
     505                 : 
     506                 :         // --------------------------------------------------------------------
     507                 :         // Now, rewind a little.  Only the TERMINATOR should have been read
     508                 :         // --------------------------------------------------------------------
     509               0 :         int rewindSize = nFieldEntryWidth - 1;
     510               0 :         VSILFILE *fp = poModule->GetFP();
     511               0 :         vsi_l_offset pos = VSIFTellL(fp) - rewindSize;
     512               0 :         VSIFSeekL(fp, pos, SEEK_SET);
     513               0 :         nDataSize -= rewindSize;
     514                 : 
     515                 :         // --------------------------------------------------------------------
     516                 :         // Okay, now let's populate the heck out of pachData...
     517                 :         // --------------------------------------------------------------------
     518               0 :         for(i=0; i<nFieldCount; i++) {
     519               0 :             int nEntryOffset = (i*nFieldEntryWidth) + _sizeFieldTag;
     520                 :             int nFieldLength = DDFScanInt(pachData + nEntryOffset,
     521               0 :                                           _sizeFieldLength);
     522               0 :             char *tmpBuf = (char*)VSIMalloc(nFieldLength);
     523               0 :             if( tmpBuf == NULL )
     524                 :             {
     525                 :                 CPLError(CE_Failure, CPLE_OutOfMemory,
     526               0 :                          "Cannot allocate %d bytes", nFieldLength);
     527               0 :                 return FALSE;
     528                 :             }
     529                 : 
     530                 :             // read an Entry:
     531               0 :             if(nFieldLength != 
     532                 :                (int) VSIFReadL(tmpBuf, 1, nFieldLength, poModule->GetFP())) {
     533                 :                 CPLError(CE_Failure, CPLE_FileIO,
     534               0 :                          "Data record is short on DDF file.");
     535               0 :                 CPLFree(tmpBuf);
     536               0 :                 return FALSE;
     537                 :             }
     538                 :       
     539                 :             // move this temp buffer into more permanent storage:
     540               0 :             char *newBuf = (char*)VSIMalloc(nDataSize+nFieldLength);
     541               0 :             if( newBuf == NULL )
     542                 :             {
     543                 :                 CPLError(CE_Failure, CPLE_OutOfMemory,
     544               0 :                          "Cannot allocate %d bytes", nDataSize + nFieldLength);
     545               0 :                 CPLFree(tmpBuf);
     546               0 :                 return FALSE;
     547                 :             }
     548               0 :             memcpy(newBuf, pachData, nDataSize);
     549               0 :             CPLFree(pachData);
     550               0 :             memcpy(&newBuf[nDataSize], tmpBuf, nFieldLength);
     551               0 :             CPLFree(tmpBuf);
     552               0 :             pachData = newBuf;
     553               0 :             nDataSize += nFieldLength;
     554                 :         }
     555                 :     
     556                 :         /* ----------------------------------------------------------------- */
     557                 :         /*     Allocate, and read field definitions.                         */
     558                 :         /* ----------------------------------------------------------------- */
     559               0 :         paoFields = new DDFField[nFieldCount];
     560                 :       
     561               0 :         for( i = 0; i < nFieldCount; i++ )
     562                 :         {
     563                 :             char    szTag[128];
     564               0 :             int     nEntryOffset = i*nFieldEntryWidth;
     565                 :             int     nFieldLength, nFieldPos;
     566                 :           
     567                 :             /* ------------------------------------------------------------- */
     568                 :             /* Read the position information and tag.                        */
     569                 :             /* ------------------------------------------------------------- */
     570               0 :             strncpy( szTag, pachData+nEntryOffset, _sizeFieldTag );
     571               0 :             szTag[_sizeFieldTag] = '\0';
     572                 :           
     573               0 :             nEntryOffset += _sizeFieldTag;
     574               0 :             nFieldLength = DDFScanInt( pachData+nEntryOffset, _sizeFieldLength );
     575                 :           
     576               0 :             nEntryOffset += _sizeFieldLength;
     577               0 :             nFieldPos = DDFScanInt( pachData+nEntryOffset, _sizeFieldPos );
     578                 :           
     579                 :             /* ------------------------------------------------------------- */
     580                 :             /* Find the corresponding field in the module directory.         */
     581                 :             /* ------------------------------------------------------------- */
     582               0 :             DDFFieldDefn    *poFieldDefn = poModule->FindFieldDefn( szTag );
     583                 :           
     584               0 :             if( poFieldDefn == NULL )
     585                 :             {
     586                 :                 CPLError( CE_Failure, CPLE_AppDefined,
     587                 :                           "Undefined field `%s' encountered in data record.",
     588               0 :                           szTag );
     589               0 :                 return FALSE;
     590                 :             }
     591                 : 
     592               0 :             if (_fieldAreaStart + nFieldPos - nLeaderSize < 0 ||
     593                 :                 nDataSize - (_fieldAreaStart + nFieldPos - nLeaderSize) < nFieldLength)
     594                 :             {
     595                 :                 CPLError( CE_Failure, CPLE_AppDefined,
     596                 :                           "Not enough byte to initialize field `%s'.",
     597               0 :                           szTag );
     598               0 :                 return FALSE;
     599                 :             }
     600                 : 
     601                 :             /* ------------------------------------------------------------- */
     602                 :             /* Assign info the DDFField.                                     */
     603                 :             /* ------------------------------------------------------------- */
     604                 : 
     605                 :             paoFields[i].Initialize( poFieldDefn, 
     606                 :                                      pachData + _fieldAreaStart
     607                 :                                      + nFieldPos - nLeaderSize,
     608               0 :                                      nFieldLength );
     609                 :         }
     610                 :       
     611               0 :         return TRUE;
     612                 :     }
     613                 : }
     614                 : 
     615                 : /************************************************************************/
     616                 : /*                             FindField()                              */
     617                 : /************************************************************************/
     618                 : 
     619                 : /**
     620                 :  * Find the named field within this record.
     621                 :  *
     622                 :  * @param pszName The name of the field to fetch.  The comparison is
     623                 :  * case insensitive.
     624                 :  * @param iFieldIndex The instance of this field to fetch.  Use zero (the
     625                 :  * default) for the first instance.
     626                 :  *
     627                 :  * @return Pointer to the requested DDFField.  This pointer is to an
     628                 :  * internal object, and should not be freed.  It remains valid until
     629                 :  * the next record read. 
     630                 :  */
     631                 : 
     632           50422 : DDFField * DDFRecord::FindField( const char * pszName, int iFieldIndex )
     633                 : 
     634                 : {
     635          102327 :     for( int i = 0; i < nFieldCount; i++ )
     636                 :     {
     637          102277 :         if( EQUAL(paoFields[i].GetFieldDefn()->GetName(),pszName) )
     638                 :         {
     639           50372 :             if( iFieldIndex == 0 )
     640           50372 :                 return paoFields + i;
     641                 :             else
     642               0 :                 iFieldIndex--;
     643                 :         }
     644                 :     }
     645                 : 
     646              50 :     return NULL;
     647                 : }
     648                 : 
     649                 : /************************************************************************/
     650                 : /*                              GetField()                              */
     651                 : /************************************************************************/
     652                 : 
     653                 : /**
     654                 :  * Fetch field object based on index.
     655                 :  *
     656                 :  * @param i The index of the field to fetch.  Between 0 and GetFieldCount()-1.
     657                 :  *
     658                 :  * @return A DDFField pointer, or NULL if the index is out of range.
     659                 :  */
     660                 : 
     661           25259 : DDFField *DDFRecord::GetField( int i )
     662                 : 
     663                 : {
     664           25259 :     if( i < 0 || i >= nFieldCount )
     665               0 :         return NULL;
     666                 :     else
     667           25259 :         return paoFields + i;
     668                 : }
     669                 : 
     670                 : /************************************************************************/
     671                 : /*                           GetIntSubfield()                           */
     672                 : /************************************************************************/
     673                 : 
     674                 : /**
     675                 :  * Fetch value of a subfield as an integer.  This is a convenience
     676                 :  * function for fetching a subfield of a field within this record.
     677                 :  *
     678                 :  * @param pszField The name of the field containing the subfield.
     679                 :  * @param iFieldIndex The instance of this field within the record.  Use
     680                 :  * zero for the first instance of this field.
     681                 :  * @param pszSubfield The name of the subfield within the selected field.
     682                 :  * @param iSubfieldIndex The instance of this subfield within the record.
     683                 :  * Use zero for the first instance.
     684                 :  * @param pnSuccess Pointer to an int which will be set to TRUE if the fetch
     685                 :  * succeeds, or FALSE if it fails.  Use NULL if you don't want to check
     686                 :  * success.
     687                 :  * @return The value of the subfield, or zero if it failed for some reason.
     688                 :  */
     689                 : 
     690           48971 : int DDFRecord::GetIntSubfield( const char * pszField, int iFieldIndex,
     691                 :                                const char * pszSubfield, int iSubfieldIndex,
     692                 :                                int * pnSuccess )
     693                 : 
     694                 : {
     695                 :     DDFField    *poField;
     696                 :     int         nDummyErr;
     697                 : 
     698           48971 :     if( pnSuccess == NULL )
     699           48893 :         pnSuccess = &nDummyErr;
     700                 : 
     701           48971 :     *pnSuccess = FALSE;
     702                 :             
     703                 : /* -------------------------------------------------------------------- */
     704                 : /*      Fetch the field. If this fails, return zero.                    */
     705                 : /* -------------------------------------------------------------------- */
     706           48971 :     poField = FindField( pszField, iFieldIndex );
     707           48971 :     if( poField == NULL )
     708               0 :         return 0;
     709                 : 
     710                 : /* -------------------------------------------------------------------- */
     711                 : /*      Get the subfield definition                                     */
     712                 : /* -------------------------------------------------------------------- */
     713                 :     DDFSubfieldDefn     *poSFDefn;
     714                 : 
     715           48971 :     poSFDefn = poField->GetFieldDefn()->FindSubfieldDefn( pszSubfield );
     716           48971 :     if( poSFDefn == NULL )
     717              12 :         return 0;
     718                 : 
     719                 : /* -------------------------------------------------------------------- */
     720                 : /*      Get a pointer to the data.                                      */
     721                 : /* -------------------------------------------------------------------- */
     722                 :     int         nBytesRemaining;
     723                 :     
     724                 :     const char *pachData = poField->GetSubfieldData(poSFDefn,
     725                 :                                                     &nBytesRemaining,
     726           48959 :                                                     iSubfieldIndex);
     727                 : 
     728                 : /* -------------------------------------------------------------------- */
     729                 : /*      Return the extracted value.                                     */
     730                 : /*                                                                      */
     731                 : /*      Assume an error has occured if no bytes are consumed.           */
     732                 : /* -------------------------------------------------------------------- */
     733           48959 :     int nConsumedBytes = 0;
     734                 :     int nResult = poSFDefn->ExtractIntData( pachData, nBytesRemaining, 
     735           48959 :                                             &nConsumedBytes );
     736                 : 
     737           48959 :     if( nConsumedBytes > 0 )
     738           48959 :         *pnSuccess = TRUE;
     739                 : 
     740           48959 :     return nResult;
     741                 : }
     742                 : 
     743                 : /************************************************************************/
     744                 : /*                          GetFloatSubfield()                          */
     745                 : /************************************************************************/
     746                 : 
     747                 : /**
     748                 :  * Fetch value of a subfield as a float (double).  This is a convenience
     749                 :  * function for fetching a subfield of a field within this record.
     750                 :  *
     751                 :  * @param pszField The name of the field containing the subfield.
     752                 :  * @param iFieldIndex The instance of this field within the record.  Use
     753                 :  * zero for the first instance of this field.
     754                 :  * @param pszSubfield The name of the subfield within the selected field.
     755                 :  * @param iSubfieldIndex The instance of this subfield within the record.
     756                 :  * Use zero for the first instance.
     757                 :  * @param pnSuccess Pointer to an int which will be set to TRUE if the fetch
     758                 :  * succeeds, or FALSE if it fails.  Use NULL if you don't want to check
     759                 :  * success.
     760                 :  * @return The value of the subfield, or zero if it failed for some reason.
     761                 :  */
     762                 : 
     763              49 : double DDFRecord::GetFloatSubfield( const char * pszField, int iFieldIndex,
     764                 :                                  const char * pszSubfield, int iSubfieldIndex,
     765                 :                                     int * pnSuccess )
     766                 : 
     767                 : {
     768                 :     DDFField    *poField;
     769                 :     int         nDummyErr;
     770                 : 
     771              49 :     if( pnSuccess == NULL )
     772              31 :         pnSuccess = &nDummyErr;
     773                 : 
     774              49 :     *pnSuccess = FALSE;
     775                 :             
     776                 : /* -------------------------------------------------------------------- */
     777                 : /*      Fetch the field. If this fails, return zero.                    */
     778                 : /* -------------------------------------------------------------------- */
     779              49 :     poField = FindField( pszField, iFieldIndex );
     780              49 :     if( poField == NULL )
     781               0 :         return 0;
     782                 : 
     783                 : /* -------------------------------------------------------------------- */
     784                 : /*      Get the subfield definition                                     */
     785                 : /* -------------------------------------------------------------------- */
     786                 :     DDFSubfieldDefn     *poSFDefn;
     787                 : 
     788              49 :     poSFDefn = poField->GetFieldDefn()->FindSubfieldDefn( pszSubfield );
     789              49 :     if( poSFDefn == NULL )
     790               0 :         return 0;
     791                 : 
     792                 : /* -------------------------------------------------------------------- */
     793                 : /*      Get a pointer to the data.                                      */
     794                 : /* -------------------------------------------------------------------- */
     795                 :     int         nBytesRemaining;
     796                 :     
     797                 :     const char *pachData = poField->GetSubfieldData(poSFDefn,
     798                 :                                                     &nBytesRemaining,
     799              49 :                                                     iSubfieldIndex);
     800                 : 
     801                 : /* -------------------------------------------------------------------- */
     802                 : /*      Return the extracted value.                                     */
     803                 : /* -------------------------------------------------------------------- */
     804              49 :     int nConsumedBytes = 0;
     805                 :     double dfResult = poSFDefn->ExtractFloatData( pachData, nBytesRemaining, 
     806              49 :                                                   &nConsumedBytes );
     807                 : 
     808              49 :     if( nConsumedBytes > 0 )
     809              49 :         *pnSuccess = TRUE;
     810                 : 
     811              49 :     return dfResult;
     812                 : }
     813                 : 
     814                 : /************************************************************************/
     815                 : /*                         GetStringSubfield()                          */
     816                 : /************************************************************************/
     817                 : 
     818                 : /**
     819                 :  * Fetch value of a subfield as a string.  This is a convenience
     820                 :  * function for fetching a subfield of a field within this record.
     821                 :  *
     822                 :  * @param pszField The name of the field containing the subfield.
     823                 :  * @param iFieldIndex The instance of this field within the record.  Use
     824                 :  * zero for the first instance of this field.
     825                 :  * @param pszSubfield The name of the subfield within the selected field.
     826                 :  * @param iSubfieldIndex The instance of this subfield within the record.
     827                 :  * Use zero for the first instance.
     828                 :  * @param pnSuccess Pointer to an int which will be set to TRUE if the fetch
     829                 :  * succeeds, or FALSE if it fails.  Use NULL if you don't want to check
     830                 :  * success.
     831                 :  * @return The value of the subfield, or NULL if it failed for some reason.
     832                 :  * The returned pointer is to internal data and should not be modified or
     833                 :  * freed by the application.
     834                 :  */
     835                 : 
     836                 : const char *
     837             472 : DDFRecord::GetStringSubfield( const char * pszField, int iFieldIndex,
     838                 :                               const char * pszSubfield, int iSubfieldIndex,
     839                 :                               int * pnSuccess )
     840                 : 
     841                 : {
     842                 :     DDFField    *poField;
     843                 :     int         nDummyErr;
     844                 : 
     845             472 :     if( pnSuccess == NULL )
     846             466 :         pnSuccess = &nDummyErr;
     847                 : 
     848             472 :     *pnSuccess = FALSE;
     849                 :             
     850                 : /* -------------------------------------------------------------------- */
     851                 : /*      Fetch the field. If this fails, return zero.                    */
     852                 : /* -------------------------------------------------------------------- */
     853             472 :     poField = FindField( pszField, iFieldIndex );
     854             472 :     if( poField == NULL )
     855               0 :         return NULL;
     856                 : 
     857                 : /* -------------------------------------------------------------------- */
     858                 : /*      Get the subfield definition                                     */
     859                 : /* -------------------------------------------------------------------- */
     860                 :     DDFSubfieldDefn     *poSFDefn;
     861                 : 
     862             472 :     poSFDefn = poField->GetFieldDefn()->FindSubfieldDefn( pszSubfield );
     863             472 :     if( poSFDefn == NULL )
     864               0 :         return NULL;
     865                 : 
     866                 : /* -------------------------------------------------------------------- */
     867                 : /*      Get a pointer to the data.                                      */
     868                 : /* -------------------------------------------------------------------- */
     869                 :     int         nBytesRemaining;
     870                 :     
     871                 :     const char *pachData = poField->GetSubfieldData(poSFDefn,
     872                 :                                                     &nBytesRemaining,
     873             472 :                                                     iSubfieldIndex);
     874                 : 
     875                 : /* -------------------------------------------------------------------- */
     876                 : /*      Return the extracted value.                                     */
     877                 : /* -------------------------------------------------------------------- */
     878             472 :     *pnSuccess = TRUE;
     879                 : 
     880             472 :     return( poSFDefn->ExtractStringData( pachData, nBytesRemaining, NULL ) );
     881                 : }
     882                 : 
     883                 : /************************************************************************/
     884                 : /*                               Clone()                                */
     885                 : /************************************************************************/
     886                 : 
     887                 : /**
     888                 :  * Make a copy of a record.
     889                 :  *
     890                 :  * This method is used to make a copy of a record that will become (mostly)
     891                 :  * the properly of application.  However, it is automatically destroyed if
     892                 :  * the DDFModule it was created relative to is destroyed, as it's field
     893                 :  * and subfield definitions relate to that DDFModule.  However, it does
     894                 :  * persist even when the record returned by DDFModule::ReadRecord() is
     895                 :  * invalidated, such as when reading a new record.  This allows an application
     896                 :  * to cache whole DDFRecords.
     897                 :  *
     898                 :  * @return A new copy of the DDFRecord.  This can be delete'd by the
     899                 :  * application when no longer needed, otherwise it will be cleaned up when
     900                 :  * the DDFModule it relates to is destroyed or closed.
     901                 :  */
     902                 : 
     903           23949 : DDFRecord * DDFRecord::Clone()
     904                 : 
     905                 : {
     906                 :     DDFRecord   *poNR;
     907                 : 
     908           23949 :     poNR = new DDFRecord( poModule );
     909                 : 
     910           23949 :     poNR->nReuseHeader = FALSE;
     911           23949 :     poNR->nFieldOffset = nFieldOffset;
     912                 :     
     913           23949 :     poNR->nDataSize = nDataSize;
     914           23949 :     poNR->pachData = (char *) CPLMalloc(nDataSize);
     915           23949 :     memcpy( poNR->pachData, pachData, nDataSize );
     916                 :     
     917           23949 :     poNR->nFieldCount = nFieldCount;
     918           23949 :     poNR->paoFields = new DDFField[nFieldCount];
     919          112914 :     for( int i = 0; i < nFieldCount; i++ )
     920                 :     {
     921                 :         int     nOffset;
     922                 : 
     923           88965 :         nOffset = (paoFields[i].GetData() - pachData);
     924                 :         poNR->paoFields[i].Initialize( paoFields[i].GetFieldDefn(),
     925                 :                                        poNR->pachData + nOffset,
     926           88965 :                                        paoFields[i].GetDataSize() );
     927                 :     }
     928                 :     
     929           23949 :     poNR->bIsClone = TRUE;
     930           23949 :     poModule->AddCloneRecord( poNR );
     931                 : 
     932           23949 :     return poNR;
     933                 : }
     934                 : 
     935                 : /************************************************************************/
     936                 : /*                              CloneOn()                               */
     937                 : /************************************************************************/
     938                 : 
     939                 : /**
     940                 :  * Recreate a record referencing another module.
     941                 :  *
     942                 :  * Works similarly to the DDFRecord::Clone() method, but creates the
     943                 :  * new record with reference to a different DDFModule.  All DDFFieldDefn
     944                 :  * references are transcribed onto the new module based on field names.
     945                 :  * If any fields don't have a similarly named field on the target module
     946                 :  * the operation will fail.  No validation of field types and properties
     947                 :  * is done, but this operation is intended only to be used between 
     948                 :  * modules with matching definitions of all affected fields. 
     949                 :  *
     950                 :  * The new record will be managed as a clone by the target module in
     951                 :  * a manner similar to regular clones. 
     952                 :  *
     953                 :  * @param poTargetModule the module on which the record copy should be
     954                 :  * created.
     955                 :  *
     956                 :  * @return NULL on failure or a pointer to the cloned record.
     957                 :  */
     958                 : 
     959              18 : DDFRecord *DDFRecord::CloneOn( DDFModule *poTargetModule )
     960                 : 
     961                 : {
     962                 : /* -------------------------------------------------------------------- */
     963                 : /*      Verify that all fields have a corresponding field definition    */
     964                 : /*      on the target module.                                           */
     965                 : /* -------------------------------------------------------------------- */
     966                 :     int         i;
     967                 : 
     968              88 :     for( i = 0; i < nFieldCount; i++ )
     969                 :     {
     970              70 :         DDFFieldDefn    *poDefn = paoFields[i].GetFieldDefn();
     971                 : 
     972              70 :         if( poTargetModule->FindFieldDefn( poDefn->GetName() ) == NULL )
     973               0 :             return NULL;
     974                 :     }
     975                 : 
     976                 : /* -------------------------------------------------------------------- */
     977                 : /*      Create a clone.                                                 */
     978                 : /* -------------------------------------------------------------------- */
     979                 :     DDFRecord   *poClone;
     980                 : 
     981              18 :     poClone = Clone();
     982                 : 
     983                 : /* -------------------------------------------------------------------- */
     984                 : /*      Update all internal information to reference other module.      */
     985                 : /* -------------------------------------------------------------------- */
     986              88 :     for( i = 0; i < nFieldCount; i++ )
     987                 :     {
     988              70 :         DDFField        *poField = poClone->paoFields+i;
     989                 :         DDFFieldDefn    *poDefn;
     990                 : 
     991                 :         poDefn = poTargetModule->FindFieldDefn( 
     992              70 :             poField->GetFieldDefn()->GetName() );
     993                 :         
     994                 :         poField->Initialize( poDefn, poField->GetData(), 
     995              70 :                              poField->GetDataSize() );
     996                 :     }
     997                 : 
     998              18 :     poModule->RemoveCloneRecord( poClone );
     999              18 :     poClone->poModule = poTargetModule;
    1000              18 :     poTargetModule->AddCloneRecord( poClone );
    1001                 : 
    1002              18 :     return poClone;
    1003                 : }
    1004                 : 
    1005                 : 
    1006                 : /************************************************************************/
    1007                 : /*                            DeleteField()                             */
    1008                 : /************************************************************************/
    1009                 : 
    1010                 : /**
    1011                 :  * Delete a field instance from a record.
    1012                 :  *
    1013                 :  * Remove a field from this record, cleaning up the data            
    1014                 :  * portion and repacking the fields list.  We don't try to          
    1015                 :  * reallocate the data area of the record to be smaller.            
    1016                 :  *                                                                       
    1017                 :  * NOTE: This method doesn't actually remove the header             
    1018                 :  * information for this field from the record tag list yet.        
    1019                 :  * This should be added if the resulting record is even to be      
    1020                 :  * written back to disk!                                           
    1021                 :  *
    1022                 :  * @param poTarget the field instance on this record to delete.
    1023                 :  *
    1024                 :  * @return TRUE on success, or FALSE on failure.  Failure can occur if 
    1025                 :  * poTarget isn't really a field on this record.
    1026                 :  */
    1027                 : 
    1028               0 : int DDFRecord::DeleteField( DDFField *poTarget )
    1029                 : 
    1030                 : {
    1031                 :     int         iTarget, i;
    1032                 : 
    1033                 : /* -------------------------------------------------------------------- */
    1034                 : /*      Find which field we are to delete.                              */
    1035                 : /* -------------------------------------------------------------------- */
    1036               0 :     for( iTarget = 0; iTarget < nFieldCount; iTarget++ )
    1037                 :     {
    1038               0 :         if( paoFields + iTarget == poTarget )
    1039               0 :             break;
    1040                 :     }
    1041                 : 
    1042               0 :     if( iTarget == nFieldCount )
    1043               0 :         return FALSE;
    1044                 : 
    1045                 : /* -------------------------------------------------------------------- */
    1046                 : /*      Change the target fields data size to zero.  This takes care    */
    1047                 : /*      of repacking the data array, and updating all the following     */
    1048                 : /*      field data pointers.                                            */
    1049                 : /* -------------------------------------------------------------------- */
    1050               0 :     ResizeField( poTarget, 0 );
    1051                 : 
    1052                 : /* -------------------------------------------------------------------- */
    1053                 : /*      remove the target field, moving down all the other fields       */
    1054                 : /*      one step in the field list.                                     */
    1055                 : /* -------------------------------------------------------------------- */
    1056               0 :     for( i = iTarget; i < nFieldCount-1; i++ )
    1057                 :     {
    1058               0 :         paoFields[i] = paoFields[i+1];
    1059                 :     }
    1060                 : 
    1061               0 :     nFieldCount--;
    1062                 : 
    1063               0 :     return TRUE;
    1064                 : }
    1065                 : 
    1066                 : /************************************************************************/
    1067                 : /*                            ResizeField()                             */
    1068                 : /************************************************************************/
    1069                 : 
    1070                 : /**
    1071                 :  * Alter field data size within record.
    1072                 :  *
    1073                 :  * This method will rearrange a DDFRecord altering the amount of space
    1074                 :  * reserved for one of the existing fields.  All following fields will
    1075                 :  * be shifted accordingly.  This includes updating the DDFField infos, 
    1076                 :  * and actually moving stuff within the data array after reallocating
    1077                 :  * to the desired size.
    1078                 :  *
    1079                 :  * @param poField the field to alter.
    1080                 :  * @param nNewDataSize the number of data bytes to be reserved for the field.
    1081                 :  *
    1082                 :  * @return TRUE on success or FALSE on failure. 
    1083                 :  */
    1084                 : 
    1085               8 : int DDFRecord::ResizeField( DDFField *poField, int nNewDataSize )
    1086                 : 
    1087                 : {
    1088                 :     int         iTarget, i;
    1089                 :     int         nBytesToMove;
    1090                 : 
    1091                 : /* -------------------------------------------------------------------- */
    1092                 : /*      Find which field we are to resize.                              */
    1093                 : /* -------------------------------------------------------------------- */
    1094              40 :     for( iTarget = 0; iTarget < nFieldCount; iTarget++ )
    1095                 :     {
    1096              40 :         if( paoFields + iTarget == poField )
    1097               8 :             break;
    1098                 :     }
    1099                 : 
    1100               8 :     if( iTarget == nFieldCount )
    1101                 :     {
    1102               0 :         CPLAssert( FALSE );
    1103               0 :         return FALSE;
    1104                 :     }
    1105                 : 
    1106                 : /* -------------------------------------------------------------------- */
    1107                 : /*      Reallocate the data buffer accordingly.                         */
    1108                 : /* -------------------------------------------------------------------- */
    1109               8 :     int nBytesToAdd = nNewDataSize - poField->GetDataSize();
    1110               8 :     const char *pachOldData = pachData;
    1111                 : 
    1112                 :     // Don't realloc things smaller ... we will cut off some data.
    1113               8 :     if( nBytesToAdd > 0 )
    1114               0 :         pachData = (char *) CPLRealloc(pachData, nDataSize + nBytesToAdd );
    1115                 : 
    1116               8 :     nDataSize += nBytesToAdd;
    1117                 : 
    1118                 : /* -------------------------------------------------------------------- */
    1119                 : /*      How much data needs to be shifted up or down after this field?  */
    1120                 : /* -------------------------------------------------------------------- */
    1121                 :     nBytesToMove = nDataSize 
    1122               8 :         - (poField->GetData()+poField->GetDataSize()-pachOldData+nBytesToAdd);
    1123                 : 
    1124                 : /* -------------------------------------------------------------------- */
    1125                 : /*      Update fields to point into newly allocated buffer.             */
    1126                 : /* -------------------------------------------------------------------- */
    1127              48 :     for( i = 0; i < nFieldCount; i++ )
    1128                 :     {
    1129                 :         int     nOffset;
    1130                 : 
    1131              40 :         nOffset = paoFields[i].GetData() - pachOldData;
    1132                 :         paoFields[i].Initialize( paoFields[i].GetFieldDefn(), 
    1133                 :                                  pachData + nOffset, 
    1134              40 :                                  paoFields[i].GetDataSize() );
    1135                 :     }
    1136                 : 
    1137                 : /* -------------------------------------------------------------------- */
    1138                 : /*      Shift the data beyond this field up or down as needed.          */
    1139                 : /* -------------------------------------------------------------------- */
    1140               8 :     if( nBytesToMove > 0 )
    1141                 :         memmove( (char *)poField->GetData()+poField->GetDataSize()+nBytesToAdd,
    1142                 :                  (char *)poField->GetData()+poField->GetDataSize(), 
    1143               0 :                  nBytesToMove );
    1144                 :              
    1145                 : /* -------------------------------------------------------------------- */
    1146                 : /*      Update the target fields info.                                  */
    1147                 : /* -------------------------------------------------------------------- */
    1148                 :     poField->Initialize( poField->GetFieldDefn(),
    1149                 :                          poField->GetData(), 
    1150               8 :                          poField->GetDataSize() + nBytesToAdd );
    1151                 : 
    1152                 : /* -------------------------------------------------------------------- */
    1153                 : /*      Shift all following fields down, and update their data          */
    1154                 : /*      locations.                                                      */
    1155                 : /* -------------------------------------------------------------------- */
    1156               8 :     if( nBytesToAdd < 0 )
    1157                 :     {
    1158               0 :         for( i = iTarget+1; i < nFieldCount; i++ )
    1159                 :         {
    1160                 :             char *pszOldDataLocation;
    1161                 : 
    1162               0 :             pszOldDataLocation = (char *) paoFields[i].GetData();
    1163                 : 
    1164                 :             paoFields[i].Initialize( paoFields[i].GetFieldDefn(), 
    1165                 :                                      pszOldDataLocation + nBytesToAdd,
    1166               0 :                                      paoFields[i].GetDataSize() ); 
    1167                 :         }
    1168                 :     }
    1169                 :     else
    1170                 :     {
    1171               8 :         for( i = nFieldCount-1; i > iTarget; i-- )
    1172                 :         {
    1173                 :             char *pszOldDataLocation;
    1174                 : 
    1175               0 :             pszOldDataLocation = (char *) paoFields[i].GetData();
    1176                 : 
    1177                 :             paoFields[i].Initialize( paoFields[i].GetFieldDefn(), 
    1178                 :                                      pszOldDataLocation + nBytesToAdd,
    1179               0 :                                      paoFields[i].GetDataSize() ); 
    1180                 :         }
    1181                 :     }
    1182                 : 
    1183               8 :     return TRUE;
    1184                 : }
    1185                 : 
    1186                 : /************************************************************************/
    1187                 : /*                              AddField()                              */
    1188                 : /************************************************************************/
    1189                 : 
    1190                 : /**
    1191                 :  * Add a new field to record.
    1192                 :  *
    1193                 :  * Add a new zero sized field to the record.  The new field is always
    1194                 :  * added at the end of the record. 
    1195                 :  *
    1196                 :  * NOTE: This method doesn't currently update the header information for
    1197                 :  * the record to include the field information for this field, so the
    1198                 :  * resulting record image isn't suitable for writing to disk.  However, 
    1199                 :  * everything else about the record state should be updated properly to 
    1200                 :  * reflect the new field.
    1201                 :  *
    1202                 :  * @param poDefn the definition of the field to be added.
    1203                 :  *
    1204                 :  * @return the field object on success, or NULL on failure.
    1205                 :  */
    1206                 : 
    1207               0 : DDFField *DDFRecord::AddField( DDFFieldDefn *poDefn )
    1208                 : 
    1209                 : {
    1210                 : /* -------------------------------------------------------------------- */
    1211                 : /*      Reallocate the fields array larger by one, and initialize       */
    1212                 : /*      the new field.                                                  */
    1213                 : /* -------------------------------------------------------------------- */
    1214                 :     DDFField    *paoNewFields;
    1215                 : 
    1216               0 :     paoNewFields = new DDFField[nFieldCount+1];
    1217               0 :     if( nFieldCount > 0 )
    1218                 :     {
    1219               0 :         memcpy( paoNewFields, paoFields, sizeof(DDFField) * nFieldCount );
    1220               0 :         delete[] paoFields;
    1221                 :     }
    1222               0 :     paoFields = paoNewFields;
    1223               0 :     nFieldCount++;
    1224                 : 
    1225                 : /* -------------------------------------------------------------------- */
    1226                 : /*      Initialize the new field properly.                              */
    1227                 : /* -------------------------------------------------------------------- */
    1228               0 :     if( nFieldCount == 1 )
    1229                 :     {
    1230               0 :         paoFields[0].Initialize( poDefn, GetData(), 0 );
    1231                 :     }
    1232                 :     else
    1233                 :     {
    1234                 :         paoFields[nFieldCount-1].Initialize( 
    1235                 :             poDefn, 
    1236                 :             paoFields[nFieldCount-2].GetData()
    1237                 :             + paoFields[nFieldCount-2].GetDataSize(), 
    1238               0 :             0 );
    1239                 :     }
    1240                 : 
    1241                 : /* -------------------------------------------------------------------- */
    1242                 : /*      Initialize field.                                               */
    1243                 : /* -------------------------------------------------------------------- */
    1244               0 :     CreateDefaultFieldInstance( paoFields + nFieldCount-1, 0 );
    1245                 : 
    1246               0 :     return paoFields + (nFieldCount - 1);
    1247                 : }
    1248                 : 
    1249                 : /************************************************************************/
    1250                 : /*                            SetFieldRaw()                             */
    1251                 : /************************************************************************/
    1252                 : 
    1253                 : /**
    1254                 :  * Set the raw contents of a field instance.
    1255                 :  *
    1256                 :  * @param poField the field to set data within. 
    1257                 :  * @param iIndexWithinField The instance of this field to replace.  Must
    1258                 :  * be a value between 0 and GetRepeatCount().  If GetRepeatCount() is used, a
    1259                 :  * new instance of the field is appeneded.
    1260                 :  * @param pachRawData the raw data to replace this field instance with.
    1261                 :  * @param nRawDataSize the number of bytes pointed to by pachRawData.
    1262                 :  *
    1263                 :  * @return TRUE on success or FALSE on failure.
    1264                 :  */
    1265                 : 
    1266                 : int
    1267               8 : DDFRecord::SetFieldRaw( DDFField *poField, int iIndexWithinField,
    1268                 :                         const char *pachRawData, int nRawDataSize )
    1269                 : 
    1270                 : {
    1271                 :     int         iTarget, nRepeatCount;
    1272                 : 
    1273                 : /* -------------------------------------------------------------------- */
    1274                 : /*      Find which field we are to update.                              */
    1275                 : /* -------------------------------------------------------------------- */
    1276              40 :     for( iTarget = 0; iTarget < nFieldCount; iTarget++ )
    1277                 :     {
    1278              40 :         if( paoFields + iTarget == poField )
    1279               8 :             break;
    1280                 :     }
    1281                 : 
    1282               8 :     if( iTarget == nFieldCount )
    1283               0 :         return FALSE;
    1284                 : 
    1285               8 :     nRepeatCount = poField->GetRepeatCount();
    1286                 : 
    1287               8 :     if( iIndexWithinField < 0 || iIndexWithinField > nRepeatCount )
    1288               0 :         return FALSE;
    1289                 : 
    1290                 : /* -------------------------------------------------------------------- */
    1291                 : /*      Are we adding an instance?  This is easier and different        */
    1292                 : /*      than replacing an existing instance.                            */
    1293                 : /* -------------------------------------------------------------------- */
    1294               8 :     if( iIndexWithinField == nRepeatCount 
    1295                 :         || !poField->GetFieldDefn()->IsRepeating() )
    1296                 :     {
    1297                 :         char    *pachFieldData;
    1298                 :         int     nOldSize;
    1299                 : 
    1300               0 :         if( !poField->GetFieldDefn()->IsRepeating() && iIndexWithinField != 0 )
    1301               0 :             return FALSE;
    1302                 : 
    1303               0 :         nOldSize = poField->GetDataSize();
    1304               0 :         if( nOldSize == 0 )
    1305               0 :             nOldSize++; // for added DDF_FIELD_TERMINATOR. 
    1306                 : 
    1307               0 :         if( !ResizeField( poField, nOldSize + nRawDataSize ) )
    1308               0 :             return FALSE;
    1309                 : 
    1310               0 :         pachFieldData = (char *) poField->GetData();
    1311                 :         memcpy( pachFieldData + nOldSize - 1, 
    1312               0 :                 pachRawData, nRawDataSize );
    1313               0 :         pachFieldData[nOldSize+nRawDataSize-1] = DDF_FIELD_TERMINATOR;
    1314                 : 
    1315               0 :         return TRUE;
    1316                 :     }
    1317                 : 
    1318                 : /* -------------------------------------------------------------------- */
    1319                 : /*      Get a pointer to the start of the existing data for this        */
    1320                 : /*      iteration of the field.                                         */
    1321                 : /* -------------------------------------------------------------------- */
    1322                 :     const char *pachWrkData;
    1323                 :     int         nInstanceSize;
    1324                 : 
    1325                 :     // We special case this to avoid alot of warnings when initializing 
    1326                 :     // the field the first time.
    1327               8 :     if( poField->GetDataSize() == 0 )
    1328                 :     {
    1329               0 :         pachWrkData = poField->GetData();
    1330               0 :         nInstanceSize = 0;
    1331                 :     }
    1332                 :     else
    1333                 :     {
    1334                 :         pachWrkData = poField->GetInstanceData( iIndexWithinField, 
    1335               8 :                                                 &nInstanceSize );
    1336                 :     }
    1337                 : 
    1338                 : /* -------------------------------------------------------------------- */
    1339                 : /*      Create new image of this whole field.                           */
    1340                 : /* -------------------------------------------------------------------- */
    1341                 :     char        *pachNewImage;
    1342                 :     int         nPreBytes, nPostBytes, nNewFieldSize;
    1343                 : 
    1344               8 :     nNewFieldSize = poField->GetDataSize() - nInstanceSize + nRawDataSize;
    1345                 : 
    1346               8 :     pachNewImage = (char *) CPLMalloc(nNewFieldSize);
    1347                 : 
    1348               8 :     nPreBytes = pachWrkData - poField->GetData();
    1349               8 :     nPostBytes = poField->GetDataSize() - nPreBytes - nInstanceSize;
    1350                 : 
    1351               8 :     memcpy( pachNewImage, poField->GetData(), nPreBytes );
    1352                 :     memcpy( pachNewImage + nPreBytes + nRawDataSize, 
    1353                 :             poField->GetData() + nPreBytes + nInstanceSize,
    1354               8 :             nPostBytes );
    1355               8 :     memcpy( pachNewImage + nPreBytes, pachRawData, nRawDataSize );
    1356                 : 
    1357                 : /* -------------------------------------------------------------------- */
    1358                 : /*      Resize the field to the desired new size.                       */
    1359                 : /* -------------------------------------------------------------------- */
    1360               8 :     ResizeField( poField, nNewFieldSize );
    1361                 : 
    1362               8 :     memcpy( (void *) poField->GetData(), pachNewImage, nNewFieldSize );
    1363               8 :     CPLFree( pachNewImage );
    1364                 : 
    1365               8 :     return TRUE;
    1366                 : }
    1367                 : 
    1368                 : /************************************************************************/
    1369                 : /*                           UpdateFieldRaw()                           */
    1370                 : /************************************************************************/
    1371                 : 
    1372                 : int
    1373               0 : DDFRecord::UpdateFieldRaw( DDFField *poField, int iIndexWithinField,
    1374                 :                            int nStartOffset, int nOldSize, 
    1375                 :                            const char *pachRawData, int nRawDataSize )
    1376                 : 
    1377                 : {
    1378                 :     int         iTarget, nRepeatCount;
    1379                 : 
    1380                 : /* -------------------------------------------------------------------- */
    1381                 : /*      Find which field we are to update.                              */
    1382                 : /* -------------------------------------------------------------------- */
    1383               0 :     for( iTarget = 0; iTarget < nFieldCount; iTarget++ )
    1384                 :     {
    1385               0 :         if( paoFields + iTarget == poField )
    1386               0 :             break;
    1387                 :     }
    1388                 : 
    1389               0 :     if( iTarget == nFieldCount )
    1390               0 :         return FALSE;
    1391                 : 
    1392               0 :     nRepeatCount = poField->GetRepeatCount();
    1393                 : 
    1394               0 :     if( iIndexWithinField < 0 || iIndexWithinField >= nRepeatCount )
    1395               0 :         return FALSE;
    1396                 : 
    1397                 : /* -------------------------------------------------------------------- */
    1398                 : /*      Figure out how much pre and post data there is.                 */
    1399                 : /* -------------------------------------------------------------------- */
    1400                 :     char *pachWrkData;
    1401                 :     int         nInstanceSize, nPostBytes, nPreBytes;
    1402                 :         
    1403                 :     pachWrkData = (char *) poField->GetInstanceData( iIndexWithinField, 
    1404               0 :                                                      &nInstanceSize );
    1405               0 :     nPreBytes = pachWrkData - poField->GetData() + nStartOffset;
    1406               0 :     nPostBytes = poField->GetDataSize() - nPreBytes - nOldSize;
    1407                 : 
    1408                 : /* -------------------------------------------------------------------- */
    1409                 : /*      If we aren't changing the size, just copy over the existing     */
    1410                 : /*      data.                                                           */
    1411                 : /* -------------------------------------------------------------------- */
    1412               0 :     if( nOldSize == nRawDataSize )
    1413                 :     {
    1414               0 :         memcpy( pachWrkData + nStartOffset, pachRawData, nRawDataSize );
    1415               0 :         return TRUE;
    1416                 :     }
    1417                 : 
    1418                 : /* -------------------------------------------------------------------- */
    1419                 : /*      If we are shrinking, move in the new data, and shuffle down     */
    1420                 : /*      the old before resizing.                                        */
    1421                 : /* -------------------------------------------------------------------- */
    1422               0 :     if( nRawDataSize < nOldSize )
    1423                 :     {
    1424                 :         memcpy( ((char*) poField->GetData()) + nPreBytes, 
    1425               0 :                 pachRawData, nRawDataSize );
    1426                 :         memmove( ((char *) poField->GetData()) + nPreBytes + nRawDataSize, 
    1427                 :                  ((char *) poField->GetData()) + nPreBytes + nOldSize, 
    1428               0 :                  nPostBytes );
    1429                 :     }
    1430                 : 
    1431                 : /* -------------------------------------------------------------------- */
    1432                 : /*      Resize the whole buffer.                                        */
    1433                 : /* -------------------------------------------------------------------- */
    1434               0 :     if( !ResizeField( poField, 
    1435                 :                       poField->GetDataSize() - nOldSize + nRawDataSize ) )
    1436               0 :         return FALSE;
    1437                 : 
    1438                 : /* -------------------------------------------------------------------- */
    1439                 : /*      If we growing the buffer, shuffle up the post data, and         */
    1440                 : /*      move in our new values.                                         */
    1441                 : /* -------------------------------------------------------------------- */
    1442               0 :     if( nRawDataSize >= nOldSize )
    1443                 :     {
    1444                 :         memmove( ((char *) poField->GetData()) + nPreBytes + nRawDataSize, 
    1445                 :                  ((char *) poField->GetData()) + nPreBytes + nOldSize, 
    1446               0 :                  nPostBytes );
    1447                 :         memcpy( ((char*) poField->GetData()) + nPreBytes, 
    1448               0 :                 pachRawData, nRawDataSize );
    1449                 :     }
    1450                 : 
    1451               0 :     return TRUE;
    1452                 : }
    1453                 : 
    1454                 : /************************************************************************/
    1455                 : /*                           ResetDirectory()                           */
    1456                 : /*                                                                      */
    1457                 : /*      Re-prepares the directory information for the record.           */
    1458                 : /************************************************************************/
    1459                 : 
    1460               0 : int DDFRecord::ResetDirectory()
    1461                 : 
    1462                 : {
    1463                 :     int iField;
    1464                 : 
    1465                 : /* -------------------------------------------------------------------- */
    1466                 : /*      Eventually we should try to optimize the size of offset and     */
    1467                 : /*      field length.  For now we will use 5 for each which is          */
    1468                 : /*      pretty big.                                                     */
    1469                 : /* -------------------------------------------------------------------- */
    1470               0 :     _sizeFieldPos = 5;
    1471               0 :     _sizeFieldLength = 5;
    1472                 : 
    1473                 : /* -------------------------------------------------------------------- */
    1474                 : /*      Compute how large the directory needs to be.                    */
    1475                 : /* -------------------------------------------------------------------- */
    1476                 :     int nEntrySize, nDirSize;
    1477                 : 
    1478               0 :     nEntrySize = _sizeFieldPos + _sizeFieldLength + _sizeFieldTag;
    1479               0 :     nDirSize = nEntrySize * nFieldCount + 1;
    1480                 : 
    1481                 : /* -------------------------------------------------------------------- */
    1482                 : /*      If the directory size is different than what is currently       */
    1483                 : /*      reserved for it, we must resize.                                */
    1484                 : /* -------------------------------------------------------------------- */
    1485               0 :     if( nDirSize != nFieldOffset )
    1486                 :     {
    1487                 :         char *pachNewData;
    1488                 :         int  nNewDataSize;
    1489                 : 
    1490               0 :         nNewDataSize = nDataSize - nFieldOffset + nDirSize;
    1491               0 :         pachNewData = (char *) CPLMalloc(nNewDataSize);
    1492                 :         memcpy( pachNewData + nDirSize, 
    1493                 :                 pachData + nFieldOffset, 
    1494               0 :                 nNewDataSize - nDirSize );
    1495                 :      
    1496               0 :         for( iField = 0; iField < nFieldCount; iField++ )
    1497                 :         {
    1498                 :             int nOffset;
    1499               0 :             DDFField *poField = GetField( iField );
    1500                 : 
    1501               0 :             nOffset = poField->GetData() - pachData - nFieldOffset + nDirSize;
    1502                 :             poField->Initialize( poField->GetFieldDefn(), 
    1503                 :                                  pachNewData + nOffset, 
    1504               0 :                                  poField->GetDataSize() );
    1505                 :         }
    1506                 : 
    1507               0 :         CPLFree( pachData );
    1508               0 :         pachData = pachNewData;
    1509               0 :         nDataSize = nNewDataSize;
    1510               0 :         nFieldOffset = nDirSize;
    1511                 :     }
    1512                 : 
    1513                 : /* -------------------------------------------------------------------- */
    1514                 : /*      Now set each directory entry.                                   */
    1515                 : /* -------------------------------------------------------------------- */
    1516               0 :     for( iField = 0; iField < nFieldCount; iField++ )
    1517                 :     {
    1518               0 :         DDFField *poField = GetField( iField );
    1519               0 :         DDFFieldDefn *poDefn = poField->GetFieldDefn();
    1520                 :         char      szFormat[128];
    1521                 : 
    1522                 :         sprintf( szFormat, "%%%ds%%0%dd%%0%dd", 
    1523               0 :                  _sizeFieldTag, _sizeFieldLength, _sizeFieldPos );
    1524                 : 
    1525                 :         sprintf( pachData + nEntrySize * iField, szFormat, 
    1526                 :                  poDefn->GetName(), poField->GetDataSize(),
    1527               0 :                  poField->GetData() - pachData - nFieldOffset );
    1528                 :     }
    1529                 : 
    1530               0 :     pachData[nEntrySize * nFieldCount] = DDF_FIELD_TERMINATOR;
    1531                 :         
    1532               0 :     return TRUE;
    1533                 : }
    1534                 : 
    1535                 : /************************************************************************/
    1536                 : /*                     CreateDefaultFieldInstance()                     */
    1537                 : /************************************************************************/
    1538                 : 
    1539                 : /**
    1540                 :  * Initialize default instance.
    1541                 :  *
    1542                 :  * This method is normally only used internally by the AddField() method
    1543                 :  * to initialize the new field instance with default subfield values.  It
    1544                 :  * installs default data for one instance of the field in the record
    1545                 :  * using the DDFFieldDefn::GetDefaultValue() method and 
    1546                 :  * DDFRecord::SetFieldRaw(). 
    1547                 :  *
    1548                 :  * @param poField the field within the record to be assign a default 
    1549                 :  * instance. 
    1550                 :  * @param iIndexWithinField the instance to set (may not have been tested with
    1551                 :  * values other than 0). 
    1552                 :  *
    1553                 :  * @return TRUE on success or FALSE on failure. 
    1554                 :  */
    1555                 : 
    1556               0 : int DDFRecord::CreateDefaultFieldInstance( DDFField *poField, 
    1557                 :                                            int iIndexWithinField )
    1558                 : 
    1559                 : {
    1560                 :     int nRawSize, nSuccess;
    1561                 :     char *pachRawData;
    1562                 : 
    1563               0 :     pachRawData = poField->GetFieldDefn()->GetDefaultValue( &nRawSize );
    1564               0 :     if( pachRawData == NULL )
    1565               0 :         return FALSE;
    1566                 : 
    1567               0 :     nSuccess = SetFieldRaw( poField, iIndexWithinField, pachRawData, nRawSize);
    1568                 : 
    1569               0 :     CPLFree( pachRawData );
    1570                 : 
    1571               0 :     return nSuccess;
    1572                 : }
    1573                 : 
    1574                 : /************************************************************************/
    1575                 : /*                         SetStringSubfield()                          */
    1576                 : /************************************************************************/
    1577                 : 
    1578                 : /**
    1579                 :  * Set a string subfield in record.
    1580                 :  *
    1581                 :  * The value of a given subfield is replaced with a new string value 
    1582                 :  * formatted appropriately. 
    1583                 :  *
    1584                 :  * @param pszField the field name to operate on.
    1585                 :  * @param iFieldIndex the field index to operate on (zero based).
    1586                 :  * @param pszSubfield the subfield name to operate on. 
    1587                 :  * @param iSubfieldIndex the subfield index to operate on (zero based). 
    1588                 :  * @param pszValue the new string to place in the subfield.  This may be 
    1589                 :  * arbitrary binary bytes if nValueLength is specified. 
    1590                 :  * @param nValueLength the number of valid bytes in pszValue, may be -1 to 
    1591                 :  * internally fetch with strlen(). 
    1592                 :  * 
    1593                 :  * @return TRUE if successful, and FALSE if not. 
    1594                 :  */
    1595                 : 
    1596               0 : int DDFRecord::SetStringSubfield( const char *pszField, int iFieldIndex, 
    1597                 :                                   const char *pszSubfield, int iSubfieldIndex,
    1598                 :                                   const char *pszValue, int nValueLength )
    1599                 : 
    1600                 : {
    1601                 : /* -------------------------------------------------------------------- */
    1602                 : /*      Fetch the field. If this fails, return zero.                    */
    1603                 : /* -------------------------------------------------------------------- */
    1604                 :     DDFField *poField; 
    1605                 : 
    1606               0 :     poField = FindField( pszField, iFieldIndex );
    1607               0 :     if( poField == NULL )
    1608               0 :         return FALSE;
    1609                 : 
    1610                 : /* -------------------------------------------------------------------- */
    1611                 : /*      Get the subfield definition                                     */
    1612                 : /* -------------------------------------------------------------------- */
    1613                 :     DDFSubfieldDefn     *poSFDefn;
    1614                 : 
    1615               0 :     poSFDefn = poField->GetFieldDefn()->FindSubfieldDefn( pszSubfield );
    1616               0 :     if( poSFDefn == NULL )
    1617               0 :         return FALSE;
    1618                 : 
    1619                 : /* -------------------------------------------------------------------- */
    1620                 : /*      How long will the formatted value be?                           */
    1621                 : /* -------------------------------------------------------------------- */
    1622                 :     int nFormattedLen;
    1623                 : 
    1624               0 :     if( !poSFDefn->FormatStringValue( NULL, 0, &nFormattedLen, pszValue,
    1625                 :                                       nValueLength ) )
    1626               0 :         return FALSE;
    1627                 : 
    1628                 : /* -------------------------------------------------------------------- */
    1629                 : /*      Get a pointer to the data.                                      */
    1630                 : /* -------------------------------------------------------------------- */
    1631                 :     int         nMaxBytes;
    1632                 :     char *pachSubfieldData = (char *) 
    1633                 :         poField->GetSubfieldData(poSFDefn, &nMaxBytes,
    1634               0 :                                  iSubfieldIndex);
    1635                 : 
    1636                 : /* -------------------------------------------------------------------- */
    1637                 : /*      Add new instance if we have run out of data.                    */
    1638                 : /* -------------------------------------------------------------------- */
    1639               0 :     if( nMaxBytes == 0 
    1640               0 :         || (nMaxBytes == 1 && pachSubfieldData[0] == DDF_FIELD_TERMINATOR) )
    1641                 :     {
    1642               0 :         CreateDefaultFieldInstance( poField, iSubfieldIndex );
    1643                 : 
    1644                 :         // Refetch.
    1645                 :         pachSubfieldData = (char *) 
    1646                 :             poField->GetSubfieldData(poSFDefn, &nMaxBytes,
    1647               0 :                                      iSubfieldIndex);
    1648                 :     }
    1649                 : 
    1650                 : /* -------------------------------------------------------------------- */
    1651                 : /*      If the new length matches the existing length, just overlay     */
    1652                 : /*      and return.                                                     */
    1653                 : /* -------------------------------------------------------------------- */
    1654                 :     int nExistingLength;
    1655                 : 
    1656               0 :     poSFDefn->GetDataLength( pachSubfieldData, nMaxBytes, &nExistingLength );
    1657                 : 
    1658               0 :     if( nExistingLength == nFormattedLen )
    1659                 :     {
    1660                 :         return poSFDefn->FormatStringValue( pachSubfieldData, nFormattedLen,
    1661               0 :                                             NULL, pszValue, nValueLength );
    1662                 :     }
    1663                 : 
    1664                 : /* -------------------------------------------------------------------- */
    1665                 : /*      We will need to resize the raw data.                            */
    1666                 : /* -------------------------------------------------------------------- */
    1667                 :     const char *pachFieldInstData;
    1668                 :     int         nInstanceSize, nStartOffset, nSuccess;
    1669                 :     char *pachNewData;
    1670                 : 
    1671                 :     pachFieldInstData = poField->GetInstanceData( iFieldIndex,
    1672               0 :                                                   &nInstanceSize );
    1673                 : 
    1674               0 :     nStartOffset = pachSubfieldData - pachFieldInstData;
    1675                 : 
    1676               0 :     pachNewData = (char *) CPLMalloc(nFormattedLen);
    1677                 :     poSFDefn->FormatStringValue( pachNewData, nFormattedLen, NULL, 
    1678               0 :                                  pszValue, nValueLength );
    1679                 :     
    1680                 :     nSuccess = UpdateFieldRaw( poField, iFieldIndex,
    1681                 :                                nStartOffset, nExistingLength, 
    1682               0 :                                pachNewData, nFormattedLen );
    1683                 : 
    1684               0 :     CPLFree( pachNewData );
    1685                 : 
    1686               0 :     return nSuccess;
    1687                 : }
    1688                 : 
    1689                 : /************************************************************************/
    1690                 : /*                           SetIntSubfield()                           */
    1691                 : /************************************************************************/
    1692                 : 
    1693                 : /**
    1694                 :  * Set an integer subfield in record.
    1695                 :  *
    1696                 :  * The value of a given subfield is replaced with a new integer value 
    1697                 :  * formatted appropriately. 
    1698                 :  *
    1699                 :  * @param pszField the field name to operate on.
    1700                 :  * @param iFieldIndex the field index to operate on (zero based).
    1701                 :  * @param pszSubfield the subfield name to operate on. 
    1702                 :  * @param iSubfieldIndex the subfield index to operate on (zero based). 
    1703                 :  * @param nNewValue the new value to place in the subfield. 
    1704                 :  * 
    1705                 :  * @return TRUE if successful, and FALSE if not. 
    1706                 :  */
    1707                 : 
    1708               0 : int DDFRecord::SetIntSubfield( const char *pszField, int iFieldIndex, 
    1709                 :                                const char *pszSubfield, int iSubfieldIndex,
    1710                 :                                int nNewValue )
    1711                 : 
    1712                 : {
    1713                 : /* -------------------------------------------------------------------- */
    1714                 : /*      Fetch the field. If this fails, return zero.                    */
    1715                 : /* -------------------------------------------------------------------- */
    1716                 :     DDFField *poField; 
    1717                 : 
    1718               0 :     poField = FindField( pszField, iFieldIndex );
    1719               0 :     if( poField == NULL )
    1720               0 :         return FALSE;
    1721                 : 
    1722                 : /* -------------------------------------------------------------------- */
    1723                 : /*      Get the subfield definition                                     */
    1724                 : /* -------------------------------------------------------------------- */
    1725                 :     DDFSubfieldDefn     *poSFDefn;
    1726                 : 
    1727               0 :     poSFDefn = poField->GetFieldDefn()->FindSubfieldDefn( pszSubfield );
    1728               0 :     if( poSFDefn == NULL )
    1729               0 :         return FALSE;
    1730                 : 
    1731                 : /* -------------------------------------------------------------------- */
    1732                 : /*      How long will the formatted value be?                           */
    1733                 : /* -------------------------------------------------------------------- */
    1734                 :     int nFormattedLen;
    1735                 : 
    1736               0 :     if( !poSFDefn->FormatIntValue( NULL, 0, &nFormattedLen, nNewValue ) )
    1737               0 :         return FALSE;
    1738                 : 
    1739                 : /* -------------------------------------------------------------------- */
    1740                 : /*      Get a pointer to the data.                                      */
    1741                 : /* -------------------------------------------------------------------- */
    1742                 :     int         nMaxBytes;
    1743                 :     char *pachSubfieldData = (char *) 
    1744                 :         poField->GetSubfieldData(poSFDefn, &nMaxBytes,
    1745               0 :                                  iSubfieldIndex);
    1746                 : 
    1747                 : /* -------------------------------------------------------------------- */
    1748                 : /*      Add new instance if we have run out of data.                    */
    1749                 : /* -------------------------------------------------------------------- */
    1750               0 :     if( nMaxBytes == 0 
    1751               0 :         || (nMaxBytes == 1 && pachSubfieldData[0] == DDF_FIELD_TERMINATOR) )
    1752                 :     {
    1753               0 :         CreateDefaultFieldInstance( poField, iSubfieldIndex );
    1754                 : 
    1755                 :         // Refetch.
    1756                 :         pachSubfieldData = (char *) 
    1757                 :             poField->GetSubfieldData(poSFDefn, &nMaxBytes,
    1758               0 :                                      iSubfieldIndex);
    1759                 :     }
    1760                 : 
    1761                 : /* -------------------------------------------------------------------- */
    1762                 : /*      If the new length matches the existing length, just overlay     */
    1763                 : /*      and return.                                                     */
    1764                 : /* -------------------------------------------------------------------- */
    1765                 :     int nExistingLength;
    1766                 : 
    1767               0 :     poSFDefn->GetDataLength( pachSubfieldData, nMaxBytes, &nExistingLength );
    1768                 : 
    1769               0 :     if( nExistingLength == nFormattedLen )
    1770                 :     {
    1771                 :         return poSFDefn->FormatIntValue( pachSubfieldData, nFormattedLen,
    1772               0 :                                          NULL, nNewValue );
    1773                 :     }
    1774                 : 
    1775                 : /* -------------------------------------------------------------------- */
    1776                 : /*      We will need to resize the raw data.                            */
    1777                 : /* -------------------------------------------------------------------- */
    1778                 :     const char *pachFieldInstData;
    1779                 :     int         nInstanceSize, nStartOffset, nSuccess;
    1780                 :     char *pachNewData;
    1781                 : 
    1782                 :     pachFieldInstData = poField->GetInstanceData( iFieldIndex,
    1783               0 :                                                   &nInstanceSize );
    1784                 : 
    1785               0 :     nStartOffset = pachSubfieldData - pachFieldInstData;
    1786                 : 
    1787               0 :     pachNewData = (char *) CPLMalloc(nFormattedLen);
    1788                 :     poSFDefn->FormatIntValue( pachNewData, nFormattedLen, NULL, 
    1789               0 :                               nNewValue );
    1790                 :     
    1791                 :     nSuccess = UpdateFieldRaw( poField, iFieldIndex,
    1792                 :                                nStartOffset, nExistingLength, 
    1793               0 :                                pachNewData, nFormattedLen );
    1794                 : 
    1795               0 :     CPLFree( pachNewData );
    1796                 : 
    1797               0 :     return nSuccess;
    1798                 : }
    1799                 : 
    1800                 : /************************************************************************/
    1801                 : /*                          SetFloatSubfield()                          */
    1802                 : /************************************************************************/
    1803                 : 
    1804                 : /**
    1805                 :  * Set a float subfield in record.
    1806                 :  *
    1807                 :  * The value of a given subfield is replaced with a new float value 
    1808                 :  * formatted appropriately. 
    1809                 :  *
    1810                 :  * @param pszField the field name to operate on.
    1811                 :  * @param iFieldIndex the field index to operate on (zero based).
    1812                 :  * @param pszSubfield the subfield name to operate on. 
    1813                 :  * @param iSubfieldIndex the subfield index to operate on (zero based). 
    1814                 :  * @param dfNewValue the new value to place in the subfield. 
    1815                 :  * 
    1816                 :  * @return TRUE if successful, and FALSE if not. 
    1817                 :  */
    1818                 : 
    1819               0 : int DDFRecord::SetFloatSubfield( const char *pszField, int iFieldIndex, 
    1820                 :                                  const char *pszSubfield, int iSubfieldIndex,
    1821                 :                                  double dfNewValue )
    1822                 : 
    1823                 : {
    1824                 : /* -------------------------------------------------------------------- */
    1825                 : /*      Fetch the field. If this fails, return zero.                    */
    1826                 : /* -------------------------------------------------------------------- */
    1827                 :     DDFField *poField; 
    1828                 : 
    1829               0 :     poField = FindField( pszField, iFieldIndex );
    1830               0 :     if( poField == NULL )
    1831               0 :         return FALSE;
    1832                 : 
    1833                 : /* -------------------------------------------------------------------- */
    1834                 : /*      Get the subfield definition                                     */
    1835                 : /* -------------------------------------------------------------------- */
    1836                 :     DDFSubfieldDefn     *poSFDefn;
    1837                 : 
    1838               0 :     poSFDefn = poField->GetFieldDefn()->FindSubfieldDefn( pszSubfield );
    1839               0 :     if( poSFDefn == NULL )
    1840               0 :         return FALSE;
    1841                 : 
    1842                 : /* -------------------------------------------------------------------- */
    1843                 : /*      How long will the formatted value be?                           */
    1844                 : /* -------------------------------------------------------------------- */
    1845                 :     int nFormattedLen;
    1846                 : 
    1847               0 :     if( !poSFDefn->FormatFloatValue( NULL, 0, &nFormattedLen, dfNewValue ) )
    1848               0 :         return FALSE;
    1849                 : 
    1850                 : /* -------------------------------------------------------------------- */
    1851                 : /*      Get a pointer to the data.                                      */
    1852                 : /* -------------------------------------------------------------------- */
    1853                 :     int         nMaxBytes;
    1854                 :     char *pachSubfieldData = (char *) 
    1855                 :         poField->GetSubfieldData(poSFDefn, &nMaxBytes,
    1856               0 :                                  iSubfieldIndex);
    1857                 : 
    1858                 : /* -------------------------------------------------------------------- */
    1859                 : /*      Add new instance if we have run out of data.                    */
    1860                 : /* -------------------------------------------------------------------- */
    1861               0 :     if( nMaxBytes == 0 
    1862               0 :         || (nMaxBytes == 1 && pachSubfieldData[0] == DDF_FIELD_TERMINATOR) )
    1863                 :     {
    1864               0 :         CreateDefaultFieldInstance( poField, iSubfieldIndex );
    1865                 : 
    1866                 :         // Refetch.
    1867                 :         pachSubfieldData = (char *) 
    1868                 :             poField->GetSubfieldData(poSFDefn, &nMaxBytes,
    1869               0 :                                      iSubfieldIndex);
    1870                 :     }
    1871                 : 
    1872                 : /* -------------------------------------------------------------------- */
    1873                 : /*      If the new length matches the existing length, just overlay     */
    1874                 : /*      and return.                                                     */
    1875                 : /* -------------------------------------------------------------------- */
    1876                 :     int nExistingLength;
    1877                 : 
    1878               0 :     poSFDefn->GetDataLength( pachSubfieldData, nMaxBytes, &nExistingLength );
    1879                 : 
    1880               0 :     if( nExistingLength == nFormattedLen )
    1881                 :     {
    1882                 :         return poSFDefn->FormatFloatValue( pachSubfieldData, nFormattedLen,
    1883               0 :                                          NULL, dfNewValue );
    1884                 :     }
    1885                 : 
    1886                 : /* -------------------------------------------------------------------- */
    1887                 : /*      We will need to resize the raw data.                            */
    1888                 : /* -------------------------------------------------------------------- */
    1889                 :     const char *pachFieldInstData;
    1890                 :     int         nInstanceSize, nStartOffset, nSuccess;
    1891                 :     char *pachNewData;
    1892                 : 
    1893                 :     pachFieldInstData = poField->GetInstanceData( iFieldIndex,
    1894               0 :                                                   &nInstanceSize );
    1895                 : 
    1896               0 :     nStartOffset = (int) (pachSubfieldData - pachFieldInstData);
    1897                 : 
    1898               0 :     pachNewData = (char *) CPLMalloc(nFormattedLen);
    1899                 :     poSFDefn->FormatFloatValue( pachNewData, nFormattedLen, NULL, 
    1900               0 :                               dfNewValue );
    1901                 :     
    1902                 :     nSuccess = UpdateFieldRaw( poField, iFieldIndex,
    1903                 :                                nStartOffset, nExistingLength, 
    1904               0 :                                pachNewData, nFormattedLen );
    1905                 : 
    1906               0 :     CPLFree( pachNewData );
    1907                 : 
    1908               0 :     return nSuccess;
    1909                 : }

Generated by: LCOV version 1.7