LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/mitab - mitab_rawbinblock.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 276 415 66.5 %
Date: 2025-09-10 17:48:50 Functions: 40 45 88.9 %

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

Generated by: LCOV version 1.14