LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/mitab - mitab_mapobjectblock.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 580 817 71.0 %
Date: 2024-11-21 22:18:42 Functions: 41 46 89.1 %

          Line data    Source code
       1             : /**********************************************************************
       2             :  *
       3             :  * Name:     mitab_mapobjectblock.cpp
       4             :  * Project:  MapInfo TAB Read/Write library
       5             :  * Language: C++
       6             :  * Purpose:  Implementation of the TABMAPObjectBlock class used to handle
       7             :  *           reading/writing of the .MAP files' object data blocks
       8             :  * Author:   Daniel Morissette, dmorissette@dmsolutions.ca
       9             :  *
      10             :  **********************************************************************
      11             :  * Copyright (c) 1999-2001, 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 <algorithm>
      21             : #include <limits.h>
      22             : #include <stddef.h>
      23             : 
      24             : #include "cpl_conv.h"
      25             : #include "cpl_error.h"
      26             : #include "cpl_vsi.h"
      27             : #include "mitab_priv.h"
      28             : #include "mitab_utils.h"
      29             : 
      30             : /*=====================================================================
      31             :  *                      class TABMAPObjectBlock
      32             :  *====================================================================*/
      33             : 
      34             : constexpr int MAP_OBJECT_HEADER_SIZE = 20;
      35             : 
      36             : /**********************************************************************
      37             :  *                   TABMAPObjectBlock::TABMAPObjectBlock()
      38             :  *
      39             :  * Constructor.
      40             :  **********************************************************************/
      41       39519 : TABMAPObjectBlock::TABMAPObjectBlock(TABAccess eAccessMode /*= TABRead*/)
      42             :     : TABRawBinBlock(eAccessMode, TRUE), m_numDataBytes(0),
      43             :       m_nFirstCoordBlock(0), m_nLastCoordBlock(0), m_nCenterX(0), m_nCenterY(0),
      44             :       m_nMinX(0), m_nMinY(0), m_nMaxX(0), m_nMaxY(0), m_nCurObjectOffset(0),
      45       39519 :       m_nCurObjectId(0), m_nCurObjectType(TAB_GEOM_UNSET), m_bLockCenter(FALSE)
      46             : {
      47       39519 : }
      48             : 
      49             : /**********************************************************************
      50             :  *                   TABMAPObjectBlock::~TABMAPObjectBlock()
      51             :  *
      52             :  * Destructor.
      53             :  **********************************************************************/
      54      118557 : TABMAPObjectBlock::~TABMAPObjectBlock()
      55             : {
      56             :     // TODO(schwehr): Why set these?  Should remove.
      57       39519 :     m_nMinX = 1000000000;
      58       39519 :     m_nMinY = 1000000000;
      59       39519 :     m_nMaxX = -1000000000;
      60       39519 :     m_nMaxY = -1000000000;
      61       79038 : }
      62             : 
      63             : /**********************************************************************
      64             :  *                   TABMAPObjectBlock::InitBlockFromData()
      65             :  *
      66             :  * Perform some initialization on the block after its binary data has
      67             :  * been set or changed (or loaded from a file).
      68             :  *
      69             :  * Returns 0 if successful or -1 if an error happened, in which case
      70             :  * CPLError() will have been called.
      71             :  **********************************************************************/
      72       47657 : int TABMAPObjectBlock::InitBlockFromData(GByte *pabyBuf, int nBlockSize,
      73             :                                          int nSizeUsed,
      74             :                                          GBool bMakeCopy /* = TRUE */,
      75             :                                          VSILFILE *fpSrc /* = NULL */,
      76             :                                          int nOffset /* = 0 */)
      77             : {
      78             :     /*-----------------------------------------------------------------
      79             :      * First of all, we must call the base class' InitBlockFromData()
      80             :      *----------------------------------------------------------------*/
      81       47657 :     const int nStatus = TABRawBinBlock::InitBlockFromData(
      82             :         pabyBuf, nBlockSize, nSizeUsed, bMakeCopy, fpSrc, nOffset);
      83       47657 :     if (nStatus != 0)
      84           0 :         return nStatus;
      85             : 
      86             :     /*-----------------------------------------------------------------
      87             :      * Validate block type
      88             :      *----------------------------------------------------------------*/
      89       47657 :     if (m_nBlockType != TABMAP_OBJECT_BLOCK)
      90             :     {
      91           0 :         CPLError(CE_Failure, CPLE_FileIO,
      92             :                  "InitBlockFromData(): Invalid Block Type: got %d expected %d",
      93             :                  m_nBlockType, TABMAP_OBJECT_BLOCK);
      94           0 :         CPLFree(m_pabyBuf);
      95           0 :         m_pabyBuf = nullptr;
      96           0 :         return -1;
      97             :     }
      98             : 
      99             :     /*-----------------------------------------------------------------
     100             :      * Init member variables
     101             :      *----------------------------------------------------------------*/
     102       47657 :     GotoByteInBlock(0x002);
     103       47657 :     m_numDataBytes = ReadInt16(); /* Excluding 4 bytes header */
     104       47657 :     if (m_numDataBytes < 0 ||
     105       47657 :         m_numDataBytes + MAP_OBJECT_HEADER_SIZE > nBlockSize)
     106             :     {
     107           0 :         CPLError(CE_Failure, CPLE_FileIO,
     108             :                  "TABMAPObjectBlock::InitBlockFromData(): m_numDataBytes=%d "
     109             :                  "incompatible with block size %d",
     110             :                  m_numDataBytes, nBlockSize);
     111           0 :         CPLFree(m_pabyBuf);
     112           0 :         m_pabyBuf = nullptr;
     113           0 :         return -1;
     114             :     }
     115             : 
     116       47657 :     m_nCenterX = ReadInt32();
     117       47657 :     m_nCenterY = ReadInt32();
     118             : 
     119       47657 :     m_nFirstCoordBlock = ReadInt32();
     120       47657 :     m_nLastCoordBlock = ReadInt32();
     121             : 
     122       47657 :     m_nCurObjectOffset = -1;
     123       47657 :     m_nCurObjectId = -1;
     124       47657 :     m_nCurObjectType = TAB_GEOM_UNSET;
     125             : 
     126       47657 :     m_nMinX = 1000000000;
     127       47657 :     m_nMinY = 1000000000;
     128       47657 :     m_nMaxX = -1000000000;
     129       47657 :     m_nMaxY = -1000000000;
     130       47657 :     m_bLockCenter = FALSE;
     131             : 
     132             :     /*-----------------------------------------------------------------
     133             :      * Set real value for m_nSizeUsed to allow random update
     134             :      * (By default TABRawBinBlock thinks all bytes are used)
     135             :      *----------------------------------------------------------------*/
     136       47657 :     m_nSizeUsed = m_numDataBytes + MAP_OBJECT_HEADER_SIZE;
     137             : 
     138       47657 :     return 0;
     139             : }
     140             : 
     141             : /************************************************************************
     142             :  *                       ClearObjects()
     143             :  *
     144             :  * Cleans existing objects from the block. This method is used when
     145             :  * compacting a page that has deleted records.
     146             :  ************************************************************************/
     147         272 : void TABMAPObjectBlock::ClearObjects()
     148             : {
     149         272 :     GotoByteInBlock(MAP_OBJECT_HEADER_SIZE);
     150         272 :     WriteZeros(m_nBlockSize - MAP_OBJECT_HEADER_SIZE);
     151         272 :     GotoByteInBlock(MAP_OBJECT_HEADER_SIZE);
     152         272 :     m_nSizeUsed = MAP_OBJECT_HEADER_SIZE;
     153         272 :     m_bModified = TRUE;
     154         272 : }
     155             : 
     156             : /************************************************************************
     157             :  *                         LockCenter()
     158             :  *
     159             :  * Prevents the m_nCenterX and m_nCenterY to be adjusted by other methods.
     160             :  * Useful when editing pages that have compressed geometries.
     161             :  * This is a bit band-aid. Proper support of compressed geometries should
     162             :  * handle center moves.
     163             :  ************************************************************************/
     164       11815 : void TABMAPObjectBlock::LockCenter()
     165             : {
     166       11815 :     m_bLockCenter = TRUE;
     167       11815 : }
     168             : 
     169             : /************************************************************************
     170             :  *                       SetCenterFromOtherBlock()
     171             :  *
     172             :  * Sets the m_nCenterX and m_nCenterY from the one of another block and
     173             :  * lock them. See LockCenter() as well.
     174             :  * Used when splitting a page.
     175             :  ************************************************************************/
     176         253 : void TABMAPObjectBlock::SetCenterFromOtherBlock(
     177             :     TABMAPObjectBlock *poOtherObjBlock)
     178             : {
     179         253 :     m_nCenterX = poOtherObjBlock->m_nCenterX;
     180         253 :     m_nCenterY = poOtherObjBlock->m_nCenterY;
     181         253 :     LockCenter();
     182         253 : }
     183             : 
     184             : /************************************************************************/
     185             : /*                        Rewind()                                      */
     186             : /************************************************************************/
     187         778 : void TABMAPObjectBlock::Rewind()
     188             : {
     189         778 :     m_nCurObjectId = -1;
     190         778 :     m_nCurObjectOffset = -1;
     191         778 :     m_nCurObjectType = TAB_GEOM_UNSET;
     192         778 : }
     193             : 
     194             : /************************************************************************/
     195             : /*                        AdvanceToNextObject()                         */
     196             : /************************************************************************/
     197             : 
     198      428085 : int TABMAPObjectBlock::AdvanceToNextObject(TABMAPHeaderBlock *poHeader)
     199             : 
     200             : {
     201      428085 :     if (m_nCurObjectId == -1)
     202             :     {
     203       15996 :         m_nCurObjectOffset = 20;
     204             :     }
     205             :     else
     206             :     {
     207      412089 :         m_nCurObjectOffset += poHeader->GetMapObjectSize(m_nCurObjectType);
     208             :     }
     209             : 
     210      428085 :     if (m_nCurObjectOffset + 5 < m_numDataBytes + 20)
     211             :     {
     212      412589 :         GotoByteInBlock(m_nCurObjectOffset);
     213      412589 :         const GByte byVal = ReadByte();
     214      412589 :         if (TABMAPFile::IsValidObjType(byVal))
     215             :         {
     216      412589 :             m_nCurObjectType = static_cast<TABGeomType>(byVal);
     217             :         }
     218             :         else
     219             :         {
     220           0 :             CPLError(
     221             :                 CE_Warning,
     222             :                 static_cast<CPLErrorNum>(TAB_WarningFeatureTypeNotSupported),
     223             :                 "Unsupported object type %d (0x%2.2x).  Feature will be "
     224             :                 "returned with NONE geometry.",
     225             :                 byVal, byVal);
     226           0 :             m_nCurObjectType = TAB_GEOM_NONE;
     227             :         }
     228             :     }
     229             :     else
     230             :     {
     231       15496 :         m_nCurObjectType = TAB_GEOM_UNSET;
     232             :     }
     233             : 
     234      428085 :     if (m_nCurObjectType <= 0 || m_nCurObjectType >= TAB_GEOM_MAX_TYPE)
     235             :     {
     236       15496 :         m_nCurObjectType = TAB_GEOM_UNSET;
     237       15496 :         m_nCurObjectId = -1;
     238       15496 :         m_nCurObjectOffset = -1;
     239             :     }
     240             :     else
     241             :     {
     242      412589 :         m_nCurObjectId = ReadInt32();
     243             : 
     244             :         // Is this object marked as deleted?  If so, skip it.
     245             :         // I check both the top bits but I have only seen this occur
     246             :         // with the second highest bit set (i.e. in usa/states.tab). NFW.
     247             : 
     248      412589 :         if ((static_cast<GUInt32>(m_nCurObjectId) & 0xC0000000U) != 0)
     249             :         {
     250       15101 :             m_nCurObjectId = AdvanceToNextObject(poHeader);
     251             :         }
     252             :     }
     253             : 
     254      428085 :     return m_nCurObjectId;
     255             : }
     256             : 
     257             : /**********************************************************************
     258             :  *                   TABMAPObjectBlock::CommitToFile()
     259             :  *
     260             :  * Commit the current state of the binary block to the file to which
     261             :  * it has been previously attached.
     262             :  *
     263             :  * This method makes sure all values are properly set in the map object
     264             :  * block header and then calls TABRawBinBlock::CommitToFile() to do
     265             :  * the actual writing to disk.
     266             :  *
     267             :  * Returns 0 if successful or -1 if an error happened, in which case
     268             :  * CPLError() will have been called.
     269             :  **********************************************************************/
     270       17145 : int TABMAPObjectBlock::CommitToFile()
     271             : {
     272       17145 :     if (m_pabyBuf == nullptr)
     273             :     {
     274           0 :         CPLError(CE_Failure, CPLE_AssertionFailed,
     275             :                  "TABMAPObjectBlock::CommitToFile(): Block has not been "
     276             :                  "initialized yet!");
     277           0 :         return -1;
     278             :     }
     279             : 
     280             :     /*-----------------------------------------------------------------
     281             :      * Nothing to do here if block has not been modified
     282             :      *----------------------------------------------------------------*/
     283       17145 :     if (!m_bModified)
     284         390 :         return 0;
     285             : 
     286             :     /*-----------------------------------------------------------------
     287             :      * Make sure 20 bytes block header is up to date.
     288             :      *----------------------------------------------------------------*/
     289       16755 :     GotoByteInBlock(0x000);
     290             : 
     291       16755 :     WriteInt16(TABMAP_OBJECT_BLOCK);  // Block type code
     292       16755 :     m_numDataBytes = m_nSizeUsed - MAP_OBJECT_HEADER_SIZE;
     293       16755 :     CPLAssert(m_numDataBytes >= 0 && m_numDataBytes < 32768);
     294       16755 :     WriteInt16(static_cast<GInt16>(m_numDataBytes));  // num. bytes used
     295             : 
     296       16755 :     WriteInt32(m_nCenterX);
     297       16755 :     WriteInt32(m_nCenterY);
     298             : 
     299       16755 :     WriteInt32(m_nFirstCoordBlock);
     300       16755 :     WriteInt32(m_nLastCoordBlock);
     301             : 
     302       16755 :     int nStatus = CPLGetLastErrorType() == CE_Failure ? -1 : 0;
     303             : 
     304             :     /*-----------------------------------------------------------------
     305             :      * OK, all object data has already been written in the block.
     306             :      * Call the base class to write the block to disk.
     307             :      *----------------------------------------------------------------*/
     308       16755 :     if (nStatus == 0)
     309             :     {
     310             : #ifdef DEBUG_VERBOSE
     311             :         CPLDebug("MITAB", "Committing OBJECT block to offset %d",
     312             :                  m_nFileOffset);
     313             : #endif
     314       16755 :         nStatus = TABRawBinBlock::CommitToFile();
     315             :     }
     316             : 
     317       16755 :     return nStatus;
     318             : }
     319             : 
     320             : /**********************************************************************
     321             :  *                   TABMAPObjectBlock::InitNewBlock()
     322             :  *
     323             :  * Initialize a newly created block so that it knows to which file it
     324             :  * is attached, its block size, etc . and then perform any specific
     325             :  * initialization for this block type, including writing a default
     326             :  * block header, etc. and leave the block ready to receive data.
     327             :  *
     328             :  * This is an alternative to calling ReadFromFile() or InitBlockFromData()
     329             :  * that puts the block in a stable state without loading any initial
     330             :  * data in it.
     331             :  *
     332             :  * Returns 0 if successful or -1 if an error happened, in which case
     333             :  * CPLError() will have been called.
     334             :  **********************************************************************/
     335        1979 : int TABMAPObjectBlock::InitNewBlock(VSILFILE *fpSrc, int nBlockSize,
     336             :                                     int nFileOffset /* = 0*/)
     337             : {
     338             :     /*-----------------------------------------------------------------
     339             :      * Start with the default initialization
     340             :      *----------------------------------------------------------------*/
     341        1979 :     if (TABRawBinBlock::InitNewBlock(fpSrc, nBlockSize, nFileOffset) != 0)
     342           0 :         return -1;
     343             : 
     344             :     /*-----------------------------------------------------------------
     345             :      * And then set default values for the block header.
     346             :      *----------------------------------------------------------------*/
     347             :     // Set block MBR to extreme values to force an update on the first
     348             :     // UpdateMBR() call.
     349        1979 :     m_nMinX = 1000000000;
     350        1979 :     m_nMaxX = -1000000000;
     351        1979 :     m_nMinY = 1000000000;
     352        1979 :     m_nMaxY = -1000000000;
     353             : 
     354             :     // Reset current object refs
     355        1979 :     m_nCurObjectId = -1;
     356        1979 :     m_nCurObjectOffset = -1;
     357        1979 :     m_nCurObjectType = TAB_GEOM_UNSET;
     358             : 
     359        1979 :     m_numDataBytes = 0; /* Data size excluding header */
     360        1979 :     m_nCenterX = 0;
     361        1979 :     m_nCenterY = 0;
     362        1979 :     m_nFirstCoordBlock = 0;
     363        1979 :     m_nLastCoordBlock = 0;
     364             : 
     365        1979 :     if (m_eAccess != TABRead && nFileOffset != 0)
     366             :     {
     367         689 :         GotoByteInBlock(0x000);
     368             : 
     369         689 :         WriteInt16(TABMAP_OBJECT_BLOCK);  // Block type code
     370         689 :         WriteInt16(0);                    // num. bytes used, excluding header
     371             : 
     372             :         // MBR center here... will be written in CommitToFile()
     373         689 :         WriteInt32(0);
     374         689 :         WriteInt32(0);
     375             : 
     376             :         // First/last coord block ref... will be written in CommitToFile()
     377         689 :         WriteInt32(0);
     378         689 :         WriteInt32(0);
     379             :     }
     380             : 
     381        1979 :     if (CPLGetLastErrorType() == CE_Failure)
     382           0 :         return -1;
     383             : 
     384        1979 :     return 0;
     385             : }
     386             : 
     387             : /**********************************************************************
     388             :  *                   TABMAPObjectBlock::ReadCoord()
     389             :  *
     390             :  * Read the next pair of integer coordinates value from the block, and
     391             :  * apply the translation relative to to the center of the data block
     392             :  * if bCompressed=TRUE.
     393             :  *
     394             :  * This means that the returned coordinates are always absolute integer
     395             :  * coordinates, even when the source coords are in compressed form.
     396             :  *
     397             :  * Returns 0 if successful or -1 if an error happened, in which case
     398             :  * CPLError() will have been called.
     399             :  **********************************************************************/
     400      546899 : int TABMAPObjectBlock::ReadIntCoord(GBool bCompressed, GInt32 &nX, GInt32 &nY)
     401             : {
     402      546899 :     if (bCompressed)
     403             :     {
     404       13822 :         nX = ReadInt16();
     405       13822 :         nY = ReadInt16();
     406       13822 :         TABSaturatedAdd(nX, m_nCenterX);
     407       13822 :         TABSaturatedAdd(nY, m_nCenterY);
     408             :     }
     409             :     else
     410             :     {
     411      533077 :         nX = ReadInt32();
     412      533077 :         nY = ReadInt32();
     413             :     }
     414             : 
     415      546899 :     if (CPLGetLastErrorType() == CE_Failure)
     416           0 :         return -1;
     417             : 
     418      546899 :     return 0;
     419             : }
     420             : 
     421             : /**********************************************************************
     422             :  *                   TABMAPObjectBlock::WriteIntCoord()
     423             :  *
     424             :  * Write a pair of integer coordinates values to the current position in the
     425             :  * the block.  If bCompr=TRUE then the coordinates are written relative to
     426             :  * the object block center... otherwise they're written as 32 bits int.
     427             :  *
     428             :  * This function does not maintain the block's MBR and center... it is
     429             :  * assumed to have been set before the first call to WriteIntCoord()
     430             :  *
     431             :  * Returns 0 if successful or -1 if an error happened, in which case
     432             :  * CPLError() will have been called.
     433             :  **********************************************************************/
     434       25705 : int TABMAPObjectBlock::WriteIntCoord(GInt32 nX, GInt32 nY,
     435             :                                      GBool bCompressed /*=FALSE*/)
     436             : {
     437             : 
     438             :     /*-----------------------------------------------------------------
     439             :      * Write coords to the file.
     440             :      *----------------------------------------------------------------*/
     441       26370 :     if ((!bCompressed && (WriteInt32(nX) != 0 || WriteInt32(nY) != 0)) ||
     442         665 :         (bCompressed &&
     443         665 :          (WriteInt16(static_cast<GInt16>(nX - m_nCenterX)) != 0 ||
     444         665 :           WriteInt16(static_cast<GInt16>(nY - m_nCenterY)) != 0)))
     445             :     {
     446           0 :         return -1;
     447             :     }
     448             : 
     449       25705 :     return 0;
     450             : }
     451             : 
     452             : /**********************************************************************
     453             :  *                   TABMAPObjectBlock::WriteIntMBRCoord()
     454             :  *
     455             :  * Write 2 pairs of integer coordinates values to the current position
     456             :  * in the block after making sure that min values are smaller than
     457             :  * max values.  Use this function to write MBR coordinates for an object.
     458             :  *
     459             :  * If bCompr=TRUE then the coordinates are written relative to
     460             :  * the object block center... otherwise they're written as 32 bits int.
     461             :  *
     462             :  * This function does not maintain the block's MBR and center... it is
     463             :  * assumed to have been set before the first call to WriteIntCoord()
     464             :  *
     465             :  * Returns 0 if successful or -1 if an error happened, in which case
     466             :  * CPLError() will have been called.
     467             :  **********************************************************************/
     468           4 : int TABMAPObjectBlock::WriteIntMBRCoord(GInt32 nXMin, GInt32 nYMin,
     469             :                                         GInt32 nXMax, GInt32 nYMax,
     470             :                                         GBool bCompressed /*=FALSE*/)
     471             : {
     472           4 :     if (WriteIntCoord(std::min(nXMin, nXMax), std::min(nYMin, nYMax),
     473           8 :                       bCompressed) != 0 ||
     474           4 :         WriteIntCoord(std::max(nXMin, nXMax), std::max(nYMin, nYMax),
     475             :                       bCompressed) != 0)
     476             :     {
     477           0 :         return -1;
     478             :     }
     479             : 
     480           4 :     return 0;
     481             : }
     482             : 
     483             : /**********************************************************************
     484             :  *                   TABMAPObjectBlock::UpdateMBR()
     485             :  *
     486             :  * Update the block's MBR and center.
     487             :  *
     488             :  * Returns 0 if successful or -1 if an error happened, in which case
     489             :  * CPLError() will have been called.
     490             :  **********************************************************************/
     491       52352 : int TABMAPObjectBlock::UpdateMBR(GInt32 nX, GInt32 nY)
     492             : {
     493             : 
     494       52352 :     if (nX < m_nMinX)
     495        1381 :         m_nMinX = nX;
     496       52352 :     if (nX > m_nMaxX)
     497        3680 :         m_nMaxX = nX;
     498             : 
     499       52352 :     if (nY < m_nMinY)
     500        1075 :         m_nMinY = nY;
     501       52352 :     if (nY > m_nMaxY)
     502        3400 :         m_nMaxY = nY;
     503             : 
     504       52352 :     if (!m_bLockCenter)
     505             :     {
     506        6918 :         m_nCenterX =
     507        6918 :             static_cast<int>((static_cast<GIntBig>(m_nMinX) + m_nMaxX) / 2);
     508        6918 :         m_nCenterY =
     509        6918 :             static_cast<int>((static_cast<GIntBig>(m_nMinY) + m_nMaxY) / 2);
     510             :     }
     511             : 
     512       52352 :     return 0;
     513             : }
     514             : 
     515             : /**********************************************************************
     516             :  *                   TABMAPObjectBlock::AddCoordBlockRef()
     517             :  *
     518             :  * Update the first/last coord block fields in this object to contain
     519             :  * the specified block address.
     520             :  **********************************************************************/
     521         766 : void TABMAPObjectBlock::AddCoordBlockRef(GInt32 nNewBlockAddress)
     522             : {
     523             :     /*-----------------------------------------------------------------
     524             :      * Normally, new blocks are added to the end of the list, except
     525             :      * the first one which is the beginning and the end of the list at
     526             :      * the same time.
     527             :      *----------------------------------------------------------------*/
     528         766 :     if (m_nFirstCoordBlock == 0)
     529          59 :         m_nFirstCoordBlock = nNewBlockAddress;
     530             : 
     531         766 :     m_nLastCoordBlock = nNewBlockAddress;
     532         766 :     m_bModified = TRUE;
     533         766 : }
     534             : 
     535             : /**********************************************************************
     536             :  *                   TABMAPObjectBlock::SetMBR()
     537             :  *
     538             :  * Set the MBR for the current block.
     539             :  **********************************************************************/
     540       48491 : void TABMAPObjectBlock::SetMBR(GInt32 nXMin, GInt32 nYMin, GInt32 nXMax,
     541             :                                GInt32 nYMax)
     542             : {
     543       48491 :     m_nMinX = nXMin;
     544       48491 :     m_nMinY = nYMin;
     545       48491 :     m_nMaxX = nXMax;
     546       48491 :     m_nMaxY = nYMax;
     547             : 
     548       48491 :     if (!m_bLockCenter)
     549             :     {
     550        3471 :         m_nCenterX =
     551        3471 :             static_cast<int>((static_cast<GIntBig>(m_nMinX) + m_nMaxX) / 2);
     552        3471 :         m_nCenterY =
     553        3471 :             static_cast<int>((static_cast<GIntBig>(m_nMinY) + m_nMaxY) / 2);
     554             :     }
     555       48491 : }
     556             : 
     557             : /**********************************************************************
     558             :  *                   TABMAPObjectBlock::GetMBR()
     559             :  *
     560             :  * Return the MBR for the current block.
     561             :  **********************************************************************/
     562       66086 : void TABMAPObjectBlock::GetMBR(GInt32 &nXMin, GInt32 &nYMin, GInt32 &nXMax,
     563             :                                GInt32 &nYMax)
     564             : {
     565       66086 :     nXMin = m_nMinX;
     566       66086 :     nYMin = m_nMinY;
     567       66086 :     nXMax = m_nMaxX;
     568       66086 :     nYMax = m_nMaxY;
     569       66086 : }
     570             : 
     571             : /**********************************************************************
     572             :  *                   TABMAPObjectBlock::PrepareNewObject()
     573             :  *
     574             :  * Prepare this block to receive this new object. We only reserve space for
     575             :  * it in this call. Actual data will be written only when CommitNewObject()
     576             :  * is called.
     577             :  *
     578             :  * Returns the position at which the new object starts
     579             :  **********************************************************************/
     580       26176 : int TABMAPObjectBlock::PrepareNewObject(TABMAPObjHdr *poObjHdr)
     581             : {
     582       26176 :     int nStartAddress = 0;
     583             : 
     584             :     // Nothing to do for NONE objects
     585       26176 :     if (poObjHdr->m_nType == TAB_GEOM_NONE)
     586             :     {
     587           0 :         return 0;
     588             :     }
     589             : 
     590             :     // Maintain MBR of this object block.
     591       26176 :     UpdateMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY);
     592       26176 :     UpdateMBR(poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
     593             : 
     594             :     /*-----------------------------------------------------------------
     595             :      * Keep track of object type, ID and start address for use by
     596             :      * CommitNewObject()
     597             :      *----------------------------------------------------------------*/
     598       26176 :     nStartAddress = GetFirstUnusedByteOffset();
     599             : 
     600             :     // Backup MBR and bLockCenter as they will be reset by GotoByteInFile()
     601             :     // that will call InitBlockFromData()
     602             :     GInt32 nXMin, nYMin, nXMax, nYMax;
     603       26176 :     GetMBR(nXMin, nYMin, nXMax, nYMax);
     604       26176 :     int bLockCenter = m_bLockCenter;
     605       26176 :     GotoByteInFile(nStartAddress);
     606       26176 :     m_bLockCenter = bLockCenter;
     607       26176 :     SetMBR(nXMin, nYMin, nXMax, nYMax);
     608       26176 :     m_nCurObjectOffset = nStartAddress - GetStartAddress();
     609             : 
     610       26176 :     m_nCurObjectType = poObjHdr->m_nType;
     611       26176 :     m_nCurObjectId = poObjHdr->m_nId;
     612             : 
     613       26176 :     return nStartAddress;
     614             : }
     615             : 
     616             : /**********************************************************************
     617             :  *                   TABMAPObjectBlock::CommitCurObjData()
     618             :  *
     619             :  * Write the ObjHdr to this block. This is usually called after
     620             :  * PrepareNewObject() once all members of the ObjHdr have
     621             :  * been set.
     622             :  *
     623             :  * Returns 0 if successful or -1 if an error happened, in which case
     624             :  * CPLError() will have been called.
     625             :  **********************************************************************/
     626       26176 : int TABMAPObjectBlock::CommitNewObject(TABMAPObjHdr *poObjHdr)
     627             : {
     628       26176 :     int nStatus = 0;
     629             : 
     630       26176 :     CPLAssert(poObjHdr->m_nType != TAB_GEOM_NONE);
     631             : 
     632             :     // Nothing to do for NONE objects
     633       26176 :     if (poObjHdr->m_nType == TAB_GEOM_NONE)
     634             :     {
     635           0 :         return 0;
     636             :     }
     637             : 
     638       26176 :     CPLAssert(m_nCurObjectId == poObjHdr->m_nId);
     639       26176 :     GotoByteInBlock(m_nCurObjectOffset);
     640             : 
     641       26176 :     nStatus = poObjHdr->WriteObj(this);
     642             : 
     643       26176 :     if (nStatus == 0)
     644       26176 :         m_numDataBytes = m_nSizeUsed - MAP_OBJECT_HEADER_SIZE;
     645             : 
     646       26176 :     return nStatus;
     647             : }
     648             : 
     649             : /**********************************************************************
     650             :  *                   TABMAPObjectBlock::Dump()
     651             :  *
     652             :  * Dump block contents... available only in DEBUG mode.
     653             :  **********************************************************************/
     654             : #ifdef DEBUG
     655             : 
     656           0 : void TABMAPObjectBlock::Dump(FILE *fpOut, GBool bDetails)
     657             : {
     658           0 :     CPLErrorReset();
     659             : 
     660           0 :     if (fpOut == nullptr)
     661           0 :         fpOut = stdout;
     662             : 
     663           0 :     fprintf(fpOut, "----- TABMAPObjectBlock::Dump() -----\n");
     664           0 :     if (m_pabyBuf == nullptr)
     665             :     {
     666           0 :         fprintf(fpOut, "Block has not been initialized yet.");
     667             :     }
     668             :     else
     669             :     {
     670           0 :         fprintf(fpOut, "Object Data Block (type %d) at offset %d.\n",
     671             :                 m_nBlockType, m_nFileOffset);
     672           0 :         fprintf(fpOut, "  m_numDataBytes        = %d\n", m_numDataBytes);
     673           0 :         fprintf(fpOut, "  m_nCenterX            = %d\n", m_nCenterX);
     674           0 :         fprintf(fpOut, "  m_nCenterY            = %d\n", m_nCenterY);
     675           0 :         fprintf(fpOut, "  m_nFirstCoordBlock    = %d\n", m_nFirstCoordBlock);
     676           0 :         fprintf(fpOut, "  m_nLastCoordBlock     = %d\n", m_nLastCoordBlock);
     677             :     }
     678             : 
     679           0 :     if (bDetails)
     680             :     {
     681             :         /* We need the mapfile's header block */
     682             :         TABRawBinBlock *poBlock =
     683           0 :             TABCreateMAPBlockFromFile(m_fp, 0, m_nBlockSize);
     684           0 :         if (poBlock == nullptr ||
     685           0 :             poBlock->GetBlockClass() != TABMAP_HEADER_BLOCK)
     686             :         {
     687           0 :             CPLError(CE_Failure, CPLE_AssertionFailed,
     688             :                      "Failed reading header block.");
     689           0 :             return;
     690             :         }
     691             :         TABMAPHeaderBlock *poHeader =
     692           0 :             cpl::down_cast<TABMAPHeaderBlock *>(poBlock);
     693             : 
     694           0 :         Rewind();
     695           0 :         TABMAPObjHdr *poObjHdr = nullptr;
     696           0 :         while ((poObjHdr = TABMAPObjHdr::ReadNextObj(this, poHeader)) !=
     697             :                nullptr)
     698             :         {
     699           0 :             fprintf(fpOut,
     700             :                     "   object id=%d, type=%d, offset=%d (%d), size=%d\n"
     701             :                     "          MBR=(%d, %d, %d, %d)\n",
     702           0 :                     m_nCurObjectId, m_nCurObjectType, m_nCurObjectOffset,
     703           0 :                     m_nFileOffset + m_nCurObjectOffset,
     704           0 :                     poHeader->GetMapObjectSize(m_nCurObjectType),
     705             :                     poObjHdr->m_nMinX, poObjHdr->m_nMinY, poObjHdr->m_nMaxX,
     706             :                     poObjHdr->m_nMaxY);
     707           0 :             delete poObjHdr;
     708             :         }
     709             : 
     710           0 :         delete poHeader;
     711             :     }
     712             : 
     713           0 :     fflush(fpOut);
     714             : }
     715             : 
     716             : #endif  // DEBUG
     717             : 
     718             : /*=====================================================================
     719             :  *                      class TABMAPObjHdr and family
     720             :  *====================================================================*/
     721             : 
     722             : /**********************************************************************
     723             :  *                   class TABMAPObjHdr
     724             :  *
     725             :  * Virtual base class... contains static methods used to allocate instance
     726             :  * of the derived classes.
     727             :  *
     728             :  **********************************************************************/
     729             : 
     730             : /**********************************************************************
     731             :  *                    TABMAPObjHdr::NewObj()
     732             :  *
     733             :  * Alloc a new object of specified type or NULL for NONE types or if type
     734             :  * is not supported.
     735             :  **********************************************************************/
     736      564335 : TABMAPObjHdr *TABMAPObjHdr::NewObj(TABGeomType nNewObjType, GInt32 nId /*=0*/)
     737             : {
     738      564335 :     TABMAPObjHdr *poObj = nullptr;
     739             : 
     740      564335 :     switch (nNewObjType)
     741             :     {
     742         214 :         case TAB_GEOM_NONE:
     743         214 :             poObj = new TABMAPObjNone;
     744         214 :             break;
     745      561452 :         case TAB_GEOM_SYMBOL_C:
     746             :         case TAB_GEOM_SYMBOL:
     747      561452 :             poObj = new TABMAPObjPoint;
     748      561452 :             break;
     749           8 :         case TAB_GEOM_FONTSYMBOL_C:
     750             :         case TAB_GEOM_FONTSYMBOL:
     751           8 :             poObj = new TABMAPObjFontPoint;
     752           8 :             break;
     753           8 :         case TAB_GEOM_CUSTOMSYMBOL_C:
     754             :         case TAB_GEOM_CUSTOMSYMBOL:
     755           8 :             poObj = new TABMAPObjCustomPoint;
     756           8 :             break;
     757          44 :         case TAB_GEOM_LINE_C:
     758             :         case TAB_GEOM_LINE:
     759          44 :             poObj = new TABMAPObjLine;
     760          44 :             break;
     761        2569 :         case TAB_GEOM_PLINE_C:
     762             :         case TAB_GEOM_PLINE:
     763             :         case TAB_GEOM_REGION_C:
     764             :         case TAB_GEOM_REGION:
     765             :         case TAB_GEOM_MULTIPLINE_C:
     766             :         case TAB_GEOM_MULTIPLINE:
     767             :         case TAB_GEOM_V450_REGION_C:
     768             :         case TAB_GEOM_V450_REGION:
     769             :         case TAB_GEOM_V450_MULTIPLINE_C:
     770             :         case TAB_GEOM_V450_MULTIPLINE:
     771             :         case TAB_GEOM_V800_REGION_C:
     772             :         case TAB_GEOM_V800_REGION:
     773             :         case TAB_GEOM_V800_MULTIPLINE_C:
     774             :         case TAB_GEOM_V800_MULTIPLINE:
     775        2569 :             poObj = new TABMAPObjPLine;
     776        2569 :             break;
     777           8 :         case TAB_GEOM_ARC_C:
     778             :         case TAB_GEOM_ARC:
     779           8 :             poObj = new TABMAPObjArc;
     780           8 :             break;
     781          12 :         case TAB_GEOM_RECT_C:
     782             :         case TAB_GEOM_RECT:
     783             :         case TAB_GEOM_ROUNDRECT_C:
     784             :         case TAB_GEOM_ROUNDRECT:
     785             :         case TAB_GEOM_ELLIPSE_C:
     786             :         case TAB_GEOM_ELLIPSE:
     787          12 :             poObj = new TABMAPObjRectEllipse;
     788          12 :             break;
     789          12 :         case TAB_GEOM_TEXT_C:
     790             :         case TAB_GEOM_TEXT:
     791          12 :             poObj = new TABMAPObjText;
     792          12 :             break;
     793           4 :         case TAB_GEOM_MULTIPOINT_C:
     794             :         case TAB_GEOM_MULTIPOINT:
     795             :         case TAB_GEOM_V800_MULTIPOINT_C:
     796             :         case TAB_GEOM_V800_MULTIPOINT:
     797           4 :             poObj = new TABMAPObjMultiPoint;
     798           4 :             break;
     799           4 :         case TAB_GEOM_COLLECTION_C:
     800             :         case TAB_GEOM_COLLECTION:
     801             :         case TAB_GEOM_V800_COLLECTION_C:
     802             :         case TAB_GEOM_V800_COLLECTION:
     803           4 :             poObj = new TABMAPObjCollection();
     804           4 :             break;
     805           0 :         default:
     806           0 :             CPLError(CE_Failure, CPLE_AssertionFailed,
     807             :                      "TABMAPObjHdr::NewObj(): Unsupported object type %d",
     808             :                      nNewObjType);
     809             :     }
     810             : 
     811      564335 :     if (poObj)
     812             :     {
     813      564335 :         poObj->m_nType = nNewObjType;
     814      564335 :         poObj->m_nId = nId;
     815      564335 :         poObj->m_nMinX = poObj->m_nMinY = poObj->m_nMaxX = poObj->m_nMaxY = 0;
     816             :     }
     817             : 
     818      564335 :     return poObj;
     819             : }
     820             : 
     821             : /**********************************************************************
     822             :  *                    TABMAPObjHdr::ReadNextObj()
     823             :  *
     824             :  * Read next object in this block and allocate/init a new object for it
     825             :  * if successful.
     826             :  * Returns NULL in case of error or if we reached end of block.
     827             :  **********************************************************************/
     828       20600 : TABMAPObjHdr *TABMAPObjHdr::ReadNextObj(TABMAPObjectBlock *poObjBlock,
     829             :                                         TABMAPHeaderBlock *poHeader)
     830             : {
     831       20600 :     TABMAPObjHdr *poObjHdr = nullptr;
     832             : 
     833       20600 :     if (poObjBlock->AdvanceToNextObject(poHeader) != -1)
     834             :     {
     835       19822 :         poObjHdr = TABMAPObjHdr::NewObj(poObjBlock->GetCurObjectType());
     836       39644 :         if (poObjHdr &&
     837       19822 :             ((poObjHdr->m_nId = poObjBlock->GetCurObjectId()) == -1 ||
     838       19822 :              poObjHdr->ReadObj(poObjBlock) != 0))
     839             :         {
     840             :             // Failed reading object in block... an error was already produced
     841           0 :             delete poObjHdr;
     842           0 :             return nullptr;
     843             :         }
     844             :     }
     845             : 
     846       20600 :     return poObjHdr;
     847             : }
     848             : 
     849             : /**********************************************************************
     850             :  *                    TABMAPObjHdr::IsCompressedType()
     851             :  *
     852             :  * Returns TRUE if the current object type uses compressed coordinates
     853             :  * or FALSE otherwise.
     854             :  **********************************************************************/
     855      580751 : GBool TABMAPObjHdr::IsCompressedType()
     856             : {
     857             :     // Compressed types are 1, 4, 7, etc.
     858      580751 :     return (m_nType % 3) == 1 ? TRUE : FALSE;
     859             : }
     860             : 
     861             : /**********************************************************************
     862             :  *                   TABMAPObjHdr::WriteObjTypeAndId()
     863             :  *
     864             :  * Writetype+object id information... should be called only by the derived
     865             :  * classes' WriteObj() methods.
     866             :  *
     867             :  * Returns 0 on success, -1 on error.
     868             :  **********************************************************************/
     869       26176 : int TABMAPObjHdr::WriteObjTypeAndId(TABMAPObjectBlock *poObjBlock)
     870             : {
     871       26176 :     poObjBlock->WriteByte(static_cast<GByte>(m_nType));
     872       26176 :     return poObjBlock->WriteInt32(m_nId);
     873             : }
     874             : 
     875             : /**********************************************************************
     876             :  *                   TABMAPObjHdr::SetMBR()
     877             :  *
     878             :  **********************************************************************/
     879      561987 : void TABMAPObjHdr::SetMBR(GInt32 nMinX, GInt32 nMinY, GInt32 nMaxX,
     880             :                           GInt32 nMaxY)
     881             : {
     882      561987 :     m_nMinX = std::min(nMinX, nMaxX);
     883      561987 :     m_nMinY = std::min(nMinY, nMaxY);
     884      561987 :     m_nMaxX = std::max(nMinX, nMaxX);
     885      561987 :     m_nMaxY = std::max(nMinY, nMaxY);
     886      561987 : }
     887             : 
     888             : /**********************************************************************
     889             :  *                   class TABMAPObjLine
     890             :  *
     891             :  * Applies to 2-points LINEs only
     892             :  **********************************************************************/
     893             : 
     894             : /**********************************************************************
     895             :  *                   TABMAPObjLine::ReadObj()
     896             :  *
     897             :  * Read Object information starting after the object id which should
     898             :  * have been read by TABMAPObjHdr::ReadNextObj() already.
     899             :  * This function should be called only by TABMAPObjHdr::ReadNextObj().
     900             :  *
     901             :  * Returns 0 on success, -1 on error.
     902             :  **********************************************************************/
     903          21 : int TABMAPObjLine::ReadObj(TABMAPObjectBlock *poObjBlock)
     904             : {
     905          21 :     poObjBlock->ReadIntCoord(IsCompressedType(), m_nX1, m_nY1);
     906          21 :     poObjBlock->ReadIntCoord(IsCompressedType(), m_nX2, m_nY2);
     907             : 
     908          21 :     m_nPenId = poObjBlock->ReadByte();  // Pen index
     909             : 
     910          21 :     SetMBR(m_nX1, m_nY1, m_nX2, m_nY2);
     911             : 
     912          21 :     if (CPLGetLastErrorType() == CE_Failure)
     913           0 :         return -1;
     914             : 
     915          21 :     return 0;
     916             : }
     917             : 
     918             : /**********************************************************************
     919             :  *                   TABMAPObjLine::WriteObj()
     920             :  *
     921             :  * Write Object information with the type+object id
     922             :  *
     923             :  * Returns 0 on success, -1 on error.
     924             :  **********************************************************************/
     925          23 : int TABMAPObjLine::WriteObj(TABMAPObjectBlock *poObjBlock)
     926             : {
     927             :     // Write object type and id
     928          23 :     TABMAPObjHdr::WriteObjTypeAndId(poObjBlock);
     929             : 
     930          23 :     poObjBlock->WriteIntCoord(m_nX1, m_nY1, IsCompressedType());
     931          23 :     poObjBlock->WriteIntCoord(m_nX2, m_nY2, IsCompressedType());
     932             : 
     933          23 :     poObjBlock->WriteByte(m_nPenId);  // Pen index
     934             : 
     935          23 :     if (CPLGetLastErrorType() == CE_Failure)
     936           0 :         return -1;
     937             : 
     938          23 :     return 0;
     939             : }
     940             : 
     941             : /**********************************************************************
     942             :  *                   class TABMAPObjPLine
     943             :  *
     944             :  * Applies to PLINE, MULTIPLINE and REGION object types
     945             :  **********************************************************************/
     946             : 
     947             : /**********************************************************************
     948             :  *                   TABMAPObjPLine::ReadObj()
     949             :  *
     950             :  * Read Object information starting after the object id which should
     951             :  * have been read by TABMAPObjHdr::ReadNextObj() already.
     952             :  * This function should be called only by TABMAPObjHdr::ReadNextObj().
     953             :  *
     954             :  * Returns 0 on success, -1 on error.
     955             :  **********************************************************************/
     956        2266 : int TABMAPObjPLine::ReadObj(TABMAPObjectBlock *poObjBlock)
     957             : {
     958        2266 :     m_nCoordBlockPtr = poObjBlock->ReadInt32();
     959        2266 :     m_nCoordDataSize = poObjBlock->ReadInt32();
     960             : 
     961        2266 :     if (m_nCoordDataSize & 0x80000000)
     962             :     {
     963           4 :         m_bSmooth = TRUE;
     964           4 :         m_nCoordDataSize &= 0x7FFFFFFF;  // Take smooth flag out of the value
     965             :     }
     966             :     else
     967             :     {
     968        2262 :         m_bSmooth = FALSE;
     969             :     }
     970             : 
     971             : #ifdef TABDUMP
     972             :     printf("TABMAPObjPLine::ReadObj: m_nCoordDataSize = %d @ %d\n", /*ok*/
     973             :            m_nCoordDataSize, m_nCoordBlockPtr);
     974             : #endif
     975             : 
     976             :     // Number of line segments applies only to MULTIPLINE/REGION but not PLINE
     977        2266 :     if (m_nType == TAB_GEOM_PLINE_C || m_nType == TAB_GEOM_PLINE)
     978             :     {
     979        1741 :         m_numLineSections = 1;
     980             :     }
     981         525 :     else if (m_nType == TAB_GEOM_V800_REGION ||
     982         525 :              m_nType == TAB_GEOM_V800_REGION_C ||
     983         525 :              m_nType == TAB_GEOM_V800_MULTIPLINE ||
     984         525 :              m_nType == TAB_GEOM_V800_MULTIPLINE_C)
     985             :     {
     986             :         /* V800 REGIONS/MULTIPLINES use an int32 */
     987           0 :         m_numLineSections = poObjBlock->ReadInt32();
     988             :         /* ... followed by 33 unknown bytes */
     989           0 :         poObjBlock->ReadInt32();
     990           0 :         poObjBlock->ReadInt32();
     991           0 :         poObjBlock->ReadInt32();
     992           0 :         poObjBlock->ReadInt32();
     993           0 :         poObjBlock->ReadInt32();
     994           0 :         poObjBlock->ReadInt32();
     995           0 :         poObjBlock->ReadInt32();
     996           0 :         poObjBlock->ReadInt32();
     997           0 :         poObjBlock->ReadByte();
     998             :     }
     999             :     else
    1000             :     {
    1001             :         /* V300 and V450 REGIONS/MULTIPLINES use an int16 */
    1002         525 :         m_numLineSections = poObjBlock->ReadInt16();
    1003             :     }
    1004             : 
    1005        2266 :     if (m_numLineSections < 0)
    1006             :     {
    1007           0 :         CPLError(CE_Failure, CPLE_AssertionFailed, "Invalid numLineSections");
    1008           0 :         return -1;
    1009             :     }
    1010             : 
    1011             : #ifdef TABDUMP
    1012             :     printf("PLINE/REGION: id=%d, type=%d, " /*ok*/
    1013             :            "CoordBlockPtr=%d, CoordDataSize=%d, numLineSect=%d, bSmooth=%d\n",
    1014             :            m_nId, m_nType, m_nCoordBlockPtr, m_nCoordDataSize,
    1015             :            m_numLineSections, m_bSmooth);
    1016             : #endif
    1017             : 
    1018        2266 :     if (IsCompressedType())
    1019             :     {
    1020             :         // Region center/label point, relative to compr. coord. origin
    1021             :         // No it is not relative to the Object block center
    1022        2205 :         m_nLabelX = poObjBlock->ReadInt16();
    1023        2205 :         m_nLabelY = poObjBlock->ReadInt16();
    1024             : 
    1025             :         // Compressed coordinate origin (present only in compressed case!)
    1026        2205 :         m_nComprOrgX = poObjBlock->ReadInt32();
    1027        2205 :         m_nComprOrgY = poObjBlock->ReadInt32();
    1028             : 
    1029        2205 :         TABSaturatedAdd(m_nLabelX, m_nComprOrgX);
    1030        2205 :         TABSaturatedAdd(m_nLabelY, m_nComprOrgY);
    1031             : 
    1032        2205 :         m_nMinX = poObjBlock->ReadInt16();  // Read MBR
    1033        2205 :         m_nMinY = poObjBlock->ReadInt16();
    1034        2205 :         m_nMaxX = poObjBlock->ReadInt16();
    1035        2205 :         m_nMaxY = poObjBlock->ReadInt16();
    1036        2205 :         TABSaturatedAdd(m_nMinX, m_nComprOrgX);
    1037        2205 :         TABSaturatedAdd(m_nMinY, m_nComprOrgY);
    1038        2205 :         TABSaturatedAdd(m_nMaxX, m_nComprOrgX);
    1039        2205 :         TABSaturatedAdd(m_nMaxY, m_nComprOrgY);
    1040             :     }
    1041             :     else
    1042             :     {
    1043             :         // Region center/label point, relative to compr. coord. origin
    1044             :         // No it is not relative to the Object block center
    1045          61 :         m_nLabelX = poObjBlock->ReadInt32();
    1046          61 :         m_nLabelY = poObjBlock->ReadInt32();
    1047             : 
    1048          61 :         m_nMinX = poObjBlock->ReadInt32();  // Read MBR
    1049          61 :         m_nMinY = poObjBlock->ReadInt32();
    1050          61 :         m_nMaxX = poObjBlock->ReadInt32();
    1051          61 :         m_nMaxY = poObjBlock->ReadInt32();
    1052             :     }
    1053             : 
    1054        2266 :     if (!IsCompressedType())
    1055             :     {
    1056             :         // Init. Compr. Origin to a default value in case type is ever changed
    1057          61 :         m_nComprOrgX =
    1058          61 :             static_cast<GInt32>((static_cast<GIntBig>(m_nMinX) + m_nMaxX) / 2);
    1059          61 :         m_nComprOrgY =
    1060          61 :             static_cast<GInt32>((static_cast<GIntBig>(m_nMinY) + m_nMaxY) / 2);
    1061             :     }
    1062             : 
    1063        2266 :     m_nPenId = poObjBlock->ReadByte();  // Pen index
    1064             : 
    1065        2266 :     if (m_nType == TAB_GEOM_REGION || m_nType == TAB_GEOM_REGION_C ||
    1066        1747 :         m_nType == TAB_GEOM_V450_REGION || m_nType == TAB_GEOM_V450_REGION_C ||
    1067        1747 :         m_nType == TAB_GEOM_V800_REGION || m_nType == TAB_GEOM_V800_REGION_C)
    1068             :     {
    1069         519 :         m_nBrushId = poObjBlock->ReadByte();  // Brush index... REGION only
    1070             :     }
    1071             :     else
    1072             :     {
    1073        1747 :         m_nBrushId = 0;
    1074             :     }
    1075             : 
    1076        2266 :     if (CPLGetLastErrorType() == CE_Failure)
    1077           0 :         return -1;
    1078             : 
    1079        2266 :     return 0;
    1080             : }
    1081             : 
    1082             : /**********************************************************************
    1083             :  *                   TABMAPObjPLine::WriteObj()
    1084             :  *
    1085             :  * Write Object information with the type+object id
    1086             :  *
    1087             :  * Returns 0 on success, -1 on error.
    1088             :  **********************************************************************/
    1089         502 : int TABMAPObjPLine::WriteObj(TABMAPObjectBlock *poObjBlock)
    1090             : {
    1091             :     // Write object type and id
    1092         502 :     TABMAPObjHdr::WriteObjTypeAndId(poObjBlock);
    1093             : 
    1094         502 :     poObjBlock->WriteInt32(m_nCoordBlockPtr);
    1095             : 
    1096             :     // Combine smooth flag in the coord data size.
    1097         502 :     if (m_bSmooth)
    1098           0 :         poObjBlock->WriteInt32(m_nCoordDataSize | 0x80000000);
    1099             :     else
    1100         502 :         poObjBlock->WriteInt32(m_nCoordDataSize);
    1101             : 
    1102             :     // Number of line segments applies only to MULTIPLINE/REGION but not PLINE
    1103         502 :     if (m_nType == TAB_GEOM_V800_REGION || m_nType == TAB_GEOM_V800_REGION_C ||
    1104         502 :         m_nType == TAB_GEOM_V800_MULTIPLINE ||
    1105         502 :         m_nType == TAB_GEOM_V800_MULTIPLINE_C)
    1106             :     {
    1107             :         /* V800 REGIONS/MULTIPLINES use an int32 */
    1108           0 :         poObjBlock->WriteInt32(m_numLineSections);
    1109             :         /* ... followed by 33 unknown bytes */
    1110           0 :         poObjBlock->WriteZeros(33);
    1111             :     }
    1112         502 :     else if (m_nType != TAB_GEOM_PLINE_C && m_nType != TAB_GEOM_PLINE)
    1113             :     {
    1114             :         /* V300 and V450 REGIONS/MULTIPLINES use an int16 */
    1115         105 :         poObjBlock->WriteInt16(static_cast<GInt16>(m_numLineSections));
    1116             :     }
    1117             : 
    1118         502 :     if (IsCompressedType())
    1119             :     {
    1120             :         // Region center/label point, relative to compr. coord. origin
    1121             :         // No it is not relative to the Object block center
    1122         492 :         poObjBlock->WriteInt16(TABInt16Diff(m_nLabelX, m_nComprOrgX));
    1123         492 :         poObjBlock->WriteInt16(TABInt16Diff(m_nLabelY, m_nComprOrgY));
    1124             : 
    1125             :         // Compressed coordinate origin (present only in compressed case!)
    1126         492 :         poObjBlock->WriteInt32(m_nComprOrgX);
    1127         492 :         poObjBlock->WriteInt32(m_nComprOrgY);
    1128             :     }
    1129             :     else
    1130             :     {
    1131             :         // Region center/label point
    1132          10 :         poObjBlock->WriteInt32(m_nLabelX);
    1133          10 :         poObjBlock->WriteInt32(m_nLabelY);
    1134             :     }
    1135             : 
    1136             :     // MBR
    1137         502 :     if (IsCompressedType())
    1138             :     {
    1139             :         // MBR relative to PLINE origin (and not object block center)
    1140         492 :         poObjBlock->WriteInt16(TABInt16Diff(m_nMinX, m_nComprOrgX));
    1141         492 :         poObjBlock->WriteInt16(TABInt16Diff(m_nMinY, m_nComprOrgY));
    1142         492 :         poObjBlock->WriteInt16(TABInt16Diff(m_nMaxX, m_nComprOrgX));
    1143         492 :         poObjBlock->WriteInt16(TABInt16Diff(m_nMaxY, m_nComprOrgY));
    1144             :     }
    1145             :     else
    1146             :     {
    1147          10 :         poObjBlock->WriteInt32(m_nMinX);
    1148          10 :         poObjBlock->WriteInt32(m_nMinY);
    1149          10 :         poObjBlock->WriteInt32(m_nMaxX);
    1150          10 :         poObjBlock->WriteInt32(m_nMaxY);
    1151             :     }
    1152             : 
    1153         502 :     poObjBlock->WriteByte(m_nPenId);  // Pen index
    1154             : 
    1155         502 :     if (m_nType == TAB_GEOM_REGION || m_nType == TAB_GEOM_REGION_C ||
    1156         405 :         m_nType == TAB_GEOM_V450_REGION || m_nType == TAB_GEOM_V450_REGION_C ||
    1157         405 :         m_nType == TAB_GEOM_V800_REGION || m_nType == TAB_GEOM_V800_REGION_C)
    1158             :     {
    1159          97 :         poObjBlock->WriteByte(m_nBrushId);  // Brush index... REGION only
    1160             :     }
    1161             : 
    1162         502 :     if (CPLGetLastErrorType() == CE_Failure)
    1163           0 :         return -1;
    1164             : 
    1165         502 :     return 0;
    1166             : }
    1167             : 
    1168             : /**********************************************************************
    1169             :  *                   class TABMAPObjPoint
    1170             :  *
    1171             :  **********************************************************************/
    1172             : 
    1173             : /**********************************************************************
    1174             :  *                   TABMAPObjPoint::ReadObj()
    1175             :  *
    1176             :  * Read Object information starting after the object id
    1177             :  **********************************************************************/
    1178      546765 : int TABMAPObjPoint::ReadObj(TABMAPObjectBlock *poObjBlock)
    1179             : {
    1180      546765 :     poObjBlock->ReadIntCoord(IsCompressedType(), m_nX, m_nY);
    1181             : 
    1182      546765 :     m_nSymbolId = poObjBlock->ReadByte();  // Symbol index
    1183             : 
    1184      546765 :     SetMBR(m_nX, m_nY, m_nX, m_nY);
    1185             : 
    1186      546765 :     if (CPLGetLastErrorType() == CE_Failure)
    1187           0 :         return -1;
    1188             : 
    1189      546765 :     return 0;
    1190             : }
    1191             : 
    1192             : /**********************************************************************
    1193             :  *                   TABMAPObjPoint::WriteObj()
    1194             :  *
    1195             :  * Write Object information with the type+object id
    1196             :  *
    1197             :  * Returns 0 on success, -1 on error.
    1198             :  **********************************************************************/
    1199       25643 : int TABMAPObjPoint::WriteObj(TABMAPObjectBlock *poObjBlock)
    1200             : {
    1201             :     // Write object type and id
    1202       25643 :     TABMAPObjHdr::WriteObjTypeAndId(poObjBlock);
    1203             : 
    1204       25643 :     poObjBlock->WriteIntCoord(m_nX, m_nY, IsCompressedType());
    1205             : 
    1206       25643 :     poObjBlock->WriteByte(m_nSymbolId);  // Symbol index
    1207             : 
    1208       25643 :     if (CPLGetLastErrorType() == CE_Failure)
    1209           0 :         return -1;
    1210             : 
    1211       25643 :     return 0;
    1212             : }
    1213             : 
    1214             : /**********************************************************************
    1215             :  *                   class TABMAPObjFontPoint
    1216             :  *
    1217             :  **********************************************************************/
    1218             : 
    1219             : /**********************************************************************
    1220             :  *                   TABMAPObjFontPoint::ReadObj()
    1221             :  *
    1222             :  * Read Object information starting after the object id
    1223             :  **********************************************************************/
    1224           6 : int TABMAPObjFontPoint::ReadObj(TABMAPObjectBlock *poObjBlock)
    1225             : {
    1226           6 :     m_nSymbolId = poObjBlock->ReadByte();  // Symbol index
    1227           6 :     m_nPointSize = poObjBlock->ReadByte();
    1228           6 :     m_nFontStyle = poObjBlock->ReadInt16();  // font style
    1229             : 
    1230           6 :     m_nR = poObjBlock->ReadByte();
    1231           6 :     m_nG = poObjBlock->ReadByte();
    1232           6 :     m_nB = poObjBlock->ReadByte();
    1233             : 
    1234           6 :     poObjBlock->ReadByte();  // ??? BG Color ???
    1235           6 :     poObjBlock->ReadByte();  // ???
    1236           6 :     poObjBlock->ReadByte();  // ???
    1237             : 
    1238           6 :     m_nAngle = poObjBlock->ReadInt16();
    1239             : 
    1240           6 :     poObjBlock->ReadIntCoord(IsCompressedType(), m_nX, m_nY);
    1241             : 
    1242           6 :     m_nFontId = poObjBlock->ReadByte();  // Font name index
    1243             : 
    1244           6 :     SetMBR(m_nX, m_nY, m_nX, m_nY);
    1245             : 
    1246           6 :     if (CPLGetLastErrorType() == CE_Failure)
    1247           0 :         return -1;
    1248             : 
    1249           6 :     return 0;
    1250             : }
    1251             : 
    1252             : /**********************************************************************
    1253             :  *                   TABMAPObjFontPoint::WriteObj()
    1254             :  *
    1255             :  * Write Object information with the type+object id
    1256             :  *
    1257             :  * Returns 0 on success, -1 on error.
    1258             :  **********************************************************************/
    1259           2 : int TABMAPObjFontPoint::WriteObj(TABMAPObjectBlock *poObjBlock)
    1260             : {
    1261             :     // Write object type and id
    1262           2 :     TABMAPObjHdr::WriteObjTypeAndId(poObjBlock);
    1263             : 
    1264           2 :     poObjBlock->WriteByte(m_nSymbolId);  // symbol shape
    1265           2 :     poObjBlock->WriteByte(m_nPointSize);
    1266           2 :     poObjBlock->WriteInt16(m_nFontStyle);  // font style
    1267             : 
    1268           2 :     poObjBlock->WriteByte(m_nR);
    1269           2 :     poObjBlock->WriteByte(m_nG);
    1270           2 :     poObjBlock->WriteByte(m_nB);
    1271             : 
    1272           2 :     poObjBlock->WriteByte(0);
    1273           2 :     poObjBlock->WriteByte(0);
    1274           2 :     poObjBlock->WriteByte(0);
    1275             : 
    1276           2 :     poObjBlock->WriteInt16(m_nAngle);
    1277             : 
    1278           2 :     poObjBlock->WriteIntCoord(m_nX, m_nY, IsCompressedType());
    1279             : 
    1280           2 :     poObjBlock->WriteByte(m_nFontId);  // Font name index
    1281             : 
    1282           2 :     if (CPLGetLastErrorType() == CE_Failure)
    1283           0 :         return -1;
    1284             : 
    1285           2 :     return 0;
    1286             : }
    1287             : 
    1288             : /**********************************************************************
    1289             :  *                   class TABMAPObjCustomPoint
    1290             :  *
    1291             :  **********************************************************************/
    1292             : 
    1293             : /**********************************************************************
    1294             :  *                   TABMAPObjCustomPoint::ReadObj()
    1295             :  *
    1296             :  * Read Object information starting after the object id
    1297             :  **********************************************************************/
    1298           6 : int TABMAPObjCustomPoint::ReadObj(TABMAPObjectBlock *poObjBlock)
    1299             : {
    1300           6 :     m_nUnknown_ = poObjBlock->ReadByte();     // ???
    1301           6 :     m_nCustomStyle = poObjBlock->ReadByte();  // 0x01=Show BG, 0x02=Apply Color
    1302             : 
    1303           6 :     poObjBlock->ReadIntCoord(IsCompressedType(), m_nX, m_nY);
    1304             : 
    1305           6 :     m_nSymbolId = poObjBlock->ReadByte();  // Symbol index
    1306           6 :     m_nFontId = poObjBlock->ReadByte();    // Font index
    1307             : 
    1308           6 :     SetMBR(m_nX, m_nY, m_nX, m_nY);
    1309             : 
    1310           6 :     if (CPLGetLastErrorType() == CE_Failure)
    1311           0 :         return -1;
    1312             : 
    1313           6 :     return 0;
    1314             : }
    1315             : 
    1316             : /**********************************************************************
    1317             :  *                   TABMAPObjCustomPoint::WriteObj()
    1318             :  *
    1319             :  * Write Object information with the type+object id
    1320             :  *
    1321             :  * Returns 0 on success, -1 on error.
    1322             :  **********************************************************************/
    1323           2 : int TABMAPObjCustomPoint::WriteObj(TABMAPObjectBlock *poObjBlock)
    1324             : {
    1325             :     // Write object type and id
    1326           2 :     TABMAPObjHdr::WriteObjTypeAndId(poObjBlock);
    1327             : 
    1328           2 :     poObjBlock->WriteByte(m_nUnknown_);     // ???
    1329           2 :     poObjBlock->WriteByte(m_nCustomStyle);  // 0x01=Show BG, 0x02=Apply Color
    1330           2 :     poObjBlock->WriteIntCoord(m_nX, m_nY, IsCompressedType());
    1331             : 
    1332           2 :     poObjBlock->WriteByte(m_nSymbolId);  // Symbol index
    1333           2 :     poObjBlock->WriteByte(m_nFontId);    // Font index
    1334             : 
    1335           2 :     if (CPLGetLastErrorType() == CE_Failure)
    1336           0 :         return -1;
    1337             : 
    1338           2 :     return 0;
    1339             : }
    1340             : 
    1341             : /**********************************************************************
    1342             :  *                   class TABMAPObjRectEllipse
    1343             :  *
    1344             :  **********************************************************************/
    1345             : 
    1346             : /**********************************************************************
    1347             :  *                   TABMAPObjRectEllipse::ReadObj()
    1348             :  *
    1349             :  * Read Object information starting after the object id
    1350             :  **********************************************************************/
    1351          12 : int TABMAPObjRectEllipse::ReadObj(TABMAPObjectBlock *poObjBlock)
    1352             : {
    1353          12 :     if (m_nType == TAB_GEOM_ROUNDRECT || m_nType == TAB_GEOM_ROUNDRECT_C)
    1354             :     {
    1355           4 :         if (IsCompressedType())
    1356             :         {
    1357           0 :             m_nCornerWidth = poObjBlock->ReadInt16();
    1358           0 :             m_nCornerHeight = poObjBlock->ReadInt16();
    1359             :         }
    1360             :         else
    1361             :         {
    1362           4 :             m_nCornerWidth = poObjBlock->ReadInt32();
    1363           4 :             m_nCornerHeight = poObjBlock->ReadInt32();
    1364             :         }
    1365             :     }
    1366             : 
    1367          12 :     poObjBlock->ReadIntCoord(IsCompressedType(), m_nMinX, m_nMinY);
    1368          12 :     poObjBlock->ReadIntCoord(IsCompressedType(), m_nMaxX, m_nMaxY);
    1369             : 
    1370          12 :     m_nPenId = poObjBlock->ReadByte();    // Pen index
    1371          12 :     m_nBrushId = poObjBlock->ReadByte();  // Brush index
    1372             : 
    1373          12 :     if (CPLGetLastErrorType() == CE_Failure)
    1374           0 :         return -1;
    1375             : 
    1376          12 :     return 0;
    1377             : }
    1378             : 
    1379             : /**********************************************************************
    1380             :  *                   TABMAPObjRectEllipse::WriteObj()
    1381             :  *
    1382             :  * Write Object information with the type+object id
    1383             :  *
    1384             :  * Returns 0 on success, -1 on error.
    1385             :  **********************************************************************/
    1386           0 : int TABMAPObjRectEllipse::WriteObj(TABMAPObjectBlock *poObjBlock)
    1387             : {
    1388             :     // Write object type and id
    1389           0 :     TABMAPObjHdr::WriteObjTypeAndId(poObjBlock);
    1390             : 
    1391           0 :     if (m_nType == TAB_GEOM_ROUNDRECT || m_nType == TAB_GEOM_ROUNDRECT_C)
    1392             :     {
    1393           0 :         if (IsCompressedType())
    1394             :         {
    1395           0 :             poObjBlock->WriteInt16(static_cast<GInt16>(m_nCornerWidth));
    1396           0 :             poObjBlock->WriteInt16(static_cast<GInt16>(m_nCornerHeight));
    1397             :         }
    1398             :         else
    1399             :         {
    1400           0 :             poObjBlock->WriteInt32(m_nCornerWidth);
    1401           0 :             poObjBlock->WriteInt32(m_nCornerHeight);
    1402             :         }
    1403             :     }
    1404             : 
    1405           0 :     poObjBlock->WriteIntMBRCoord(m_nMinX, m_nMinY, m_nMaxX, m_nMaxY,
    1406             :                                  IsCompressedType());
    1407             : 
    1408           0 :     poObjBlock->WriteByte(m_nPenId);    // Pen index
    1409           0 :     poObjBlock->WriteByte(m_nBrushId);  // Brush index
    1410             : 
    1411           0 :     if (CPLGetLastErrorType() == CE_Failure)
    1412           0 :         return -1;
    1413             : 
    1414           0 :     return 0;
    1415             : }
    1416             : 
    1417             : /**********************************************************************
    1418             :  *                   class TABMAPObjArc
    1419             :  *
    1420             :  **********************************************************************/
    1421             : 
    1422             : /**********************************************************************
    1423             :  *                   TABMAPObjArc::ReadObj()
    1424             :  *
    1425             :  * Read Object information starting after the object id
    1426             :  **********************************************************************/
    1427           8 : int TABMAPObjArc::ReadObj(TABMAPObjectBlock *poObjBlock)
    1428             : {
    1429           8 :     m_nStartAngle = poObjBlock->ReadInt16();
    1430           8 :     m_nEndAngle = poObjBlock->ReadInt16();
    1431             : 
    1432             :     // An arc is defined by its defining ellipse's MBR:
    1433           8 :     poObjBlock->ReadIntCoord(IsCompressedType(), m_nArcEllipseMinX,
    1434           8 :                              m_nArcEllipseMinY);
    1435           8 :     poObjBlock->ReadIntCoord(IsCompressedType(), m_nArcEllipseMaxX,
    1436           8 :                              m_nArcEllipseMaxY);
    1437             : 
    1438             :     // Read the Arc's actual MBR
    1439           8 :     poObjBlock->ReadIntCoord(IsCompressedType(), m_nMinX, m_nMinY);
    1440           8 :     poObjBlock->ReadIntCoord(IsCompressedType(), m_nMaxX, m_nMaxY);
    1441             : 
    1442           8 :     m_nPenId = poObjBlock->ReadByte();  // Pen index
    1443             : 
    1444           8 :     if (CPLGetLastErrorType() == CE_Failure)
    1445           0 :         return -1;
    1446             : 
    1447           8 :     return 0;
    1448             : }
    1449             : 
    1450             : /**********************************************************************
    1451             :  *                   TABMAPObjArc::WriteObj()
    1452             :  *
    1453             :  * Write Object information with the type+object id
    1454             :  *
    1455             :  * Returns 0 on success, -1 on error.
    1456             :  **********************************************************************/
    1457           0 : int TABMAPObjArc::WriteObj(TABMAPObjectBlock *poObjBlock)
    1458             : {
    1459             :     // Write object type and id
    1460           0 :     TABMAPObjHdr::WriteObjTypeAndId(poObjBlock);
    1461             : 
    1462           0 :     poObjBlock->WriteInt16(static_cast<GInt16>(m_nStartAngle));
    1463           0 :     poObjBlock->WriteInt16(static_cast<GInt16>(m_nEndAngle));
    1464             : 
    1465             :     // An arc is defined by its defining ellipse's MBR:
    1466           0 :     poObjBlock->WriteIntMBRCoord(m_nArcEllipseMinX, m_nArcEllipseMinY,
    1467             :                                  m_nArcEllipseMaxX, m_nArcEllipseMaxY,
    1468             :                                  IsCompressedType());
    1469             : 
    1470             :     // Write the Arc's actual MBR
    1471           0 :     poObjBlock->WriteIntMBRCoord(m_nMinX, m_nMinY, m_nMaxX, m_nMaxY,
    1472             :                                  IsCompressedType());
    1473             : 
    1474           0 :     poObjBlock->WriteByte(m_nPenId);  // Pen index
    1475             : 
    1476           0 :     if (CPLGetLastErrorType() == CE_Failure)
    1477           0 :         return -1;
    1478             : 
    1479           0 :     return 0;
    1480             : }
    1481             : 
    1482             : /**********************************************************************
    1483             :  *                   class TABMAPObjText
    1484             :  *
    1485             :  **********************************************************************/
    1486             : 
    1487             : /**********************************************************************
    1488             :  *                   TABMAPObjText::ReadObj()
    1489             :  *
    1490             :  * Read Object information starting after the object id
    1491             :  **********************************************************************/
    1492           8 : int TABMAPObjText::ReadObj(TABMAPObjectBlock *poObjBlock)
    1493             : {
    1494           8 :     m_nCoordBlockPtr = poObjBlock->ReadInt32();  // String position
    1495           8 :     m_nCoordDataSize = poObjBlock->ReadInt16();  // String length
    1496           8 :     if (m_nCoordDataSize < 0)
    1497             :     {
    1498           0 :         CPLError(CE_Failure, CPLE_AssertionFailed, "m_nCoordDataSize < 0");
    1499           0 :         return -1;
    1500             :     }
    1501           8 :     m_nTextAlignment = poObjBlock->ReadInt16();  // just./spacing/arrow
    1502             : 
    1503           8 :     m_nAngle = poObjBlock->ReadInt16();  // Tenths of degree
    1504             : 
    1505           8 :     m_nFontStyle = poObjBlock->ReadInt16();  // Font style/effect
    1506             : 
    1507           8 :     m_nFGColorR = poObjBlock->ReadByte();
    1508           8 :     m_nFGColorG = poObjBlock->ReadByte();
    1509           8 :     m_nFGColorB = poObjBlock->ReadByte();
    1510             : 
    1511           8 :     m_nBGColorR = poObjBlock->ReadByte();
    1512           8 :     m_nBGColorG = poObjBlock->ReadByte();
    1513           8 :     m_nBGColorB = poObjBlock->ReadByte();
    1514             : 
    1515             :     // Label line end point
    1516           8 :     poObjBlock->ReadIntCoord(IsCompressedType(), m_nLineEndX, m_nLineEndY);
    1517             : 
    1518             :     // Text Height
    1519           8 :     if (IsCompressedType())
    1520           0 :         m_nHeight = poObjBlock->ReadInt16();
    1521             :     else
    1522           8 :         m_nHeight = poObjBlock->ReadInt32();
    1523             : 
    1524             :     // Font name
    1525           8 :     m_nFontId = poObjBlock->ReadByte();  // Font name index
    1526             : 
    1527             :     // MBR after rotation
    1528           8 :     poObjBlock->ReadIntCoord(IsCompressedType(), m_nMinX, m_nMinY);
    1529           8 :     poObjBlock->ReadIntCoord(IsCompressedType(), m_nMaxX, m_nMaxY);
    1530             : 
    1531           8 :     m_nPenId = poObjBlock->ReadByte();  // Pen index
    1532             : 
    1533           8 :     if (CPLGetLastErrorType() == CE_Failure)
    1534           0 :         return -1;
    1535             : 
    1536           8 :     return 0;
    1537             : }
    1538             : 
    1539             : /**********************************************************************
    1540             :  *                   TABMAPObjText::WriteObj()
    1541             :  *
    1542             :  * Write Object information with the type+object id
    1543             :  *
    1544             :  * Returns 0 on success, -1 on error.
    1545             :  **********************************************************************/
    1546           4 : int TABMAPObjText::WriteObj(TABMAPObjectBlock *poObjBlock)
    1547             : {
    1548             :     // Write object type and id
    1549           4 :     TABMAPObjHdr::WriteObjTypeAndId(poObjBlock);
    1550             : 
    1551           4 :     poObjBlock->WriteInt32(m_nCoordBlockPtr);  // String position
    1552           4 :     poObjBlock->WriteInt16(
    1553           4 :         static_cast<GInt16>(m_nCoordDataSize));  // String length
    1554           4 :     poObjBlock->WriteInt16(
    1555           4 :         static_cast<GInt16>(m_nTextAlignment));  // just./spacing/arrow
    1556             : 
    1557           4 :     poObjBlock->WriteInt16(static_cast<GInt16>(m_nAngle));  // Tenths of degree
    1558             : 
    1559           4 :     poObjBlock->WriteInt16(m_nFontStyle);  // Font style/effect
    1560             : 
    1561           4 :     poObjBlock->WriteByte(m_nFGColorR);
    1562           4 :     poObjBlock->WriteByte(m_nFGColorG);
    1563           4 :     poObjBlock->WriteByte(m_nFGColorB);
    1564             : 
    1565           4 :     poObjBlock->WriteByte(m_nBGColorR);
    1566           4 :     poObjBlock->WriteByte(m_nBGColorG);
    1567           4 :     poObjBlock->WriteByte(m_nBGColorB);
    1568             : 
    1569             :     // Label line end point
    1570           4 :     poObjBlock->WriteIntCoord(m_nLineEndX, m_nLineEndY, IsCompressedType());
    1571             : 
    1572             :     // Text Height
    1573           4 :     if (IsCompressedType())
    1574           0 :         poObjBlock->WriteInt16(static_cast<GInt16>(m_nHeight));
    1575             :     else
    1576           4 :         poObjBlock->WriteInt32(m_nHeight);
    1577             : 
    1578             :     // Font name
    1579           4 :     poObjBlock->WriteByte(m_nFontId);  // Font name index
    1580             : 
    1581             :     // MBR after rotation
    1582           4 :     poObjBlock->WriteIntMBRCoord(m_nMinX, m_nMinY, m_nMaxX, m_nMaxY,
    1583             :                                  IsCompressedType());
    1584             : 
    1585           4 :     poObjBlock->WriteByte(m_nPenId);  // Pen index
    1586             : 
    1587           4 :     if (CPLGetLastErrorType() == CE_Failure)
    1588           0 :         return -1;
    1589             : 
    1590           4 :     return 0;
    1591             : }
    1592             : 
    1593             : /**********************************************************************
    1594             :  *                   class TABMAPObjMultiPoint
    1595             :  *
    1596             :  * Applies to PLINE, MULTIPLINE and REGION object types
    1597             :  **********************************************************************/
    1598             : 
    1599             : /**********************************************************************
    1600             :  *                   TABMAPObjMultiPoint::ReadObj()
    1601             :  *
    1602             :  * Read Object information starting after the object id which should
    1603             :  * have been read by TABMAPObjHdr::ReadNextObj() already.
    1604             :  * This function should be called only by TABMAPObjHdr::ReadNextObj().
    1605             :  *
    1606             :  * Returns 0 on success, -1 on error.
    1607             :  **********************************************************************/
    1608           4 : int TABMAPObjMultiPoint::ReadObj(TABMAPObjectBlock *poObjBlock)
    1609             : {
    1610           4 :     m_nCoordBlockPtr = poObjBlock->ReadInt32();
    1611           4 :     m_nNumPoints = poObjBlock->ReadInt32();
    1612             : 
    1613           4 :     const int nPointSize = (IsCompressedType()) ? 2 * 2 : 2 * 4;
    1614           4 :     if (m_nNumPoints < 0 || m_nNumPoints > INT_MAX / nPointSize)
    1615             :     {
    1616           0 :         CPLError(CE_Failure, CPLE_AssertionFailed, "Invalid m_nNumPoints = %d",
    1617             :                  m_nNumPoints);
    1618           0 :         return -1;
    1619             :     }
    1620           4 :     m_nCoordDataSize = m_nNumPoints * nPointSize;
    1621             : 
    1622             : #ifdef TABDUMP
    1623             :     printf("MULTIPOINT: id=%d, type=%d, " /*ok*/
    1624             :            "CoordBlockPtr=%d, CoordDataSize=%d, numPoints=%d\n",
    1625             :            m_nId, m_nType, m_nCoordBlockPtr, m_nCoordDataSize, m_nNumPoints);
    1626             : #endif
    1627             : 
    1628             :     // ?????
    1629           4 :     poObjBlock->ReadInt32();
    1630           4 :     poObjBlock->ReadInt32();
    1631           4 :     poObjBlock->ReadInt32();
    1632           4 :     poObjBlock->ReadByte();
    1633           4 :     poObjBlock->ReadByte();
    1634           4 :     poObjBlock->ReadByte();
    1635             : 
    1636           4 :     if (m_nType == TAB_GEOM_V800_MULTIPOINT ||
    1637           4 :         m_nType == TAB_GEOM_V800_MULTIPOINT_C)
    1638             :     {
    1639             :         /* V800 MULTIPOINTS have another 33 unknown bytes... all zeros */
    1640           0 :         poObjBlock->ReadInt32();
    1641           0 :         poObjBlock->ReadInt32();
    1642           0 :         poObjBlock->ReadInt32();
    1643           0 :         poObjBlock->ReadInt32();
    1644           0 :         poObjBlock->ReadInt32();
    1645           0 :         poObjBlock->ReadInt32();
    1646           0 :         poObjBlock->ReadInt32();
    1647           0 :         poObjBlock->ReadInt32();
    1648           0 :         poObjBlock->ReadByte();
    1649             :     }
    1650             : 
    1651           4 :     m_nSymbolId = poObjBlock->ReadByte();
    1652             : 
    1653             :     // ?????
    1654           4 :     poObjBlock->ReadByte();
    1655             : 
    1656           4 :     if (IsCompressedType())
    1657             :     {
    1658             :         // Region center/label point, relative to compr. coord. origin
    1659             :         // No it is not relative to the Object block center
    1660           4 :         m_nLabelX = poObjBlock->ReadInt16();
    1661           4 :         m_nLabelY = poObjBlock->ReadInt16();
    1662             : 
    1663             :         // Compressed coordinate origin
    1664           4 :         m_nComprOrgX = poObjBlock->ReadInt32();
    1665           4 :         m_nComprOrgY = poObjBlock->ReadInt32();
    1666             : 
    1667           4 :         TABSaturatedAdd(m_nLabelX, m_nComprOrgX);
    1668           4 :         TABSaturatedAdd(m_nLabelY, m_nComprOrgY);
    1669             : 
    1670           4 :         m_nMinX = poObjBlock->ReadInt16();  // Read MBR
    1671           4 :         m_nMinY = poObjBlock->ReadInt16();
    1672           4 :         m_nMaxX = poObjBlock->ReadInt16();
    1673           4 :         m_nMaxY = poObjBlock->ReadInt16();
    1674           4 :         TABSaturatedAdd(m_nMinX, m_nComprOrgX);
    1675           4 :         TABSaturatedAdd(m_nMinY, m_nComprOrgY);
    1676           4 :         TABSaturatedAdd(m_nMaxX, m_nComprOrgX);
    1677           4 :         TABSaturatedAdd(m_nMaxY, m_nComprOrgY);
    1678             :     }
    1679             :     else
    1680             :     {
    1681             :         // Region center/label point
    1682           0 :         m_nLabelX = poObjBlock->ReadInt32();
    1683           0 :         m_nLabelY = poObjBlock->ReadInt32();
    1684             : 
    1685           0 :         m_nMinX = poObjBlock->ReadInt32();  // Read MBR
    1686           0 :         m_nMinY = poObjBlock->ReadInt32();
    1687           0 :         m_nMaxX = poObjBlock->ReadInt32();
    1688           0 :         m_nMaxY = poObjBlock->ReadInt32();
    1689             : 
    1690             :         // Init. Compr. Origin to a default value in case type is ever changed
    1691           0 :         m_nComprOrgX =
    1692           0 :             static_cast<GInt32>((static_cast<GIntBig>(m_nMinX) + m_nMaxX) / 2);
    1693           0 :         m_nComprOrgY =
    1694           0 :             static_cast<GInt32>((static_cast<GIntBig>(m_nMinY) + m_nMaxY) / 2);
    1695             :     }
    1696             : 
    1697           4 :     if (CPLGetLastErrorType() == CE_Failure)
    1698           0 :         return -1;
    1699             : 
    1700           4 :     return 0;
    1701             : }
    1702             : 
    1703             : /**********************************************************************
    1704             :  *                   TABMAPObjMultiPoint::WriteObj()
    1705             :  *
    1706             :  * Write Object information with the type+object id
    1707             :  *
    1708             :  * Returns 0 on success, -1 on error.
    1709             :  **********************************************************************/
    1710           0 : int TABMAPObjMultiPoint::WriteObj(TABMAPObjectBlock *poObjBlock)
    1711             : {
    1712             :     // Write object type and id
    1713           0 :     TABMAPObjHdr::WriteObjTypeAndId(poObjBlock);
    1714             : 
    1715           0 :     poObjBlock->WriteInt32(m_nCoordBlockPtr);
    1716             : 
    1717             :     // Number of points
    1718           0 :     poObjBlock->WriteInt32(m_nNumPoints);
    1719             : 
    1720             :     //  unknown bytes
    1721           0 :     poObjBlock->WriteZeros(15);
    1722             : 
    1723           0 :     if (m_nType == TAB_GEOM_V800_MULTIPOINT ||
    1724           0 :         m_nType == TAB_GEOM_V800_MULTIPOINT_C)
    1725             :     {
    1726             :         /* V800 MULTIPOINTS have another 33 unknown bytes... all zeros */
    1727           0 :         poObjBlock->WriteZeros(33);
    1728             :     }
    1729             : 
    1730             :     // Symbol Id
    1731           0 :     poObjBlock->WriteByte(m_nSymbolId);
    1732             : 
    1733             :     // ????
    1734           0 :     poObjBlock->WriteByte(0);
    1735             : 
    1736             :     // MBR
    1737           0 :     if (IsCompressedType())
    1738             :     {
    1739             :         // Region center/label point, relative to compr. coord. origin
    1740             :         // No it is not relative to the Object block center
    1741           0 :         poObjBlock->WriteInt16(TABInt16Diff(m_nLabelX, m_nComprOrgX));
    1742           0 :         poObjBlock->WriteInt16(TABInt16Diff(m_nLabelY, m_nComprOrgY));
    1743             : 
    1744           0 :         poObjBlock->WriteInt32(m_nComprOrgX);
    1745           0 :         poObjBlock->WriteInt32(m_nComprOrgY);
    1746             : 
    1747             :         // MBR relative to object origin (and not object block center)
    1748           0 :         poObjBlock->WriteInt16(TABInt16Diff(m_nMinX, m_nComprOrgX));
    1749           0 :         poObjBlock->WriteInt16(TABInt16Diff(m_nMinY, m_nComprOrgY));
    1750           0 :         poObjBlock->WriteInt16(TABInt16Diff(m_nMaxX, m_nComprOrgX));
    1751           0 :         poObjBlock->WriteInt16(TABInt16Diff(m_nMaxY, m_nComprOrgY));
    1752             :     }
    1753             :     else
    1754             :     {
    1755             :         // Region center/label point
    1756           0 :         poObjBlock->WriteInt32(m_nLabelX);
    1757           0 :         poObjBlock->WriteInt32(m_nLabelY);
    1758             : 
    1759           0 :         poObjBlock->WriteInt32(m_nMinX);
    1760           0 :         poObjBlock->WriteInt32(m_nMinY);
    1761           0 :         poObjBlock->WriteInt32(m_nMaxX);
    1762           0 :         poObjBlock->WriteInt32(m_nMaxY);
    1763             :     }
    1764             : 
    1765           0 :     if (CPLGetLastErrorType() == CE_Failure)
    1766           0 :         return -1;
    1767             : 
    1768           0 :     return 0;
    1769             : }
    1770             : 
    1771             : /**********************************************************************
    1772             :  *                   class TABMAPObjCollection
    1773             :  *
    1774             :  **********************************************************************/
    1775             : 
    1776             : /**********************************************************************
    1777             :  *                   TABMAPObjCollection::ReadObj()
    1778             :  *
    1779             :  * Read Object information starting after the object id which should
    1780             :  * have been read by TABMAPObjHdr::ReadNextObj() already.
    1781             :  * This function should be called only by TABMAPObjHdr::ReadNextObj().
    1782             :  *
    1783             :  * Returns 0 on success, -1 on error.
    1784             :  **********************************************************************/
    1785           4 : int TABMAPObjCollection::ReadObj(TABMAPObjectBlock *poObjBlock)
    1786             : {
    1787           4 :     int SIZE_OF_REGION_PLINE_MINI_HDR = 24, SIZE_OF_MPOINT_MINI_HDR = 24;
    1788           4 :     int nVersion = TAB_GEOM_GET_VERSION(m_nType);
    1789             : 
    1790             :     /* Figure the size of the mini-header that we find for each of the
    1791             :      * 3 optional components (center x,y and mbr)
    1792             :      */
    1793           4 :     if (IsCompressedType())
    1794             :     {
    1795             :         /* 6 * int16 */
    1796           4 :         SIZE_OF_REGION_PLINE_MINI_HDR = SIZE_OF_MPOINT_MINI_HDR = 12;
    1797             :     }
    1798             :     else
    1799             :     {
    1800             :         /* 6 * int32 */
    1801           0 :         SIZE_OF_REGION_PLINE_MINI_HDR = SIZE_OF_MPOINT_MINI_HDR = 24;
    1802             :     }
    1803             : 
    1804           4 :     if (nVersion >= 800)
    1805             :     {
    1806             :         /* extra 4 bytes for num_segments in Region/Pline mini-headers */
    1807           0 :         SIZE_OF_REGION_PLINE_MINI_HDR += 4;
    1808             :     }
    1809             : 
    1810           4 :     m_nCoordBlockPtr = poObjBlock->ReadInt32();   // pointer into coord block
    1811           4 :     m_nNumMultiPoints = poObjBlock->ReadInt32();  // no. points in multi point
    1812           4 :     m_nRegionDataSize =
    1813           4 :         poObjBlock->ReadInt32();  // size of region data inc. section hdrs
    1814           4 :     m_nPolylineDataSize =
    1815           4 :         poObjBlock->ReadInt32();  // size of multipline data inc. section hdrs
    1816             : 
    1817           4 :     if (m_nRegionDataSize < 0)
    1818             :     {
    1819           0 :         CPLError(CE_Failure, CPLE_AssertionFailed, "Invalid m_nRegionDataSize");
    1820           0 :         return -1;
    1821             :     }
    1822             : 
    1823           4 :     if (m_nPolylineDataSize < 0)
    1824             :     {
    1825           0 :         CPLError(CE_Failure, CPLE_AssertionFailed, "Invalid m_nRegionDataSize");
    1826           0 :         return -1;
    1827             :     }
    1828             : 
    1829           4 :     if (nVersion < 800)
    1830             :     {
    1831             :         // Num Region/Pline section headers (int16 in V650)
    1832           4 :         m_nNumRegSections = poObjBlock->ReadInt16();
    1833           4 :         m_nNumPLineSections = poObjBlock->ReadInt16();
    1834             :     }
    1835             :     else
    1836             :     {
    1837             :         // Num Region/Pline section headers (int32 in V800)
    1838           0 :         m_nNumRegSections = poObjBlock->ReadInt32();
    1839           0 :         m_nNumPLineSections = poObjBlock->ReadInt32();
    1840             :     }
    1841             : 
    1842           4 :     const int nPointSize = (IsCompressedType()) ? 2 * 2 : 2 * 4;
    1843           4 :     if (m_nNumMultiPoints < 0 || m_nNumMultiPoints > INT_MAX / nPointSize)
    1844             :     {
    1845           0 :         CPLError(CE_Failure, CPLE_AssertionFailed, "Invalid m_nNumMultiPoints");
    1846           0 :         return -1;
    1847             :     }
    1848             : 
    1849           4 :     m_nMPointDataSize = m_nNumMultiPoints * nPointSize;
    1850             : 
    1851             :     /* NB. MapInfo counts 2 extra bytes per Region and Pline section header
    1852             :      * in the RegionDataSize and PolylineDataSize values but those 2 extra
    1853             :      * bytes are not present in the section hdr (possibly due to an alignment
    1854             :      * to a 4 byte boundary in memory in MapInfo?). The real data size in
    1855             :      * the CoordBlock is actually 2 bytes shorter per section header than
    1856             :      * what is written in RegionDataSize and PolylineDataSize values.
    1857             :      *
    1858             :      * We'll adjust the values in memory to be the corrected values.
    1859             :      */
    1860           4 :     if (m_nNumRegSections < 0 || m_nNumRegSections > INT_MAX / 2 ||
    1861           4 :         m_nRegionDataSize < 2 * m_nNumRegSections)
    1862             :     {
    1863           0 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    1864             :                  "Invalid m_nNumRegSections / m_nRegionDataSize");
    1865           0 :         return -1;
    1866             :     }
    1867           4 :     m_nRegionDataSize = m_nRegionDataSize - (2 * m_nNumRegSections);
    1868             : 
    1869           4 :     if (m_nNumPLineSections < 0 || m_nNumPLineSections > INT_MAX / 2 ||
    1870           4 :         m_nPolylineDataSize < 2 * m_nNumPLineSections)
    1871             :     {
    1872           0 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    1873             :                  "Invalid m_nNumPLineSections / m_nPolylineDataSize");
    1874           0 :         return -1;
    1875             :     }
    1876           4 :     m_nPolylineDataSize = m_nPolylineDataSize - (2 * m_nNumPLineSections);
    1877             : 
    1878             :     /* Compute total coord block data size, required when splitting blocks */
    1879           4 :     m_nCoordDataSize = 0;
    1880             : 
    1881           4 :     if (m_nNumRegSections > 0)
    1882             :     {
    1883           4 :         if (m_nRegionDataSize > INT_MAX - SIZE_OF_REGION_PLINE_MINI_HDR ||
    1884           4 :             m_nCoordDataSize >
    1885           4 :                 INT_MAX - (SIZE_OF_REGION_PLINE_MINI_HDR + m_nRegionDataSize))
    1886             :         {
    1887           0 :             CPLError(CE_Failure, CPLE_AssertionFailed,
    1888             :                      "Invalid m_nCoordDataSize / m_nRegionDataSize");
    1889           0 :             return -1;
    1890             :         }
    1891           4 :         m_nCoordDataSize += SIZE_OF_REGION_PLINE_MINI_HDR + m_nRegionDataSize;
    1892             :     }
    1893           4 :     if (m_nNumPLineSections > 0)
    1894             :     {
    1895           4 :         if (m_nPolylineDataSize > INT_MAX - SIZE_OF_REGION_PLINE_MINI_HDR ||
    1896           4 :             m_nCoordDataSize >
    1897           4 :                 INT_MAX - (SIZE_OF_REGION_PLINE_MINI_HDR + m_nPolylineDataSize))
    1898             :         {
    1899           0 :             CPLError(CE_Failure, CPLE_AssertionFailed,
    1900             :                      "Invalid m_nCoordDataSize / m_nPolylineDataSize");
    1901           0 :             return -1;
    1902             :         }
    1903           4 :         m_nCoordDataSize += SIZE_OF_REGION_PLINE_MINI_HDR + m_nPolylineDataSize;
    1904             :     }
    1905           4 :     if (m_nNumMultiPoints > 0)
    1906             :     {
    1907           4 :         if (m_nMPointDataSize > INT_MAX - SIZE_OF_MPOINT_MINI_HDR ||
    1908           4 :             m_nCoordDataSize >
    1909           4 :                 INT_MAX - (SIZE_OF_MPOINT_MINI_HDR + m_nMPointDataSize))
    1910             :         {
    1911           0 :             CPLError(CE_Failure, CPLE_AssertionFailed,
    1912             :                      "Invalid m_nCoordDataSize / m_nMPointDataSize");
    1913           0 :             return -1;
    1914             :         }
    1915           4 :         m_nCoordDataSize += SIZE_OF_MPOINT_MINI_HDR + m_nMPointDataSize;
    1916             :     }
    1917             : 
    1918             : #ifdef TABDUMP
    1919             :     printf("COLLECTION: id=%d, type=%d (0x%x), " /*ok*/
    1920             :            "CoordBlockPtr=%d, numRegionSections=%d (size=%d+%d), "
    1921             :            "numPlineSections=%d (size=%d+%d), numPoints=%d (size=%d+%d)\n",
    1922             :            m_nId, m_nType, m_nType, m_nCoordBlockPtr, m_nNumRegSections,
    1923             :            m_nRegionDataSize, SIZE_OF_REGION_PLINE_MINI_HDR,
    1924             :            m_nNumPLineSections, m_nPolylineDataSize,
    1925             :            SIZE_OF_REGION_PLINE_MINI_HDR, m_nNumMultiPoints, m_nMPointDataSize,
    1926             :            SIZE_OF_MPOINT_MINI_HDR);
    1927             : #endif
    1928             : 
    1929           4 :     if (nVersion >= 800)
    1930             :     {
    1931             :         // Extra byte in V800 files... value always 4???
    1932           0 :         int nValue = poObjBlock->ReadByte();
    1933           0 :         if (nValue != 4)
    1934             :         {
    1935           0 :             CPLError(CE_Failure, CPLE_AssertionFailed,
    1936             :                      "TABMAPObjCollection::ReadObj(): Byte 29 in Collection "
    1937             :                      "object header not equal to 4 as expected. Value is %d. "
    1938             :                      "Please report this error to the MITAB list so that "
    1939             :                      "MITAB can be extended to support this case.",
    1940             :                      nValue);
    1941             :             // We don't return right away, the error should be caught at the
    1942             :             // end of this function.
    1943             :         }
    1944             :     }
    1945             : 
    1946             :     // ??? All zeros ???
    1947           4 :     poObjBlock->ReadInt32();
    1948           4 :     poObjBlock->ReadInt32();
    1949           4 :     poObjBlock->ReadInt32();
    1950           4 :     poObjBlock->ReadByte();
    1951           4 :     poObjBlock->ReadByte();
    1952           4 :     poObjBlock->ReadByte();
    1953             : 
    1954           4 :     m_nMultiPointSymbolId = poObjBlock->ReadByte();
    1955             : 
    1956           4 :     poObjBlock->ReadByte();  // ???
    1957           4 :     m_nRegionPenId = poObjBlock->ReadByte();
    1958           4 :     m_nPolylinePenId = poObjBlock->ReadByte();
    1959           4 :     m_nRegionBrushId = poObjBlock->ReadByte();
    1960             : 
    1961           4 :     if (IsCompressedType())
    1962             :     {
    1963             : #ifdef TABDUMP
    1964             :         printf("COLLECTION: READING ComprOrg @ %d\n", /*ok*/
    1965             :                poObjBlock->GetCurAddress());
    1966             : #endif
    1967             :         // Compressed coordinate origin
    1968           4 :         m_nComprOrgX = poObjBlock->ReadInt32();
    1969           4 :         m_nComprOrgY = poObjBlock->ReadInt32();
    1970             : 
    1971           4 :         m_nMinX = poObjBlock->ReadInt16();  // Read MBR
    1972           4 :         m_nMinY = poObjBlock->ReadInt16();
    1973           4 :         m_nMaxX = poObjBlock->ReadInt16();
    1974           4 :         m_nMaxY = poObjBlock->ReadInt16();
    1975           4 :         TABSaturatedAdd(m_nMinX, m_nComprOrgX);
    1976           4 :         TABSaturatedAdd(m_nMinY, m_nComprOrgY);
    1977           4 :         TABSaturatedAdd(m_nMaxX, m_nComprOrgX);
    1978           4 :         TABSaturatedAdd(m_nMaxY, m_nComprOrgY);
    1979             : #ifdef TABDUMP
    1980             :         printf("COLLECTION: ComprOrgX,Y= (%d,%d)\n", /*ok*/
    1981             :                m_nComprOrgX, m_nComprOrgY);
    1982             : #endif
    1983             :     }
    1984             :     else
    1985             :     {
    1986           0 :         m_nMinX = poObjBlock->ReadInt32();  // Read MBR
    1987           0 :         m_nMinY = poObjBlock->ReadInt32();
    1988           0 :         m_nMaxX = poObjBlock->ReadInt32();
    1989           0 :         m_nMaxY = poObjBlock->ReadInt32();
    1990             : 
    1991             :         // Init. Compr. Origin to a default value in case type is ever changed
    1992           0 :         m_nComprOrgX =
    1993           0 :             static_cast<GInt32>((static_cast<GIntBig>(m_nMinX) + m_nMaxX) / 2);
    1994           0 :         m_nComprOrgY =
    1995           0 :             static_cast<GInt32>((static_cast<GIntBig>(m_nMinY) + m_nMaxY) / 2);
    1996             :     }
    1997             : 
    1998           4 :     if (CPLGetLastErrorType() == CE_Failure)
    1999           0 :         return -1;
    2000             : 
    2001           4 :     return 0;
    2002             : }
    2003             : 
    2004             : /**********************************************************************
    2005             :  *                   TABMAPObjCollection::WriteObj()
    2006             :  *
    2007             :  * Write Object information with the type+object id
    2008             :  *
    2009             :  * Returns 0 on success, -1 on error.
    2010             :  **********************************************************************/
    2011           0 : int TABMAPObjCollection::WriteObj(TABMAPObjectBlock *poObjBlock)
    2012             : {
    2013             :     // Write object type and id
    2014           0 :     TABMAPObjHdr::WriteObjTypeAndId(poObjBlock);
    2015             : 
    2016           0 :     int nVersion = TAB_GEOM_GET_VERSION(m_nType);
    2017             : 
    2018             :     /* NB. MapInfo counts 2 extra bytes per Region and Pline section header
    2019             :      * in the RegionDataSize and PolylineDataSize values but those 2 extra
    2020             :      * bytes are not present in the section hdr (possibly due to an alignment
    2021             :      * to a 4 byte boundary in memory in MapInfo?). The real data size in
    2022             :      * the CoordBlock is actually 2 bytes shorter per section header than
    2023             :      * what is written in RegionDataSize and PolylineDataSize values.
    2024             :      *
    2025             :      * The values in memory are the corrected values so we need to add 2 bytes
    2026             :      * per section header in the values that we write on disk to emulate
    2027             :      * MapInfo's behavior.
    2028             :      */
    2029           0 :     GInt32 nRegionDataSizeMI = m_nRegionDataSize + (2 * m_nNumRegSections);
    2030           0 :     GInt32 nPolylineDataSizeMI =
    2031           0 :         m_nPolylineDataSize + (2 * m_nNumPLineSections);
    2032             : 
    2033           0 :     poObjBlock->WriteInt32(m_nCoordBlockPtr);   // pointer into coord block
    2034           0 :     poObjBlock->WriteInt32(m_nNumMultiPoints);  // no. points in multi point
    2035           0 :     poObjBlock->WriteInt32(
    2036             :         nRegionDataSizeMI);  // size of region data inc. section hdrs
    2037           0 :     poObjBlock->WriteInt32(
    2038             :         nPolylineDataSizeMI);  // size of Mpolyline data inc. section hdrs
    2039             : 
    2040           0 :     if (nVersion < 800)
    2041             :     {
    2042             :         // Num Region/Pline section headers (int16 in V650)
    2043           0 :         poObjBlock->WriteInt16(static_cast<GInt16>(m_nNumRegSections));
    2044           0 :         poObjBlock->WriteInt16(static_cast<GInt16>(m_nNumPLineSections));
    2045             :     }
    2046             :     else
    2047             :     {
    2048             :         // Num Region/Pline section headers (int32 in V800)
    2049           0 :         poObjBlock->WriteInt32(m_nNumRegSections);
    2050           0 :         poObjBlock->WriteInt32(m_nNumPLineSections);
    2051             :     }
    2052             : 
    2053           0 :     if (nVersion >= 800)
    2054             :     {
    2055             :         // Extra byte in V800 files... value always 4???
    2056           0 :         poObjBlock->WriteByte(4);
    2057             :     }
    2058             : 
    2059             :     // Unknown data ?????
    2060           0 :     poObjBlock->WriteInt32(0);
    2061           0 :     poObjBlock->WriteInt32(0);
    2062           0 :     poObjBlock->WriteInt32(0);
    2063           0 :     poObjBlock->WriteByte(0);
    2064           0 :     poObjBlock->WriteByte(0);
    2065           0 :     poObjBlock->WriteByte(0);
    2066             : 
    2067           0 :     poObjBlock->WriteByte(m_nMultiPointSymbolId);
    2068             : 
    2069           0 :     poObjBlock->WriteByte(0);
    2070           0 :     poObjBlock->WriteByte(m_nRegionPenId);
    2071           0 :     poObjBlock->WriteByte(m_nPolylinePenId);
    2072           0 :     poObjBlock->WriteByte(m_nRegionBrushId);
    2073             : 
    2074           0 :     if (IsCompressedType())
    2075             :     {
    2076             : #ifdef TABDUMP
    2077             :         printf("COLLECTION: WRITING ComprOrgX,Y= (%d,%d) @ %d\n", /*ok*/
    2078             :                m_nComprOrgX, m_nComprOrgY, poObjBlock->GetCurAddress());
    2079             : #endif
    2080             :         // Compressed coordinate origin
    2081           0 :         poObjBlock->WriteInt32(m_nComprOrgX);
    2082           0 :         poObjBlock->WriteInt32(m_nComprOrgY);
    2083             : 
    2084           0 :         poObjBlock->WriteInt16(TABInt16Diff(m_nMinX, m_nComprOrgX));  // MBR
    2085           0 :         poObjBlock->WriteInt16(TABInt16Diff(m_nMinY, m_nComprOrgY));
    2086           0 :         poObjBlock->WriteInt16(TABInt16Diff(m_nMaxX, m_nComprOrgX));
    2087           0 :         poObjBlock->WriteInt16(TABInt16Diff(m_nMaxY, m_nComprOrgY));
    2088             :     }
    2089             :     else
    2090             :     {
    2091           0 :         poObjBlock->WriteInt32(m_nMinX);  // MBR
    2092           0 :         poObjBlock->WriteInt32(m_nMinY);
    2093           0 :         poObjBlock->WriteInt32(m_nMaxX);
    2094           0 :         poObjBlock->WriteInt32(m_nMaxY);
    2095             :     }
    2096             : 
    2097           0 :     if (CPLGetLastErrorType() == CE_Failure)
    2098           0 :         return -1;
    2099             : 
    2100           0 :     return 0;
    2101             : }

Generated by: LCOV version 1.14