LCOV - code coverage report
Current view: directory - frmts/iso8211 - ddfrecord.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 502 197 39.2 %
Date: 2013-03-30 Functions: 26 14 53.8 %

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

Generated by: LCOV version 1.7