LCOV - code coverage report
Current view: directory - frmts/iso8211 - ddfrecord.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 476 143 30.0 %
Date: 2010-01-09 Functions: 24 11 45.8 %

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

Generated by: LCOV version 1.7