LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/mitab - mitab_rawbinblock.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 329 178 54.1 %
Date: 2012-04-28 Functions: 44 33 75.0 %

       1                 : /**********************************************************************
       2                 :  * $Id: mitab_rawbinblock.cpp,v 1.11 2007-06-11 14:40:03 dmorissette Exp $
       3                 :  *
       4                 :  * Name:     mitab_rawbinblock.cpp
       5                 :  * Project:  MapInfo TAB Read/Write library
       6                 :  * Language: C++
       7                 :  * Purpose:  Implementation of the TABRawBinBlock class used to handle
       8                 :  *           reading/writing blocks in the .MAP files
       9                 :  * Author:   Daniel Morissette, dmorissette@dmsolutions.ca
      10                 :  *
      11                 :  **********************************************************************
      12                 :  * Copyright (c) 1999, 2000, Daniel Morissette
      13                 :  *
      14                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      15                 :  * copy of this software and associated documentation files (the "Software"),
      16                 :  * to deal in the Software without restriction, including without limitation
      17                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      18                 :  * and/or sell copies of the Software, and to permit persons to whom the
      19                 :  * Software is furnished to do so, subject to the following conditions:
      20                 :  * 
      21                 :  * The above copyright notice and this permission notice shall be included
      22                 :  * in all copies or substantial portions of the Software.
      23                 :  * 
      24                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      25                 :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      26                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      27                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      28                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      29                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
      30                 :  * DEALINGS IN THE SOFTWARE.
      31                 :  **********************************************************************
      32                 :  *
      33                 :  * $Log: mitab_rawbinblock.cpp,v $
      34                 :  * Revision 1.11  2007-06-11 14:40:03  dmorissette
      35                 :  * Fixed another issue related to attempting to read past EOF while writing
      36                 :  * collections (bug 1657)
      37                 :  *
      38                 :  * Revision 1.10  2007/02/22 18:35:53  dmorissette
      39                 :  * Fixed problem writing collections where MITAB was sometimes trying to
      40                 :  * read past EOF in write mode (bug 1657).
      41                 :  *
      42                 :  * Revision 1.9  2006/11/28 18:49:08  dmorissette
      43                 :  * Completed changes to split TABMAPObjectBlocks properly and produce an
      44                 :  * optimal spatial index (bug 1585)
      45                 :  *
      46                 :  * Revision 1.8  2005/10/06 19:15:31  dmorissette
      47                 :  * Collections: added support for reading/writing pen/brush/symbol ids and
      48                 :  * for writing collection objects to .TAB/.MAP (bug 1126)
      49                 :  *
      50                 :  * Revision 1.7  2004/12/01 18:25:03  dmorissette
      51                 :  * Fixed potential memory leaks in error conditions (bug 881)
      52                 :  *
      53                 :  * Revision 1.6  2004/06/30 20:29:04  dmorissette
      54                 :  * Fixed refs to old address danmo@videotron.ca
      55                 :  *
      56                 :  * Revision 1.5  2000/02/28 17:06:06  daniel
      57                 :  * Added m_bModified flag
      58                 :  *
      59                 :  * Revision 1.4  2000/01/15 22:30:45  daniel
      60                 :  * Switch to MIT/X-Consortium OpenSource license
      61                 :  *
      62                 :  * Revision 1.3  1999/09/26 14:59:37  daniel
      63                 :  * Implemented write support
      64                 :  *
      65                 :  * Revision 1.2  1999/09/16 02:39:17  daniel
      66                 :  * Completed read support for most feature types
      67                 :  *
      68                 :  * Revision 1.1  1999/07/12 04:18:25  daniel
      69                 :  * Initial checkin
      70                 :  *
      71                 :  **********************************************************************/
      72                 : 
      73                 : #include "mitab.h"
      74                 : 
      75                 : /*=====================================================================
      76                 :  *                      class TABRawBinBlock
      77                 :  *====================================================================*/
      78                 : 
      79                 : 
      80                 : /**********************************************************************
      81                 :  *                   TABRawBinBlock::TABRawBinBlock()
      82                 :  *
      83                 :  * Constructor.
      84                 :  **********************************************************************/
      85             158 : TABRawBinBlock::TABRawBinBlock(TABAccess eAccessMode /*= TABRead*/,
      86             158 :                                GBool bHardBlockSize /*= TRUE*/)
      87                 : {
      88             158 :     m_fp = NULL;
      89             158 :     m_pabyBuf = NULL;
      90             158 :     m_nFirstBlockPtr = 0;
      91             158 :     m_nBlockSize = m_nSizeUsed = m_nFileOffset = m_nCurPos = 0;
      92             158 :     m_bHardBlockSize = bHardBlockSize;
      93                 : 
      94             158 :     m_bModified = FALSE;
      95                 : 
      96             158 :     m_eAccess = eAccessMode; 
      97                 : 
      98             158 : }
      99                 : 
     100                 : /**********************************************************************
     101                 :  *                   TABRawBinBlock::~TABRawBinBlock()
     102                 :  *
     103                 :  * Destructor.
     104                 :  **********************************************************************/
     105             158 : TABRawBinBlock::~TABRawBinBlock()
     106                 : {
     107             158 :     if (m_pabyBuf)
     108             158 :         CPLFree(m_pabyBuf);
     109             158 : }
     110                 : 
     111                 : 
     112                 : /**********************************************************************
     113                 :  *                   TABRawBinBlock::ReadFromFile()
     114                 :  *
     115                 :  * Load data from the specified file location and initialize the block.
     116                 :  *
     117                 :  * Returns 0 if succesful or -1 if an error happened, in which case 
     118                 :  * CPLError() will have been called.
     119                 :  **********************************************************************/
     120             130 : int     TABRawBinBlock::ReadFromFile(FILE *fpSrc, int nOffset, 
     121                 :                                      int nSize /*= 512*/)
     122                 : {
     123                 :     GByte *pabyBuf;
     124                 : 
     125             130 :     if (fpSrc == NULL || nSize == 0)
     126                 :     {
     127                 :         CPLError(CE_Failure, CPLE_AssertionFailed, 
     128               0 :                  "TABRawBinBlock::ReadFromFile(): Assertion Failed!");
     129               0 :         return -1;
     130                 :     }
     131                 : 
     132             130 :     m_fp = fpSrc;
     133             130 :     m_nFileOffset = nOffset;
     134             130 :     m_nCurPos = 0;
     135             130 :     m_bModified = FALSE;
     136                 :     
     137                 :     /*----------------------------------------------------------------
     138                 :      * Alloc a buffer to contain the data
     139                 :      *---------------------------------------------------------------*/
     140             130 :     pabyBuf = (GByte*)CPLMalloc(nSize*sizeof(GByte));
     141                 : 
     142                 :     /*----------------------------------------------------------------
     143                 :      * Read from the file
     144                 :      *---------------------------------------------------------------*/
     145             130 :     if (VSIFSeek(fpSrc, nOffset, SEEK_SET) != 0 ||
     146                 :         (m_nSizeUsed = VSIFRead(pabyBuf, sizeof(GByte), nSize, fpSrc) ) == 0 ||
     147                 :         (m_bHardBlockSize && m_nSizeUsed != nSize ) )
     148                 :     {
     149                 :         CPLError(CE_Failure, CPLE_FileIO,
     150                 :                  "ReadFromFile() failed reading %d bytes at offset %d.",
     151               0 :                  nSize, nOffset);
     152               0 :         CPLFree(pabyBuf);
     153               0 :         return -1;
     154                 :     }
     155                 : 
     156                 :     /*----------------------------------------------------------------
     157                 :      * Init block with the data we just read
     158                 :      *---------------------------------------------------------------*/
     159                 :     return InitBlockFromData(pabyBuf, nSize, m_nSizeUsed, 
     160             130 :                              FALSE, fpSrc, nOffset);
     161                 : }
     162                 : 
     163                 : 
     164                 : /**********************************************************************
     165                 :  *                   TABRawBinBlock::CommitToFile()
     166                 :  *
     167                 :  * Commit the current state of the binary block to the file to which 
     168                 :  * it has been previously attached.
     169                 :  *
     170                 :  * Derived classes may want to (optionally) reimplement this method if
     171                 :  * they need to do special processing before committing the block to disk.
     172                 :  *
     173                 :  * For files created with bHardBlockSize=TRUE, a complete block of
     174                 :  * the specified size is always written, otherwise only the number of
     175                 :  * used bytes in the block will be written to disk.
     176                 :  *
     177                 :  * Returns 0 if succesful or -1 if an error happened, in which case 
     178                 :  * CPLError() will have been called.
     179                 :  **********************************************************************/
     180             120 : int     TABRawBinBlock::CommitToFile()
     181                 : {
     182             120 :     int nStatus = 0;
     183                 : 
     184             120 :     if (m_fp == NULL || m_nBlockSize <= 0 || m_pabyBuf == NULL ||
     185                 :         m_nFileOffset < 0)
     186                 :     {
     187                 :         CPLError(CE_Failure, CPLE_AssertionFailed, 
     188               0 :         "TABRawBinBlock::CommitToFile(): Block has not been initialized yet!");
     189               0 :         return -1;
     190                 :     }
     191                 : 
     192                 :     /*----------------------------------------------------------------
     193                 :      * If block has not been modified, then just return... nothing to do.
     194                 :      *---------------------------------------------------------------*/
     195             120 :     if (!m_bModified)
     196               8 :         return 0;
     197                 : 
     198                 :     /*----------------------------------------------------------------
     199                 :      * Move the output file pointer to the right position... 
     200                 :      *---------------------------------------------------------------*/
     201             112 :     if (VSIFSeek(m_fp, m_nFileOffset, SEEK_SET) != 0)
     202                 :     {
     203                 :         /*------------------------------------------------------------
     204                 :          * Moving pointer failed... we may need to pad with zeros if 
     205                 :          * block destination is beyond current end of file.
     206                 :          *-----------------------------------------------------------*/
     207                 :         int nCurPos;
     208               0 :         nCurPos = VSIFTell(m_fp);
     209                 : 
     210               0 :         if (nCurPos < m_nFileOffset &&
     211                 :             VSIFSeek(m_fp, 0L, SEEK_END) == 0 &&
     212                 :             (nCurPos = VSIFTell(m_fp)) < m_nFileOffset)
     213                 :         {
     214               0 :             GByte cZero = 0;
     215                 : 
     216               0 :             while(nCurPos < m_nFileOffset && nStatus == 0)
     217                 :             {
     218               0 :                 if (VSIFWrite(&cZero, 1, 1, m_fp) != 1)
     219                 :                 {
     220                 :                     CPLError(CE_Failure, CPLE_FileIO,
     221               0 :                              "Failed writing 1 byte at offset %d.", nCurPos);
     222               0 :                     nStatus = -1;
     223               0 :                     break;
     224                 :                 }
     225               0 :                 nCurPos++;
     226                 :             }
     227                 :         }
     228                 :             
     229               0 :         if (nCurPos != m_nFileOffset)
     230               0 :             nStatus = -1; // Error message will follow below
     231                 : 
     232                 :     }
     233                 : 
     234                 :     /*----------------------------------------------------------------
     235                 :      * At this point we are ready to write to the file.
     236                 :      *
     237                 :      * If m_bHardBlockSize==FALSE, then we do not write a complete block;
     238                 :      * we write only the part of the block that was used.
     239                 :      *---------------------------------------------------------------*/
     240             112 :     int numBytesToWrite = m_bHardBlockSize?m_nBlockSize:m_nSizeUsed;
     241                 : 
     242             112 :     if (nStatus != 0 ||
     243                 :         VSIFWrite(m_pabyBuf,sizeof(GByte),
     244                 :                     numBytesToWrite, m_fp) != (size_t)numBytesToWrite )
     245                 :     {
     246                 :         CPLError(CE_Failure, CPLE_FileIO,
     247                 :                  "Failed writing %d bytes at offset %d.",
     248               0 :                  numBytesToWrite, m_nFileOffset);
     249               0 :         return -1;
     250                 :     }
     251                 : 
     252             112 :     fflush(m_fp);
     253                 : 
     254             112 :     m_bModified = FALSE;
     255                 : 
     256             112 :     return 0;
     257                 : }
     258                 : 
     259                 : /**********************************************************************
     260                 :  *                   TABRawBinBlock::CommitAsDeleted()
     261                 :  *
     262                 :  * Commit current block to file using block type 4 (garbage block)
     263                 :  *
     264                 :  * Returns 0 if succesful or -1 if an error happened, in which case 
     265                 :  * CPLError() will have been called.
     266                 :  **********************************************************************/
     267               0 : int     TABRawBinBlock::CommitAsDeleted(GInt32 nNextBlockPtr)
     268                 : {
     269               0 :     int nStatus = 0;
     270                 : 
     271               0 :     CPLErrorReset();
     272                 : 
     273               0 :     if ( m_pabyBuf == NULL )
     274                 :     {
     275                 :         CPLError(CE_Failure, CPLE_AssertionFailed, 
     276               0 :                  "CommitAsDeleted(): Block has not been initialized yet!");
     277               0 :         return -1;
     278                 :     }
     279                 : 
     280                 :     /*-----------------------------------------------------------------
     281                 :      * Create deleted block header
     282                 :      *----------------------------------------------------------------*/
     283               0 :     GotoByteInBlock(0x000);
     284               0 :     WriteInt32(nNextBlockPtr);
     285                 : 
     286               0 :     if( CPLGetLastErrorType() == CE_Failure )
     287               0 :         nStatus = CPLGetLastErrorNo();
     288                 : 
     289                 :     /*-----------------------------------------------------------------
     290                 :      * OK, call the base class to write the block to disk.
     291                 :      *----------------------------------------------------------------*/
     292               0 :     if (nStatus == 0)
     293               0 :         nStatus = TABRawBinBlock::CommitToFile();
     294                 : 
     295               0 :     return nStatus;
     296                 : }
     297                 : 
     298                 : /**********************************************************************
     299                 :  *                   TABRawBinBlock::InitBlockFromData()
     300                 :  *
     301                 :  * Set the binary data buffer and initialize the block.
     302                 :  *
     303                 :  * Calling ReadFromFile() will automatically call InitBlockFromData() to
     304                 :  * complete the initialization of the block after the data is read from the
     305                 :  * file.  Derived classes should implement their own version of 
     306                 :  * InitBlockFromData() if they need specific initialization... in this
     307                 :  * case the derived InitBlockFromData() should call 
     308                 :  * TABRawBinBlock::InitBlockFromData() before doing anything else.
     309                 :  *
     310                 :  * By default, the buffer will be copied, but if bMakeCopy = FALSE then
     311                 :  * it won't be copied, and the object will keep a reference to the
     312                 :  * user's buffer... and this object will eventually free the user's buffer.
     313                 :  *
     314                 :  * Returns 0 if succesful or -1 if an error happened, in which case 
     315                 :  * CPLError() will have been called.
     316                 :  **********************************************************************/
     317             146 : int     TABRawBinBlock::InitBlockFromData(GByte *pabyBuf, 
     318                 :                                           int nBlockSize, int nSizeUsed, 
     319                 :                                           GBool bMakeCopy /* = TRUE */,
     320                 :                                           FILE *fpSrc /* = NULL */, 
     321                 :                                           int nOffset /* = 0 */)
     322                 : {
     323             146 :     m_fp = fpSrc;
     324             146 :     m_nFileOffset = nOffset;
     325             146 :     m_nCurPos = 0;
     326             146 :     m_bModified = FALSE;
     327                 :     
     328                 :     /*----------------------------------------------------------------
     329                 :      * Alloc or realloc the buffer to contain the data if necessary
     330                 :      *---------------------------------------------------------------*/
     331             146 :     if (!bMakeCopy)
     332                 :     {
     333             142 :         if (m_pabyBuf != NULL)
     334              88 :             CPLFree(m_pabyBuf);
     335             142 :         m_pabyBuf = pabyBuf;
     336             142 :         m_nBlockSize = nBlockSize;
     337             142 :         m_nSizeUsed = nSizeUsed;
     338                 :     }
     339               4 :     else if (m_pabyBuf == NULL || nBlockSize != m_nBlockSize)
     340                 :     {
     341               4 :         m_pabyBuf = (GByte*)CPLRealloc(m_pabyBuf, nBlockSize*sizeof(GByte));
     342               4 :         m_nBlockSize = nBlockSize;
     343               4 :         m_nSizeUsed = nSizeUsed;
     344               4 :         memcpy(m_pabyBuf, pabyBuf, m_nSizeUsed);
     345                 :     }
     346                 : 
     347                 :     /*----------------------------------------------------------------
     348                 :      * Extract block type... header block (first block in a file) has
     349                 :      * no block type, so we assign one by default.
     350                 :      *---------------------------------------------------------------*/
     351             146 :     if (m_nFileOffset == 0)
     352              38 :         m_nBlockType = TABMAP_HEADER_BLOCK;
     353                 :     else
     354                 :     {
     355                 :         // Block type will be validated only if GetBlockType() is called
     356             108 :         m_nBlockType = (int)m_pabyBuf[0];
     357                 :     }
     358                 : 
     359             146 :     return 0;
     360                 : }
     361                 : 
     362                 : /**********************************************************************
     363                 :  *                   TABRawBinBlock::InitNewBlock()
     364                 :  *
     365                 :  * Initialize the block so that it knows to which file is is attached,
     366                 :  * its block size, etc.
     367                 :  *
     368                 :  * This is an alternative to calling ReadFromFile() or InitBlockFromData()
     369                 :  * that puts the block in a stable state without loading any initial
     370                 :  * data in it.
     371                 :  *
     372                 :  * Returns 0 if succesful or -1 if an error happened, in which case 
     373                 :  * CPLError() will have been called.
     374                 :  **********************************************************************/
     375             138 : int     TABRawBinBlock::InitNewBlock(FILE *fpSrc, int nBlockSize, 
     376                 :                                      int nFileOffset /* = 0*/)
     377                 : {
     378             138 :     m_fp = fpSrc;
     379             138 :     m_nBlockSize = nBlockSize;
     380             138 :     m_nSizeUsed = 0;
     381             138 :     m_nCurPos = 0;
     382             138 :     m_bModified = FALSE;
     383                 : 
     384             138 :     if (nFileOffset > 0)
     385              64 :         m_nFileOffset = nFileOffset;
     386                 :     else
     387              74 :         m_nFileOffset = 0;
     388                 : 
     389             138 :     m_nBlockType = -1;
     390                 : 
     391             138 :     m_pabyBuf = (GByte*)CPLRealloc(m_pabyBuf, m_nBlockSize*sizeof(GByte));
     392             138 :     memset(m_pabyBuf, 0, m_nBlockSize);
     393                 : 
     394             138 :     return 0;
     395                 : }
     396                 : 
     397                 : 
     398                 : /**********************************************************************
     399                 :  *                   TABRawBinBlock::GetBlockType()
     400                 :  *
     401                 :  * Return the block type for the current object.
     402                 :  *
     403                 :  * Returns a block type >= 0 if succesful or -1 if an error happened, in 
     404                 :  * which case  CPLError() will have been called.
     405                 :  **********************************************************************/
     406               8 : int     TABRawBinBlock::GetBlockType()
     407                 : {
     408               8 :     if (m_pabyBuf == NULL)
     409                 :     {
     410                 :         CPLError(CE_Failure, CPLE_AppDefined,
     411               0 :                  "GetBlockType(): Block has not been initialized.");
     412               0 :         return -1;
     413                 :     }
     414                 : 
     415               8 :     if (m_nBlockType > TABMAP_LAST_VALID_BLOCK_TYPE)
     416                 :     {
     417                 :         CPLError(CE_Failure, CPLE_NotSupported,
     418                 :                  "GetBlockType(): Unsupported block type %d.", 
     419               0 :                  m_nBlockType);
     420               0 :         return -1;
     421                 :     }
     422                 : 
     423               8 :     return m_nBlockType;
     424                 : }
     425                 : 
     426                 : /**********************************************************************
     427                 :  *                   TABRawBinBlock::GotoByteInBlock()
     428                 :  *
     429                 :  * Move the block pointer to the specified position relative to the 
     430                 :  * beginning of the block.
     431                 :  *
     432                 :  * Returns 0 if succesful or -1 if an error happened, in which case 
     433                 :  * CPLError() will have been called.
     434                 :  **********************************************************************/
     435            3660 : int     TABRawBinBlock::GotoByteInBlock(int nOffset)
     436                 : {
     437            3660 :     if ( (m_eAccess == TABRead && nOffset > m_nSizeUsed) ||
     438                 :          (m_eAccess != TABRead && nOffset > m_nBlockSize) )
     439                 :     {
     440                 :         CPLError(CE_Failure, CPLE_AppDefined,
     441               0 :                  "GotoByteInBlock(): Attempt to go past end of data block.");
     442               0 :         return -1;
     443                 :     }
     444                 : 
     445            3660 :     if (nOffset < 0)
     446                 :     {
     447                 :         CPLError(CE_Failure, CPLE_AppDefined,
     448               0 :                "GotoByteInBlock(): Attempt to go before start of data block.");
     449               0 :         return -1;
     450                 :     }
     451                 : 
     452            3660 :     m_nCurPos = nOffset;
     453                 :     
     454            3660 :     m_nSizeUsed = MAX(m_nSizeUsed, m_nCurPos);
     455                 : 
     456            3660 :     return 0;
     457                 : }
     458                 : 
     459                 : /**********************************************************************
     460                 :  *                   TABRawBinBlock::GotoByteRel()
     461                 :  *
     462                 :  * Move the block pointer by the specified number of bytes relative
     463                 :  * to its current position.
     464                 :  *
     465                 :  * Returns 0 if succesful or -1 if an error happened, in which case 
     466                 :  * CPLError() will have been called.
     467                 :  **********************************************************************/
     468              16 : int     TABRawBinBlock::GotoByteRel(int nOffset)
     469                 : {
     470              16 :     return GotoByteInBlock(m_nCurPos + nOffset);
     471                 : }
     472                 : 
     473                 : /**********************************************************************
     474                 :  *                   TABRawBinBlock::GotoByteInFile()
     475                 :  *
     476                 :  * Move the block pointer to the specified position relative to the 
     477                 :  * beginning of the file.  
     478                 :  * 
     479                 :  * In read access, the current block may be reloaded to contain a right
     480                 :  * block of binary data if necessary.
     481                 :  *
     482                 :  * In write mode, the current block may automagically be committed to 
     483                 :  * disk and a new block initialized if necessary.
     484                 :  *
     485                 :  * bForceReadFromFile is used in write mode to read the new block data from
     486                 :  * file instead of creating an empty block. (Useful for TABCollection
     487                 :  * or other cases that need to do random access in the file in write mode.)
     488                 :  *
     489                 :  * bOffsetIsEndOfData is set to TRUE to indicate that the nOffset
     490                 :  * to which we are attempting to go is the end of the used data in this
     491                 :  * block (we are positioninig ourselves to append data), so if the nOffset 
     492                 :  * corresponds to the beginning of a 512 bytes block then we should really 
     493                 :  * be positioning ourselves at the end of the block that ends at this 
     494                 :  * address instead of at the beginning of the blocks that starts at this 
     495                 :  * address. This case can happen when going back and forth to write collection
     496                 :  * objects to a Coordblock and is documented in bug 1657.
     497                 :  *
     498                 :  * Returns 0 if succesful or -1 if an error happened, in which case 
     499                 :  * CPLError() will have been called.
     500                 :  **********************************************************************/
     501             660 : int     TABRawBinBlock::GotoByteInFile(int nOffset, 
     502                 :                                        GBool bForceReadFromFile /*=FALSE*/,
     503                 :                                        GBool bOffsetIsEndOfData /*=FALSE*/)
     504                 : {
     505                 :     int nNewBlockPtr;
     506                 : 
     507             660 :     if (nOffset < 0)
     508                 :     {
     509                 :         CPLError(CE_Failure, CPLE_AppDefined,
     510               0 :                "GotoByteInFile(): Attempt to go before start of file.");
     511               0 :         return -1;
     512                 :     }
     513                 : 
     514                 :     nNewBlockPtr = ( (nOffset-m_nFirstBlockPtr)/m_nBlockSize)*m_nBlockSize +
     515             660 :                      m_nFirstBlockPtr;
     516                 : 
     517             660 :     if (m_eAccess == TABRead)
     518                 :     {
     519             696 :         if ( (nOffset<m_nFileOffset || nOffset>=m_nFileOffset+m_nSizeUsed) &&
     520              88 :              ReadFromFile(m_fp, nNewBlockPtr, m_nBlockSize) != 0)
     521                 :         {
     522                 :             // Failed reading new block... error has already been reported.
     523               0 :             return -1;
     524                 :         }
     525                 :     }
     526              52 :     else if (m_eAccess == TABWrite)
     527                 :     {
     528              24 :         if ( (nOffset<m_nFileOffset || nOffset>=m_nFileOffset+m_nBlockSize) &&
     529               0 :              (CommitToFile() != 0 ||
     530               0 :               InitNewBlock(m_fp, m_nBlockSize, nNewBlockPtr) != 0 ) )
     531                 :         {
     532                 :             // Failed reading new block... error has already been reported.
     533               0 :             return -1;
     534                 :         }
     535                 :     }
     536              28 :     else if (m_eAccess == TABReadWrite)
     537                 :     {
     538                 :         // TODO: THIS IS NOT REAL read/write access (it's more extended write)
     539                 :         // Currently we try to read from file only if explicitly requested.
     540                 :         // If we ever want true read/write mode we should implement
     541                 :         // more smarts to detect whether the caller wants an existing block to
     542                 :         // be read, or a new one to be created from scratch.
     543                 :         // CommitToFile() should only be called only if something changed.
     544                 :         //
     545              28 :         if (bOffsetIsEndOfData &&  nOffset%m_nBlockSize == 0)
     546                 :         {
     547                 :             /* We're trying to go byte 512 of a block that's full of data.
     548                 :              * In this case it's okay to place the m_nCurPos at byte 512
     549                 :              * which is past the end of the block.
     550                 :              */
     551                 : 
     552                 :             /* Make sure we request the block that ends with requested
     553                 :              * address and not the following block that doesn't exist
     554                 :              * yet on disk */
     555               0 :             nNewBlockPtr -= m_nBlockSize;
     556                 : 
     557               0 :             if ( (nOffset < m_nFileOffset || 
     558                 :                   nOffset > m_nFileOffset+m_nBlockSize) &&
     559               0 :                  (CommitToFile() != 0 ||
     560                 :                   (!bForceReadFromFile && 
     561               0 :                    InitNewBlock(m_fp, m_nBlockSize, nNewBlockPtr) != 0) ||
     562                 :                   (bForceReadFromFile &&
     563               0 :                    ReadFromFile(m_fp, nNewBlockPtr, m_nBlockSize) != 0) )  )
     564                 :             {
     565                 :                 // Failed reading new block... error has already been reported.
     566               0 :                 return -1;
     567                 :             }
     568                 :         }
     569                 :         else
     570                 :         {
     571              28 :             if ( (nOffset < m_nFileOffset || 
     572                 :                   nOffset >= m_nFileOffset+m_nBlockSize) &&
     573               0 :                  (CommitToFile() != 0 ||
     574                 :                   (!bForceReadFromFile && 
     575               0 :                    InitNewBlock(m_fp, m_nBlockSize, nNewBlockPtr) != 0) ||
     576                 :                   (bForceReadFromFile &&
     577               0 :                    ReadFromFile(m_fp, nNewBlockPtr, m_nBlockSize) != 0) )  )
     578                 :             {
     579                 :                 // Failed reading new block... error has already been reported.
     580               0 :                 return -1;
     581                 :             }
     582                 :         }
     583                 :     }
     584                 :     else
     585                 :     {
     586                 :         CPLError(CE_Failure, CPLE_NotSupported,
     587               0 :                  "Access mode not supported yet!");
     588               0 :         return -1;
     589                 :     }
     590                 : 
     591             660 :     m_nCurPos = nOffset-m_nFileOffset;
     592                 : 
     593             660 :     m_nSizeUsed = MAX(m_nSizeUsed, m_nCurPos);
     594                 : 
     595             660 :     return 0;
     596                 : }
     597                 : 
     598                 : 
     599                 : /**********************************************************************
     600                 :  *                   TABRawBinBlock::SetFirstBlockPtr()
     601                 :  *
     602                 :  * Set the position in the file at which the first block starts.
     603                 :  * This value will usually be the header size and needs to be specified 
     604                 :  * only if the header size is different from the other blocks size. 
     605                 :  *
     606                 :  * This value will be used by GotoByteInFile() to properly align the data
     607                 :  * blocks that it loads automatically when a requested position is outside
     608                 :  * of the block currently in memory.
     609                 :  **********************************************************************/
     610              12 : void  TABRawBinBlock::SetFirstBlockPtr(int nOffset)
     611                 : {
     612              12 :     m_nFirstBlockPtr = nOffset;
     613              12 : }
     614                 : 
     615                 : 
     616                 : /**********************************************************************
     617                 :  *                   TABRawBinBlock::GetNumUnusedBytes()
     618                 :  *
     619                 :  * Return the number of unused bytes in this block.
     620                 :  **********************************************************************/
     621              54 : int     TABRawBinBlock::GetNumUnusedBytes()
     622                 : {
     623              54 :     return (m_nBlockSize - m_nSizeUsed);
     624                 : }
     625                 : 
     626                 : /**********************************************************************
     627                 :  *                   TABRawBinBlock::GetFirstUnusedByteOffset()
     628                 :  *
     629                 :  * Return the position of the first unused byte in this block relative
     630                 :  * to the beginning of the file, or -1 if the block is full.
     631                 :  **********************************************************************/
     632              24 : int     TABRawBinBlock::GetFirstUnusedByteOffset()
     633                 : {
     634              24 :     if (m_nSizeUsed < m_nBlockSize)
     635              24 :         return m_nFileOffset + m_nSizeUsed;
     636                 :     else
     637               0 :         return -1;
     638                 : }
     639                 : 
     640                 : /**********************************************************************
     641                 :  *                   TABRawBinBlock::GetCurAddress()
     642                 :  *
     643                 :  * Return the current pointer position, relative to beginning of file.
     644                 :  **********************************************************************/
     645              22 : int     TABRawBinBlock::GetCurAddress()
     646                 : {
     647              22 :     return (m_nFileOffset + m_nCurPos);
     648                 : }
     649                 : 
     650                 : /**********************************************************************
     651                 :  *                   TABRawBinBlock::ReadBytes()
     652                 :  *
     653                 :  * Copy the number of bytes from the data block's internal buffer to
     654                 :  * the user's buffer pointed by pabyDstBuf.
     655                 :  *
     656                 :  * Passing pabyDstBuf = NULL will only move the read pointer by the
     657                 :  * specified number of bytes as if the copy had happened... but it 
     658                 :  * won't crash.
     659                 :  *
     660                 :  * Returns 0 if succesful or -1 if an error happened, in which case 
     661                 :  * CPLError() will have been called.
     662                 :  **********************************************************************/
     663            9084 : int     TABRawBinBlock::ReadBytes(int numBytes, GByte *pabyDstBuf)
     664                 : {
     665                 :     /*----------------------------------------------------------------
     666                 :      * Make sure block is initialized with Read access and that the
     667                 :      * operation won't go beyond the buffer's size.
     668                 :      *---------------------------------------------------------------*/
     669            9084 :     if (m_pabyBuf == NULL)
     670                 :     {
     671                 :         CPLError(CE_Failure, CPLE_AppDefined,
     672               0 :                  "ReadBytes(): Block has not been initialized.");
     673               0 :         return -1;
     674                 :     }
     675                 : 
     676            9084 :     if (m_eAccess != TABRead && m_eAccess != TABReadWrite )
     677                 :     {
     678                 :         CPLError(CE_Failure, CPLE_AppDefined,
     679               0 :                  "ReadBytes(): Block does not support read operations.");
     680               0 :         return -1;
     681                 :     }
     682                 : 
     683            9084 :     if (m_nCurPos + numBytes > m_nSizeUsed)
     684                 :     {
     685                 :         CPLError(CE_Failure, CPLE_AppDefined,
     686               0 :                  "ReadBytes(): Attempt to read past end of data block.");
     687               0 :         return -1;
     688                 :     }
     689                 : 
     690            9084 :     if (pabyDstBuf)
     691                 :     {
     692            9084 :         memcpy(pabyDstBuf, m_pabyBuf + m_nCurPos, numBytes);
     693                 :     }
     694                 : 
     695            9084 :     m_nCurPos += numBytes;
     696                 : 
     697            9084 :     return 0;
     698                 : }
     699                 : 
     700                 : /**********************************************************************
     701                 :  *                   TABRawBinBlock::Read<datatype>()
     702                 :  *
     703                 :  * MapInfo files are binary files with LSB first (Intel) byte 
     704                 :  * ordering.  The following functions will read from the input file
     705                 :  * and return a value with the bytes ordered properly for the current 
     706                 :  * platform.
     707                 :  **********************************************************************/
     708             948 : GByte  TABRawBinBlock::ReadByte()
     709                 : {
     710                 :     GByte byValue;
     711                 : 
     712             948 :     ReadBytes(1, (GByte*)(&byValue));
     713                 : 
     714             948 :     return byValue;
     715                 : }
     716                 : 
     717            5060 : GInt16  TABRawBinBlock::ReadInt16()
     718                 : {
     719                 :     GInt16 n16Value;
     720                 : 
     721            5060 :     ReadBytes(2, (GByte*)(&n16Value));
     722                 : 
     723                 : #ifdef CPL_MSB
     724                 :     return (GInt16)CPL_SWAP16(n16Value);
     725                 : #else
     726            5060 :     return n16Value;
     727                 : #endif
     728                 : }
     729                 : 
     730            2626 : GInt32  TABRawBinBlock::ReadInt32()
     731                 : {
     732                 :     GInt32 n32Value;
     733                 : 
     734            2626 :     ReadBytes(4, (GByte*)(&n32Value));
     735                 : 
     736                 : #ifdef CPL_MSB
     737                 :     return (GInt32)CPL_SWAP32(n32Value);
     738                 : #else
     739            2626 :     return n32Value;
     740                 : #endif
     741                 : }
     742                 : 
     743               0 : float   TABRawBinBlock::ReadFloat()
     744                 : {
     745                 :     float fValue;
     746                 : 
     747               0 :     ReadBytes(4, (GByte*)(&fValue));
     748                 : 
     749                 : #ifdef CPL_MSB
     750                 :     *(GUInt32*)(&fValue) = CPL_SWAP32(*(GUInt32*)(&fValue));
     751                 : #endif
     752               0 :     return fValue;
     753                 : }
     754                 : 
     755             328 : double  TABRawBinBlock::ReadDouble()
     756                 : {
     757                 :     double dValue;
     758                 : 
     759             328 :     ReadBytes(8, (GByte*)(&dValue));
     760                 : 
     761                 : #ifdef CPL_MSB
     762                 :     CPL_SWAPDOUBLE(&dValue);
     763                 : #endif
     764                 : 
     765             328 :     return dValue;
     766                 : }
     767                 : 
     768                 : 
     769                 : 
     770                 : /**********************************************************************
     771                 :  *                   TABRawBinBlock::WriteBytes()
     772                 :  *
     773                 :  * Copy the number of bytes from the user's buffer pointed by pabySrcBuf
     774                 :  * to the data block's internal buffer.
     775                 :  * Note that this call only writes to the memory buffer... nothing is
     776                 :  * written to the file until WriteToFile() is called.
     777                 :  *
     778                 :  * Passing pabySrcBuf = NULL will only move the write pointer by the
     779                 :  * specified number of bytes as if the copy had happened... but it 
     780                 :  * won't crash.
     781                 :  *
     782                 :  * Returns 0 if succesful or -1 if an error happened, in which case 
     783                 :  * CPLError() will have been called.
     784                 :  **********************************************************************/
     785            4358 : int  TABRawBinBlock::WriteBytes(int nBytesToWrite, GByte *pabySrcBuf)
     786                 : {
     787                 :     /*----------------------------------------------------------------
     788                 :      * Make sure block is initialized with Write access and that the
     789                 :      * operation won't go beyond the buffer's size.
     790                 :      *---------------------------------------------------------------*/
     791            4358 :     if (m_pabyBuf == NULL)
     792                 :     {
     793                 :         CPLError(CE_Failure, CPLE_AppDefined,
     794               0 :                  "WriteBytes(): Block has not been initialized.");
     795               0 :         return -1;
     796                 :     }
     797                 : 
     798            4358 :     if (m_eAccess != TABWrite && m_eAccess != TABReadWrite )
     799                 :     {
     800                 :         CPLError(CE_Failure, CPLE_AppDefined,
     801               0 :                  "WriteBytes(): Block does not support write operations.");
     802               0 :         return -1;
     803                 :     }
     804                 : 
     805            4358 :     if (m_nCurPos + nBytesToWrite > m_nBlockSize)
     806                 :     {
     807                 :         CPLError(CE_Failure, CPLE_AppDefined,
     808               0 :                  "WriteBytes(): Attempt to write past end of data block.");
     809               0 :         return -1;
     810                 :     }
     811                 : 
     812                 :     /*----------------------------------------------------------------
     813                 :      * Everything is OK... copy the data
     814                 :      *---------------------------------------------------------------*/
     815            4358 :     if (pabySrcBuf)
     816                 :     {
     817            4358 :         memcpy(m_pabyBuf + m_nCurPos, pabySrcBuf, nBytesToWrite);
     818                 :     }
     819                 : 
     820            4358 :     m_nCurPos += nBytesToWrite;
     821                 : 
     822            4358 :     m_nSizeUsed = MAX(m_nSizeUsed, m_nCurPos);
     823                 : 
     824            4358 :     m_bModified = TRUE;
     825                 : 
     826            4358 :     return 0;
     827                 : }
     828                 : 
     829                 : 
     830                 : /**********************************************************************
     831                 :  *                    TABRawBinBlock::Write<datatype>()
     832                 :  *
     833                 :  * Arc/Info files are binary files with MSB first (Motorola) byte 
     834                 :  * ordering.  The following functions will reorder the byte for the
     835                 :  * value properly and write that to the output file.
     836                 :  *
     837                 :  * If a problem happens, then CPLError() will be called and 
     838                 :  * CPLGetLastErrNo() can be used to test if a write operation was 
     839                 :  * succesful.
     840                 :  **********************************************************************/
     841             444 : int  TABRawBinBlock::WriteByte(GByte byValue)
     842                 : {
     843             444 :     return WriteBytes(1, (GByte*)&byValue);
     844                 : }
     845                 : 
     846            1318 : int  TABRawBinBlock::WriteInt16(GInt16 n16Value)
     847                 : {
     848                 : #ifdef CPL_MSB
     849                 :     n16Value = (GInt16)CPL_SWAP16(n16Value);
     850                 : #endif
     851                 : 
     852            1318 :     return WriteBytes(2, (GByte*)&n16Value);
     853                 : }
     854                 : 
     855            1148 : int  TABRawBinBlock::WriteInt32(GInt32 n32Value)
     856                 : {
     857                 : #ifdef CPL_MSB
     858                 :     n32Value = (GInt32)CPL_SWAP32(n32Value);
     859                 : #endif
     860                 : 
     861            1148 :     return WriteBytes(4, (GByte*)&n32Value);
     862                 : }
     863                 : 
     864               0 : int  TABRawBinBlock::WriteFloat(float fValue)
     865                 : {
     866                 : #ifdef CPL_MSB
     867                 :     *(GUInt32*)(&fValue) = CPL_SWAP32(*(GUInt32*)(&fValue));
     868                 : #endif
     869                 : 
     870               0 :     return WriteBytes(4, (GByte*)&fValue);
     871                 : }
     872                 : 
     873             136 : int  TABRawBinBlock::WriteDouble(double dValue)
     874                 : {
     875                 : #ifdef CPL_MSB
     876                 :     CPL_SWAPDOUBLE(&dValue);
     877                 : #endif
     878                 : 
     879             136 :     return WriteBytes(8, (GByte*)&dValue);
     880                 : }
     881                 : 
     882                 : 
     883                 : /**********************************************************************
     884                 :  *                    TABRawBinBlock::WriteZeros()
     885                 :  *
     886                 :  * Write a number of zeros (sepcified in bytes) at the current position 
     887                 :  * in the file.
     888                 :  *
     889                 :  * If a problem happens, then CPLError() will be called and 
     890                 :  * CPLGetLastErrNo() can be used to test if a write operation was 
     891                 :  * succesful.
     892                 :  **********************************************************************/
     893             136 : int  TABRawBinBlock::WriteZeros(int nBytesToWrite)
     894                 : {
     895             136 :     char acZeros[8] = {0, 0, 0, 0, 0, 0, 0, 0};
     896                 :     int i;
     897             136 :     int nStatus = 0;
     898                 : 
     899                 :     /* Write by 8 bytes chunks.  The last chunk may be less than 8 bytes 
     900                 :      */
     901            1198 :     for(i=0; nStatus == 0 && i< nBytesToWrite; i+=8)
     902                 :     {
     903            1062 :         nStatus = WriteBytes(MIN(8,(nBytesToWrite-i)), (GByte*)acZeros);
     904                 :     }
     905                 : 
     906             136 :     return nStatus;
     907                 : }
     908                 : 
     909                 : /**********************************************************************
     910                 :  *                   TABRawBinBlock::WritePaddedString()
     911                 :  *
     912                 :  * Write a string and pad the end of the field (up to nFieldSize) with
     913                 :  * spaces number of spaces at the current position in the file.
     914                 :  *
     915                 :  * If a problem happens, then CPLError() will be called and 
     916                 :  * CPLGetLastErrNo() can be used to test if a write operation was 
     917                 :  * succesful.
     918                 :  **********************************************************************/
     919               0 : int  TABRawBinBlock::WritePaddedString(int nFieldSize, const char *pszString)
     920                 : {
     921               0 :     char acSpaces[8] = {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '};
     922                 :     int i, nLen, numSpaces;
     923               0 :     int nStatus = 0;
     924                 : 
     925               0 :     nLen = strlen(pszString);
     926               0 :     nLen = MIN(nLen, nFieldSize);
     927               0 :     numSpaces = nFieldSize - nLen;
     928                 : 
     929               0 :     if (nLen > 0)
     930               0 :         nStatus = WriteBytes(nLen, (GByte*)pszString);
     931                 : 
     932                 :     /* Write spaces by 8 bytes chunks.  The last chunk may be less than 8 bytes
     933                 :      */
     934               0 :     for(i=0; nStatus == 0 && i< numSpaces; i+=8)
     935                 :     {
     936               0 :         nStatus = WriteBytes(MIN(8,(numSpaces-i)), (GByte*)acSpaces);
     937                 :     }
     938                 : 
     939               0 :     return nStatus;
     940                 : }
     941                 : 
     942                 : /**********************************************************************
     943                 :  *                   TABRawBinBlock::Dump()
     944                 :  *
     945                 :  * Dump block contents... available only in DEBUG mode.
     946                 :  **********************************************************************/
     947                 : #ifdef DEBUG
     948                 : 
     949               0 : void TABRawBinBlock::Dump(FILE *fpOut /*=NULL*/)
     950                 : {
     951               0 :     if (fpOut == NULL)
     952               0 :         fpOut = stdout;
     953                 : 
     954               0 :     fprintf(fpOut, "----- TABRawBinBlock::Dump() -----\n");
     955               0 :     if (m_pabyBuf == NULL)
     956                 :     {
     957               0 :         fprintf(fpOut, "Block has not been initialized yet.");
     958                 :     }
     959                 :     else
     960                 :     {
     961                 :         fprintf(fpOut, "Block (type %d) size=%d bytes at offset %d in file.\n",
     962               0 :                 m_nBlockType, m_nBlockSize, m_nFileOffset);
     963               0 :         fprintf(fpOut, "Current pointer at byte %d\n", m_nCurPos);
     964                 :     }
     965                 : 
     966               0 :     fflush(fpOut);
     967               0 : }
     968                 : 
     969                 : #endif // DEBUG
     970                 : 
     971                 : 
     972                 : /**********************************************************************
     973                 :  *                          DumpBytes()
     974                 :  *
     975                 :  * Read and dump the contents of an Binary file.
     976                 :  **********************************************************************/
     977               0 : void TABRawBinBlock::DumpBytes(GInt32 nValue, int nOffset /*=0*/,
     978                 :                                FILE *fpOut /*=NULL*/)
     979                 : {
     980                 :     GInt32      anVal[2];
     981                 :     GInt16      *pn16Val1, *pn16Val2;
     982                 :     float       *pfValue;
     983                 :     char        *pcValue;
     984                 :     double      *pdValue;
     985                 : 
     986                 : 
     987               0 :     pfValue = (float*)(&nValue);
     988               0 :     pcValue = (char*)(&nValue);
     989               0 :     pdValue = (double*)anVal;
     990                 : 
     991               0 :     pn16Val1 = (GInt16*)(pcValue+2);
     992               0 :     pn16Val2 = (GInt16*)(pcValue);
     993                 : 
     994               0 :     anVal[0] = anVal[1] = 0;
     995                 : 
     996                 :     /* For double precision values, we only use the first half 
     997                 :      * of the height bytes... and leave the other 4 bytes as zeros!
     998                 :      * It's a bit of a hack, but it seems to be enough for the 
     999                 :      * precision of the values we print!
    1000                 :      */
    1001                 : #ifdef CPL_MSB
    1002                 :     anVal[0] = nValue;
    1003                 : #else
    1004               0 :     anVal[1] = nValue;
    1005                 : #endif
    1006                 : 
    1007               0 :     if (fpOut == NULL)
    1008               0 :         fpOut = stdout;
    1009                 : 
    1010                 :     fprintf(fpOut, "%d\t0x%8.8x  %-5d\t%-6d %-6d %5.3e  d=%5.3e",
    1011                 :                     nOffset, nValue, nValue,
    1012               0 :                     *pn16Val1, *pn16Val2, *pfValue, *pdValue);
    1013                 : 
    1014               0 :     printf("\t[%c%c%c%c]\n", isprint(pcValue[0])?pcValue[0]:'.',
    1015               0 :                              isprint(pcValue[1])?pcValue[1]:'.',
    1016               0 :                              isprint(pcValue[2])?pcValue[2]:'.',
    1017               0 :                              isprint(pcValue[3])?pcValue[3]:'.');
    1018               0 : }
    1019                 : 
    1020                 : 
    1021                 : 
    1022                 : /**********************************************************************
    1023                 :  *                   TABCreateMAPBlockFromFile()
    1024                 :  *
    1025                 :  * Load data from the specified file location and create and initialize 
    1026                 :  * a TABMAP*Block of the right type to handle it.
    1027                 :  *
    1028                 :  * Returns the new object if succesful or NULL if an error happened, in 
    1029                 :  * which case CPLError() will have been called.
    1030                 :  **********************************************************************/
    1031              12 : TABRawBinBlock *TABCreateMAPBlockFromFile(FILE *fpSrc, int nOffset, 
    1032                 :                                           int nSize /*= 512*/, 
    1033                 :                                           GBool bHardBlockSize /*= TRUE */,
    1034                 :                                           TABAccess eAccessMode /*= TABRead*/)
    1035                 : {
    1036              12 :     TABRawBinBlock *poBlock = NULL;
    1037                 :     GByte *pabyBuf;
    1038                 : 
    1039              12 :     if (fpSrc == NULL || nSize == 0)
    1040                 :     {
    1041                 :         CPLError(CE_Failure, CPLE_AssertionFailed, 
    1042               0 :                  "TABCreateMAPBlockFromFile(): Assertion Failed!");
    1043               0 :         return NULL;
    1044                 :     }
    1045                 : 
    1046                 :     /*----------------------------------------------------------------
    1047                 :      * Alloc a buffer to contain the data
    1048                 :      *---------------------------------------------------------------*/
    1049              12 :     pabyBuf = (GByte*)CPLMalloc(nSize*sizeof(GByte));
    1050                 : 
    1051                 :     /*----------------------------------------------------------------
    1052                 :      * Read from the file
    1053                 :      *---------------------------------------------------------------*/
    1054              12 :     if (VSIFSeek(fpSrc, nOffset, SEEK_SET) != 0 ||
    1055                 :         VSIFRead(pabyBuf, sizeof(GByte), nSize, fpSrc)!=(unsigned int)nSize )
    1056                 :     {
    1057                 :         CPLError(CE_Failure, CPLE_FileIO,
    1058                 :          "TABCreateMAPBlockFromFile() failed reading %d bytes at offset %d.",
    1059               0 :                  nSize, nOffset);
    1060               0 :         CPLFree(pabyBuf);
    1061               0 :         return NULL;
    1062                 :     }
    1063                 : 
    1064                 :     /*----------------------------------------------------------------
    1065                 :      * Create an object of the right type
    1066                 :      * Header block is different: it does not start with the object 
    1067                 :      * type byte but it is always the first block in a file
    1068                 :      *---------------------------------------------------------------*/
    1069              12 :     if (nOffset == 0)
    1070                 :     {
    1071              12 :         poBlock = new TABMAPHeaderBlock;
    1072                 :     }
    1073                 :     else
    1074                 :     {
    1075               0 :         switch(pabyBuf[0])
    1076                 :         {
    1077                 :           case TABMAP_INDEX_BLOCK:
    1078               0 :             poBlock = new TABMAPIndexBlock(eAccessMode);
    1079               0 :             break;
    1080                 :           case TABMAP_OBJECT_BLOCK:
    1081               0 :             poBlock = new TABMAPObjectBlock(eAccessMode);
    1082               0 :             break;
    1083                 :           case TABMAP_COORD_BLOCK:
    1084               0 :             poBlock = new TABMAPCoordBlock(eAccessMode);
    1085               0 :             break;
    1086                 :           case TABMAP_TOOL_BLOCK:
    1087               0 :             poBlock = new TABMAPToolBlock(eAccessMode);
    1088               0 :             break;
    1089                 :           case TABMAP_GARB_BLOCK:
    1090                 :           default:
    1091               0 :             poBlock = new TABRawBinBlock(eAccessMode, bHardBlockSize);
    1092                 :             break;
    1093                 :         }
    1094                 :     }
    1095                 : 
    1096                 :     /*----------------------------------------------------------------
    1097                 :      * Init new object with the data we just read
    1098                 :      *---------------------------------------------------------------*/
    1099              12 :     if (poBlock->InitBlockFromData(pabyBuf, nSize, nSize, 
    1100              12 :                                    FALSE, fpSrc, nOffset) != 0)
    1101                 :     {
    1102                 :         // Some error happened... and CPLError() has been called
    1103               0 :         delete poBlock;
    1104               0 :         poBlock = NULL;
    1105                 :     }
    1106                 : 
    1107              12 :     return poBlock;
    1108                 : }
    1109                 : 
    1110                 : /*=====================================================================
    1111                 :  *                      class TABBinBlockManager
    1112                 :  *====================================================================*/
    1113                 : 
    1114                 : 
    1115                 : /**********************************************************************
    1116                 :  *                   TABBinBlockManager::TABBinBlockManager()
    1117                 :  *
    1118                 :  * Constructor.
    1119                 :  **********************************************************************/
    1120              26 : TABBinBlockManager::TABBinBlockManager(int nBlockSize /*=512*/)
    1121                 : {
    1122                 : 
    1123              26 :     m_nBlockSize=nBlockSize;
    1124              26 :     m_nLastAllocatedBlock = -1;
    1125              26 :     m_psGarbageBlocks = NULL;
    1126              26 : }
    1127                 : 
    1128                 : /**********************************************************************
    1129                 :  *                   TABBinBlockManager::~TABBinBlockManager()
    1130                 :  *
    1131                 :  * Destructor.
    1132                 :  **********************************************************************/
    1133              26 : TABBinBlockManager::~TABBinBlockManager()
    1134                 : {
    1135              26 :     Reset();
    1136              26 : }
    1137                 : 
    1138                 : /**********************************************************************
    1139                 :  *                   TABBinBlockManager::AllocNewBlock()
    1140                 :  *
    1141                 :  * Returns and reserves the address of the next available block, either a 
    1142                 :  * brand new block at end of file, or recycle a garbage block if one is 
    1143                 :  * available.
    1144                 :  **********************************************************************/
    1145              70 : GInt32  TABBinBlockManager::AllocNewBlock()
    1146                 : {
    1147                 :     // Try to reuse garbage blocks first
    1148              70 :     if (GetFirstGarbageBlock() > 0)
    1149               0 :         return PopGarbageBlock();
    1150                 : 
    1151                 :     // ... or alloc a new block at EOF
    1152              70 :     if (m_nLastAllocatedBlock==-1)
    1153              28 :         m_nLastAllocatedBlock = 0;
    1154                 :     else
    1155              42 :         m_nLastAllocatedBlock+=m_nBlockSize;
    1156                 : 
    1157              70 :     return m_nLastAllocatedBlock;
    1158                 : }
    1159                 : 
    1160                 : /**********************************************************************
    1161                 :  *                   TABBinBlockManager::Reset()
    1162                 :  *
    1163                 :  **********************************************************************/
    1164              60 : void TABBinBlockManager::Reset()
    1165                 : {
    1166              60 :     m_nLastAllocatedBlock = -1;
    1167                 : 
    1168                 :     // Flush list of garbage blocks
    1169             120 :     while (m_psGarbageBlocks != NULL)
    1170                 :     {
    1171               0 :         TABBlockRef *psNext = m_psGarbageBlocks->psNext;
    1172               0 :         CPLFree(m_psGarbageBlocks);
    1173               0 :         m_psGarbageBlocks = psNext;
    1174                 :     }
    1175              60 : }
    1176                 : 
    1177                 : /**********************************************************************
    1178                 :  *                   TABBinBlockManager::PushGarbageBlock()
    1179                 :  *
    1180                 :  * Insert a garbage block at the head of the list of garbage blocks.
    1181                 :  **********************************************************************/
    1182               0 : void TABBinBlockManager::PushGarbageBlock(GInt32 nBlockPtr)
    1183                 : {
    1184               0 :     TABBlockRef *psNewBlockRef = (TABBlockRef *)CPLMalloc(sizeof(TABBlockRef));
    1185                 : 
    1186               0 :     if (psNewBlockRef)
    1187                 :     {
    1188               0 :         psNewBlockRef->nBlockPtr = nBlockPtr;
    1189               0 :         psNewBlockRef->psNext = m_psGarbageBlocks;
    1190               0 :         m_psGarbageBlocks = psNewBlockRef;
    1191                 :     }
    1192               0 : }
    1193                 : 
    1194                 : /**********************************************************************
    1195                 :  *                   TABBinBlockManager::GetFirstGarbageBlock()
    1196                 :  *
    1197                 :  * Return address of the block at the head of the list of garbage blocks
    1198                 :  * or 0 if the list is empty.
    1199                 :  **********************************************************************/
    1200              76 : GInt32 TABBinBlockManager::GetFirstGarbageBlock()
    1201                 : {
    1202              76 :     if (m_psGarbageBlocks)
    1203               0 :         return m_psGarbageBlocks->nBlockPtr;
    1204                 : 
    1205              76 :     return 0;
    1206                 : }
    1207                 : 
    1208                 : /**********************************************************************
    1209                 :  *                   TABBinBlockManager::PopGarbageBlock()
    1210                 :  *
    1211                 :  * Return address of the block at the head of the list of garbage blocks
    1212                 :  * and remove that block from the list.
    1213                 :  * Retuns 0 if the list is empty.
    1214                 :  **********************************************************************/
    1215               0 : GInt32 TABBinBlockManager::PopGarbageBlock()
    1216                 : {
    1217               0 :     GInt32 nBlockPtr = 0;
    1218                 : 
    1219               0 :     if (m_psGarbageBlocks)
    1220                 :     {
    1221               0 :         nBlockPtr = m_psGarbageBlocks->nBlockPtr;
    1222               0 :         TABBlockRef *psNext = m_psGarbageBlocks->psNext;
    1223               0 :         CPLFree(m_psGarbageBlocks);
    1224               0 :         m_psGarbageBlocks = psNext;
    1225                 :     }
    1226                 : 
    1227               0 :     return nBlockPtr;
    1228                 : }
    1229                 : 

Generated by: LCOV version 1.7