LCOV - code coverage report
Current view: directory - frmts/iso8211 - ddfrecord.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 486 195 40.1 %
Date: 2012-04-28 Functions: 26 14 53.8 %

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

Generated by: LCOV version 1.7