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: 582 819 71.1 %
Date: 2025-06-17 00:08:44 Functions: 42 47 89.4 %

          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       39330 : 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       39330 :       m_nCurObjectId(0), m_nCurObjectType(TAB_GEOM_UNSET), m_bLockCenter(FALSE)
      46             : {
      47       39330 : }
      48             : 
      49             : /**********************************************************************
      50             :  *                   TABMAPObjectBlock::~TABMAPObjectBlock()
      51             :  *
      52             :  * Destructor.
      53             :  **********************************************************************/
      54      117990 : TABMAPObjectBlock::~TABMAPObjectBlock()
      55             : {
      56             :     // TODO(schwehr): Why set these?  Should remove.
      57       39330 :     m_nMinX = 1000000000;
      58       39330 :     m_nMinY = 1000000000;
      59       39330 :     m_nMaxX = -1000000000;
      60       39330 :     m_nMaxY = -1000000000;
      61       78660 : }
      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       47346 : 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       47346 :     const int nStatus = TABRawBinBlock::InitBlockFromData(
      82             :         pabyBuf, nBlockSize, nSizeUsed, bMakeCopy, fpSrc, nOffset);
      83       47346 :     if (nStatus != 0)
      84           0 :         return nStatus;
      85             : 
      86             :     /*-----------------------------------------------------------------
      87             :      * Validate block type
      88             :      *----------------------------------------------------------------*/
      89       47346 :     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       47346 :     GotoByteInBlock(0x002);
     103       47346 :     m_numDataBytes = ReadInt16(); /* Excluding 4 bytes header */
     104       47346 :     if (m_numDataBytes < 0 ||
     105       47346 :         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       47346 :     m_nCenterX = ReadInt32();
     117       47346 :     m_nCenterY = ReadInt32();
     118             : 
     119       47346 :     m_nFirstCoordBlock = ReadInt32();
     120       47346 :     m_nLastCoordBlock = ReadInt32();
     121             : 
     122       47346 :     m_nCurObjectOffset = -1;
     123       47346 :     m_nCurObjectId = -1;
     124       47346 :     m_nCurObjectType = TAB_GEOM_UNSET;
     125             : 
     126       47346 :     m_nMinX = 1000000000;
     127       47346 :     m_nMinY = 1000000000;
     128       47346 :     m_nMaxX = -1000000000;
     129       47346 :     m_nMaxY = -1000000000;
     130       47346 :     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       47346 :     m_nSizeUsed = m_numDataBytes + MAP_OBJECT_HEADER_SIZE;
     137             : 
     138       47346 :     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         270 : void TABMAPObjectBlock::ClearObjects()
     148             : {
     149         270 :     GotoByteInBlock(MAP_OBJECT_HEADER_SIZE);
     150         270 :     WriteZeros(m_nBlockSize - MAP_OBJECT_HEADER_SIZE);
     151         270 :     GotoByteInBlock(MAP_OBJECT_HEADER_SIZE);
     152         270 :     m_nSizeUsed = MAP_OBJECT_HEADER_SIZE;
     153         270 :     m_bModified = TRUE;
     154         270 : }
     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       11816 : void TABMAPObjectBlock::LockCenter()
     165             : {
     166       11816 :     m_bLockCenter = TRUE;
     167       11816 : }
     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         254 : void TABMAPObjectBlock::SetCenterFromOtherBlock(
     177             :     TABMAPObjectBlock *poOtherObjBlock)
     178             : {
     179         254 :     m_nCenterX = poOtherObjBlock->m_nCenterX;
     180         254 :     m_nCenterY = poOtherObjBlock->m_nCenterY;
     181         254 :     LockCenter();
     182         254 : }
     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      427591 : int TABMAPObjectBlock::AdvanceToNextObject(TABMAPHeaderBlock *poHeader)
     199             : 
     200             : {
     201      427591 :     if (m_nCurObjectId == -1)
     202             :     {
     203       15819 :         m_nCurObjectOffset = 20;
     204             :     }
     205             :     else
     206             :     {
     207      411772 :         m_nCurObjectOffset += poHeader->GetMapObjectSize(m_nCurObjectType);
     208             :     }
     209             : 
     210      427591 :     if (m_nCurObjectOffset + 5 < m_numDataBytes + 20)
     211             :     {
     212      412272 :         GotoByteInBlock(m_nCurObjectOffset);
     213      412272 :         const GByte byVal = ReadByte();
     214      412272 :         if (TABMAPFile::IsValidObjType(byVal))
     215             :         {
     216      412272 :             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       15319 :         m_nCurObjectType = TAB_GEOM_UNSET;
     232             :     }
     233             : 
     234      427591 :     if (m_nCurObjectType <= 0 || m_nCurObjectType >= TAB_GEOM_MAX_TYPE)
     235             :     {
     236       15319 :         m_nCurObjectType = TAB_GEOM_UNSET;
     237       15319 :         m_nCurObjectId = -1;
     238       15319 :         m_nCurObjectOffset = -1;
     239             :     }
     240             :     else
     241             :     {
     242      412272 :         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      412272 :         if ((static_cast<GUInt32>(m_nCurObjectId) & 0xC0000000U) != 0)
     249             :         {
     250       16497 :             m_nCurObjectId = AdvanceToNextObject(poHeader);
     251             :         }
     252             :     }
     253             : 
     254      427591 :     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       17016 : int TABMAPObjectBlock::CommitToFile()
     271             : {
     272       17016 :     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       17016 :     if (!m_bModified)
     284         383 :         return 0;
     285             : 
     286             :     /*-----------------------------------------------------------------
     287             :      * Make sure 20 bytes block header is up to date.
     288             :      *----------------------------------------------------------------*/
     289       16633 :     GotoByteInBlock(0x000);
     290             : 
     291       16633 :     WriteInt16(TABMAP_OBJECT_BLOCK);  // Block type code
     292       16633 :     m_numDataBytes = m_nSizeUsed - MAP_OBJECT_HEADER_SIZE;
     293       16633 :     CPLAssert(m_numDataBytes >= 0 && m_numDataBytes < 32768);
     294       16633 :     WriteInt16(static_cast<GInt16>(m_numDataBytes));  // num. bytes used
     295             : 
     296       16633 :     WriteInt32(m_nCenterX);
     297       16633 :     WriteInt32(m_nCenterY);
     298             : 
     299       16633 :     WriteInt32(m_nFirstCoordBlock);
     300       16633 :     WriteInt32(m_nLastCoordBlock);
     301             : 
     302       16633 :     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       16633 :     if (nStatus == 0)
     309             :     {
     310             : #ifdef DEBUG_VERBOSE
     311             :         CPLDebug("MITAB", "Committing OBJECT block to offset %d",
     312             :                  m_nFileOffset);
     313             : #endif
     314       16633 :         nStatus = TABRawBinBlock::CommitToFile();
     315             :     }
     316             : 
     317       16633 :     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        1982 : int TABMAPObjectBlock::InitNewBlock(VSILFILE *fpSrc, int nBlockSize,
     336             :                                     int nFileOffset /* = 0*/)
     337             : {
     338             :     /*-----------------------------------------------------------------
     339             :      * Start with the default initialization
     340             :      *----------------------------------------------------------------*/
     341        1982 :     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        1982 :     m_nMinX = 1000000000;
     350        1982 :     m_nMaxX = -1000000000;
     351        1982 :     m_nMinY = 1000000000;
     352        1982 :     m_nMaxY = -1000000000;
     353             : 
     354             :     // Reset current object refs
     355        1982 :     m_nCurObjectId = -1;
     356        1982 :     m_nCurObjectOffset = -1;
     357        1982 :     m_nCurObjectType = TAB_GEOM_UNSET;
     358             : 
     359        1982 :     m_numDataBytes = 0; /* Data size excluding header */
     360        1982 :     m_nCenterX = 0;
     361        1982 :     m_nCenterY = 0;
     362        1982 :     m_nFirstCoordBlock = 0;
     363        1982 :     m_nLastCoordBlock = 0;
     364             : 
     365        1982 :     if (m_eAccess != TABRead && nFileOffset != 0)
     366             :     {
     367         691 :         GotoByteInBlock(0x000);
     368             : 
     369         691 :         WriteInt16(TABMAP_OBJECT_BLOCK);  // Block type code
     370         691 :         WriteInt16(0);                    // num. bytes used, excluding header
     371             : 
     372             :         // MBR center here... will be written in CommitToFile()
     373         691 :         WriteInt32(0);
     374         691 :         WriteInt32(0);
     375             : 
     376             :         // First/last coord block ref... will be written in CommitToFile()
     377         691 :         WriteInt32(0);
     378         691 :         WriteInt32(0);
     379             :     }
     380             : 
     381        1982 :     if (CPLGetLastErrorType() == CE_Failure)
     382           0 :         return -1;
     383             : 
     384        1982 :     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      545238 : int TABMAPObjectBlock::ReadIntCoord(GBool bCompressed, GInt32 &nX, GInt32 &nY)
     401             : {
     402      545238 :     if (bCompressed)
     403             :     {
     404       13886 :         nX = ReadInt16();
     405       13886 :         nY = ReadInt16();
     406       13886 :         TABSaturatedAdd(nX, m_nCenterX);
     407       13886 :         TABSaturatedAdd(nY, m_nCenterY);
     408             :     }
     409             :     else
     410             :     {
     411      531352 :         nX = ReadInt32();
     412      531352 :         nY = ReadInt32();
     413             :     }
     414             : 
     415      545238 :     if (CPLGetLastErrorType() == CE_Failure)
     416           0 :         return -1;
     417             : 
     418      545238 :     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       25692 : int TABMAPObjectBlock::WriteIntCoord(GInt32 nX, GInt32 nY,
     435             :                                      GBool bCompressed /*=FALSE*/)
     436             : {
     437             : 
     438             :     /*-----------------------------------------------------------------
     439             :      * Write coords to the file.
     440             :      *----------------------------------------------------------------*/
     441       26349 :     if ((!bCompressed && (WriteInt32(nX) != 0 || WriteInt32(nY) != 0)) ||
     442         657 :         (bCompressed &&
     443         657 :          (WriteInt16(static_cast<GInt16>(nX - m_nCenterX)) != 0 ||
     444         657 :           WriteInt16(static_cast<GInt16>(nY - m_nCenterY)) != 0)))
     445             :     {
     446           0 :         return -1;
     447             :     }
     448             : 
     449       25692 :     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       52346 : int TABMAPObjectBlock::UpdateMBR(GInt32 nX, GInt32 nY)
     492             : {
     493             : 
     494       52346 :     if (nX < m_nMinX)
     495        1373 :         m_nMinX = nX;
     496       52346 :     if (nX > m_nMaxX)
     497        3755 :         m_nMaxX = nX;
     498             : 
     499       52346 :     if (nY < m_nMinY)
     500        1070 :         m_nMinY = nY;
     501       52346 :     if (nY > m_nMaxY)
     502        3400 :         m_nMaxY = nY;
     503             : 
     504       52346 :     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       52346 :     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         771 : 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         771 :     if (m_nFirstCoordBlock == 0)
     529          61 :         m_nFirstCoordBlock = nNewBlockAddress;
     530             : 
     531         771 :     m_nLastCoordBlock = nNewBlockAddress;
     532         771 :     m_bModified = TRUE;
     533         771 : }
     534             : 
     535             : /**********************************************************************
     536             :  *                   TABMAPObjectBlock::SetMBR()
     537             :  *
     538             :  * Set the MBR for the current block.
     539             :  **********************************************************************/
     540       48474 : void TABMAPObjectBlock::SetMBR(GInt32 nXMin, GInt32 nYMin, GInt32 nXMax,
     541             :                                GInt32 nYMax)
     542             : {
     543       48474 :     m_nMinX = nXMin;
     544       48474 :     m_nMinY = nYMin;
     545       48474 :     m_nMaxX = nXMax;
     546       48474 :     m_nMaxY = nYMax;
     547             : 
     548       48474 :     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       48474 : }
     556             : 
     557             : /**********************************************************************
     558             :  *                   TABMAPObjectBlock::GetMBR()
     559             :  *
     560             :  * Return the MBR for the current block.
     561             :  **********************************************************************/
     562       66102 : void TABMAPObjectBlock::GetMBR(GInt32 &nXMin, GInt32 &nYMin, GInt32 &nXMax,
     563             :                                GInt32 &nYMax)
     564             : {
     565       66102 :     nXMin = m_nMinX;
     566       66102 :     nYMin = m_nMinY;
     567       66102 :     nXMax = m_nMaxX;
     568       66102 :     nYMax = m_nMaxY;
     569       66102 : }
     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       26173 : int TABMAPObjectBlock::PrepareNewObject(TABMAPObjHdr *poObjHdr)
     581             : {
     582       26173 :     int nStartAddress = 0;
     583             : 
     584             :     // Nothing to do for NONE objects
     585       26173 :     if (poObjHdr->m_nType == TAB_GEOM_NONE)
     586             :     {
     587           0 :         return 0;
     588             :     }
     589             : 
     590             :     // Maintain MBR of this object block.
     591       26173 :     UpdateMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY);
     592       26173 :     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       26173 :     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       26173 :     GetMBR(nXMin, nYMin, nXMax, nYMax);
     604       26173 :     int bLockCenter = m_bLockCenter;
     605       26173 :     GotoByteInFile(nStartAddress);
     606       26173 :     m_bLockCenter = bLockCenter;
     607       26173 :     SetMBR(nXMin, nYMin, nXMax, nYMax);
     608       26173 :     m_nCurObjectOffset = nStartAddress - GetStartAddress();
     609             : 
     610       26173 :     m_nCurObjectType = poObjHdr->m_nType;
     611       26173 :     m_nCurObjectId = poObjHdr->m_nId;
     612             : 
     613       26173 :     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       26173 : int TABMAPObjectBlock::CommitNewObject(TABMAPObjHdr *poObjHdr)
     627             : {
     628       26173 :     int nStatus = 0;
     629             : 
     630       26173 :     CPLAssert(poObjHdr->m_nType != TAB_GEOM_NONE);
     631             : 
     632             :     // Nothing to do for NONE objects
     633       26173 :     if (poObjHdr->m_nType == TAB_GEOM_NONE)
     634             :     {
     635           0 :         return 0;
     636             :     }
     637             : 
     638       26173 :     CPLAssert(m_nCurObjectId == poObjHdr->m_nId);
     639       26173 :     GotoByteInBlock(m_nCurObjectOffset);
     640             : 
     641       26173 :     nStatus = poObjHdr->WriteObj(this);
     642             : 
     643       26173 :     if (nStatus == 0)
     644       26173 :         m_numDataBytes = m_nSizeUsed - MAP_OBJECT_HEADER_SIZE;
     645             : 
     646       26173 :     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             : TABMAPObjHdr::~TABMAPObjHdr() = default;
     731             : 
     732             : /**********************************************************************
     733             :  *                    TABMAPObjHdr::NewObj()
     734             :  *
     735             :  * Alloc a new object of specified type or NULL for NONE types or if type
     736             :  * is not supported.
     737             :  **********************************************************************/
     738      562623 : TABMAPObjHdr *TABMAPObjHdr::NewObj(TABGeomType nNewObjType, GInt32 nId /*=0*/)
     739             : {
     740      562623 :     TABMAPObjHdr *poObj = nullptr;
     741             : 
     742      562623 :     switch (nNewObjType)
     743             :     {
     744         215 :         case TAB_GEOM_NONE:
     745         215 :             poObj = new TABMAPObjNone;
     746         215 :             break;
     747      559791 :         case TAB_GEOM_SYMBOL_C:
     748             :         case TAB_GEOM_SYMBOL:
     749      559791 :             poObj = new TABMAPObjPoint;
     750      559791 :             break;
     751           8 :         case TAB_GEOM_FONTSYMBOL_C:
     752             :         case TAB_GEOM_FONTSYMBOL:
     753           8 :             poObj = new TABMAPObjFontPoint;
     754           8 :             break;
     755           8 :         case TAB_GEOM_CUSTOMSYMBOL_C:
     756             :         case TAB_GEOM_CUSTOMSYMBOL:
     757           8 :             poObj = new TABMAPObjCustomPoint;
     758           8 :             break;
     759          44 :         case TAB_GEOM_LINE_C:
     760             :         case TAB_GEOM_LINE:
     761          44 :             poObj = new TABMAPObjLine;
     762          44 :             break;
     763        2517 :         case TAB_GEOM_PLINE_C:
     764             :         case TAB_GEOM_PLINE:
     765             :         case TAB_GEOM_REGION_C:
     766             :         case TAB_GEOM_REGION:
     767             :         case TAB_GEOM_MULTIPLINE_C:
     768             :         case TAB_GEOM_MULTIPLINE:
     769             :         case TAB_GEOM_V450_REGION_C:
     770             :         case TAB_GEOM_V450_REGION:
     771             :         case TAB_GEOM_V450_MULTIPLINE_C:
     772             :         case TAB_GEOM_V450_MULTIPLINE:
     773             :         case TAB_GEOM_V800_REGION_C:
     774             :         case TAB_GEOM_V800_REGION:
     775             :         case TAB_GEOM_V800_MULTIPLINE_C:
     776             :         case TAB_GEOM_V800_MULTIPLINE:
     777        2517 :             poObj = new TABMAPObjPLine;
     778        2517 :             break;
     779           8 :         case TAB_GEOM_ARC_C:
     780             :         case TAB_GEOM_ARC:
     781           8 :             poObj = new TABMAPObjArc;
     782           8 :             break;
     783          12 :         case TAB_GEOM_RECT_C:
     784             :         case TAB_GEOM_RECT:
     785             :         case TAB_GEOM_ROUNDRECT_C:
     786             :         case TAB_GEOM_ROUNDRECT:
     787             :         case TAB_GEOM_ELLIPSE_C:
     788             :         case TAB_GEOM_ELLIPSE:
     789          12 :             poObj = new TABMAPObjRectEllipse;
     790          12 :             break;
     791          12 :         case TAB_GEOM_TEXT_C:
     792             :         case TAB_GEOM_TEXT:
     793          12 :             poObj = new TABMAPObjText;
     794          12 :             break;
     795           4 :         case TAB_GEOM_MULTIPOINT_C:
     796             :         case TAB_GEOM_MULTIPOINT:
     797             :         case TAB_GEOM_V800_MULTIPOINT_C:
     798             :         case TAB_GEOM_V800_MULTIPOINT:
     799           4 :             poObj = new TABMAPObjMultiPoint;
     800           4 :             break;
     801           4 :         case TAB_GEOM_COLLECTION_C:
     802             :         case TAB_GEOM_COLLECTION:
     803             :         case TAB_GEOM_V800_COLLECTION_C:
     804             :         case TAB_GEOM_V800_COLLECTION:
     805           4 :             poObj = new TABMAPObjCollection();
     806           4 :             break;
     807           0 :         default:
     808           0 :             CPLError(CE_Failure, CPLE_AssertionFailed,
     809             :                      "TABMAPObjHdr::NewObj(): Unsupported object type %d",
     810             :                      nNewObjType);
     811             :     }
     812             : 
     813      562623 :     if (poObj)
     814             :     {
     815      562623 :         poObj->m_nType = nNewObjType;
     816      562623 :         poObj->m_nId = nId;
     817      562623 :         poObj->m_nMinX = poObj->m_nMinY = poObj->m_nMaxX = poObj->m_nMaxY = 0;
     818             :     }
     819             : 
     820      562623 :     return poObj;
     821             : }
     822             : 
     823             : /**********************************************************************
     824             :  *                    TABMAPObjHdr::ReadNextObj()
     825             :  *
     826             :  * Read next object in this block and allocate/init a new object for it
     827             :  * if successful.
     828             :  * Returns NULL in case of error or if we reached end of block.
     829             :  **********************************************************************/
     830       20608 : TABMAPObjHdr *TABMAPObjHdr::ReadNextObj(TABMAPObjectBlock *poObjBlock,
     831             :                                         TABMAPHeaderBlock *poHeader)
     832             : {
     833       20608 :     TABMAPObjHdr *poObjHdr = nullptr;
     834             : 
     835       20608 :     if (poObjBlock->AdvanceToNextObject(poHeader) != -1)
     836             :     {
     837       19830 :         poObjHdr = TABMAPObjHdr::NewObj(poObjBlock->GetCurObjectType());
     838       39660 :         if (poObjHdr &&
     839       19830 :             ((poObjHdr->m_nId = poObjBlock->GetCurObjectId()) == -1 ||
     840       19830 :              poObjHdr->ReadObj(poObjBlock) != 0))
     841             :         {
     842             :             // Failed reading object in block... an error was already produced
     843           0 :             delete poObjHdr;
     844           0 :             return nullptr;
     845             :         }
     846             :     }
     847             : 
     848       20608 :     return poObjHdr;
     849             : }
     850             : 
     851             : /**********************************************************************
     852             :  *                    TABMAPObjHdr::IsCompressedType()
     853             :  *
     854             :  * Returns TRUE if the current object type uses compressed coordinates
     855             :  * or FALSE otherwise.
     856             :  **********************************************************************/
     857      578945 : GBool TABMAPObjHdr::IsCompressedType()
     858             : {
     859             :     // Compressed types are 1, 4, 7, etc.
     860      578945 :     return (m_nType % 3) == 1 ? TRUE : FALSE;
     861             : }
     862             : 
     863             : /**********************************************************************
     864             :  *                   TABMAPObjHdr::WriteObjTypeAndId()
     865             :  *
     866             :  * Writetype+object id information... should be called only by the derived
     867             :  * classes' WriteObj() methods.
     868             :  *
     869             :  * Returns 0 on success, -1 on error.
     870             :  **********************************************************************/
     871       26173 : int TABMAPObjHdr::WriteObjTypeAndId(TABMAPObjectBlock *poObjBlock)
     872             : {
     873       26173 :     poObjBlock->WriteByte(static_cast<GByte>(m_nType));
     874       26173 :     return poObjBlock->WriteInt32(m_nId);
     875             : }
     876             : 
     877             : /**********************************************************************
     878             :  *                   TABMAPObjHdr::SetMBR()
     879             :  *
     880             :  **********************************************************************/
     881      560340 : void TABMAPObjHdr::SetMBR(GInt32 nMinX, GInt32 nMinY, GInt32 nMaxX,
     882             :                           GInt32 nMaxY)
     883             : {
     884      560340 :     m_nMinX = std::min(nMinX, nMaxX);
     885      560340 :     m_nMinY = std::min(nMinY, nMaxY);
     886      560340 :     m_nMaxX = std::max(nMinX, nMaxX);
     887      560340 :     m_nMaxY = std::max(nMinY, nMaxY);
     888      560340 : }
     889             : 
     890             : /**********************************************************************
     891             :  *                   class TABMAPObjNone
     892             :  **********************************************************************/
     893             : 
     894         155 : int TABMAPObjNone::ReadObj(TABMAPObjectBlock *)
     895             : {
     896         155 :     return 0;
     897             : }
     898             : 
     899             : /**********************************************************************
     900             :  *                   class TABMAPObjHdrWithCoord
     901             :  **********************************************************************/
     902             : 
     903             : TABMAPObjHdrWithCoord::~TABMAPObjHdrWithCoord() = default;
     904             : 
     905             : /**********************************************************************
     906             :  *                   class TABMAPObjLine
     907             :  *
     908             :  * Applies to 2-points LINEs only
     909             :  **********************************************************************/
     910             : 
     911             : /**********************************************************************
     912             :  *                   TABMAPObjLine::ReadObj()
     913             :  *
     914             :  * Read Object information starting after the object id which should
     915             :  * have been read by TABMAPObjHdr::ReadNextObj() already.
     916             :  * This function should be called only by TABMAPObjHdr::ReadNextObj().
     917             :  *
     918             :  * Returns 0 on success, -1 on error.
     919             :  **********************************************************************/
     920          21 : int TABMAPObjLine::ReadObj(TABMAPObjectBlock *poObjBlock)
     921             : {
     922          21 :     poObjBlock->ReadIntCoord(IsCompressedType(), m_nX1, m_nY1);
     923          21 :     poObjBlock->ReadIntCoord(IsCompressedType(), m_nX2, m_nY2);
     924             : 
     925          21 :     m_nPenId = poObjBlock->ReadByte();  // Pen index
     926             : 
     927          21 :     SetMBR(m_nX1, m_nY1, m_nX2, m_nY2);
     928             : 
     929          21 :     if (CPLGetLastErrorType() == CE_Failure)
     930           0 :         return -1;
     931             : 
     932          21 :     return 0;
     933             : }
     934             : 
     935             : /**********************************************************************
     936             :  *                   TABMAPObjLine::WriteObj()
     937             :  *
     938             :  * Write Object information with the type+object id
     939             :  *
     940             :  * Returns 0 on success, -1 on error.
     941             :  **********************************************************************/
     942          23 : int TABMAPObjLine::WriteObj(TABMAPObjectBlock *poObjBlock)
     943             : {
     944             :     // Write object type and id
     945          23 :     TABMAPObjHdr::WriteObjTypeAndId(poObjBlock);
     946             : 
     947          23 :     poObjBlock->WriteIntCoord(m_nX1, m_nY1, IsCompressedType());
     948          23 :     poObjBlock->WriteIntCoord(m_nX2, m_nY2, IsCompressedType());
     949             : 
     950          23 :     poObjBlock->WriteByte(m_nPenId);  // Pen index
     951             : 
     952          23 :     if (CPLGetLastErrorType() == CE_Failure)
     953           0 :         return -1;
     954             : 
     955          23 :     return 0;
     956             : }
     957             : 
     958             : /**********************************************************************
     959             :  *                   class TABMAPObjPLine
     960             :  *
     961             :  * Applies to PLINE, MULTIPLINE and REGION object types
     962             :  **********************************************************************/
     963             : 
     964             : /**********************************************************************
     965             :  *                   TABMAPObjPLine::ReadObj()
     966             :  *
     967             :  * Read Object information starting after the object id which should
     968             :  * have been read by TABMAPObjHdr::ReadNextObj() already.
     969             :  * This function should be called only by TABMAPObjHdr::ReadNextObj().
     970             :  *
     971             :  * Returns 0 on success, -1 on error.
     972             :  **********************************************************************/
     973        2214 : int TABMAPObjPLine::ReadObj(TABMAPObjectBlock *poObjBlock)
     974             : {
     975        2214 :     m_nCoordBlockPtr = poObjBlock->ReadInt32();
     976        2214 :     m_nCoordDataSize = poObjBlock->ReadInt32();
     977             : 
     978        2214 :     if (m_nCoordDataSize & 0x80000000)
     979             :     {
     980           4 :         m_bSmooth = TRUE;
     981           4 :         m_nCoordDataSize &= 0x7FFFFFFF;  // Take smooth flag out of the value
     982             :     }
     983             :     else
     984             :     {
     985        2210 :         m_bSmooth = FALSE;
     986             :     }
     987             : 
     988             : #ifdef TABDUMP
     989             :     printf("TABMAPObjPLine::ReadObj: m_nCoordDataSize = %d @ %d\n", /*ok*/
     990             :            m_nCoordDataSize, m_nCoordBlockPtr);
     991             : #endif
     992             : 
     993             :     // Number of line segments applies only to MULTIPLINE/REGION but not PLINE
     994        2214 :     if (m_nType == TAB_GEOM_PLINE_C || m_nType == TAB_GEOM_PLINE)
     995             :     {
     996        1689 :         m_numLineSections = 1;
     997             :     }
     998         525 :     else if (m_nType == TAB_GEOM_V800_REGION ||
     999         525 :              m_nType == TAB_GEOM_V800_REGION_C ||
    1000         525 :              m_nType == TAB_GEOM_V800_MULTIPLINE ||
    1001         525 :              m_nType == TAB_GEOM_V800_MULTIPLINE_C)
    1002             :     {
    1003             :         /* V800 REGIONS/MULTIPLINES use an int32 */
    1004           0 :         m_numLineSections = poObjBlock->ReadInt32();
    1005             :         /* ... followed by 33 unknown bytes */
    1006           0 :         poObjBlock->ReadInt32();
    1007           0 :         poObjBlock->ReadInt32();
    1008           0 :         poObjBlock->ReadInt32();
    1009           0 :         poObjBlock->ReadInt32();
    1010           0 :         poObjBlock->ReadInt32();
    1011           0 :         poObjBlock->ReadInt32();
    1012           0 :         poObjBlock->ReadInt32();
    1013           0 :         poObjBlock->ReadInt32();
    1014           0 :         poObjBlock->ReadByte();
    1015             :     }
    1016             :     else
    1017             :     {
    1018             :         /* V300 and V450 REGIONS/MULTIPLINES use an int16 */
    1019         525 :         m_numLineSections = poObjBlock->ReadInt16();
    1020             :     }
    1021             : 
    1022        2214 :     if (m_numLineSections < 0)
    1023             :     {
    1024           0 :         CPLError(CE_Failure, CPLE_AssertionFailed, "Invalid numLineSections");
    1025           0 :         return -1;
    1026             :     }
    1027             : 
    1028             : #ifdef TABDUMP
    1029             :     printf("PLINE/REGION: id=%d, type=%d, " /*ok*/
    1030             :            "CoordBlockPtr=%d, CoordDataSize=%d, numLineSect=%d, bSmooth=%d\n",
    1031             :            m_nId, m_nType, m_nCoordBlockPtr, m_nCoordDataSize,
    1032             :            m_numLineSections, m_bSmooth);
    1033             : #endif
    1034             : 
    1035        2214 :     if (IsCompressedType())
    1036             :     {
    1037             :         // Region center/label point, relative to compr. coord. origin
    1038             :         // No it is not relative to the Object block center
    1039        2153 :         m_nLabelX = poObjBlock->ReadInt16();
    1040        2153 :         m_nLabelY = poObjBlock->ReadInt16();
    1041             : 
    1042             :         // Compressed coordinate origin (present only in compressed case!)
    1043        2153 :         m_nComprOrgX = poObjBlock->ReadInt32();
    1044        2153 :         m_nComprOrgY = poObjBlock->ReadInt32();
    1045             : 
    1046        2153 :         TABSaturatedAdd(m_nLabelX, m_nComprOrgX);
    1047        2153 :         TABSaturatedAdd(m_nLabelY, m_nComprOrgY);
    1048             : 
    1049        2153 :         m_nMinX = poObjBlock->ReadInt16();  // Read MBR
    1050        2153 :         m_nMinY = poObjBlock->ReadInt16();
    1051        2153 :         m_nMaxX = poObjBlock->ReadInt16();
    1052        2153 :         m_nMaxY = poObjBlock->ReadInt16();
    1053        2153 :         TABSaturatedAdd(m_nMinX, m_nComprOrgX);
    1054        2153 :         TABSaturatedAdd(m_nMinY, m_nComprOrgY);
    1055        2153 :         TABSaturatedAdd(m_nMaxX, m_nComprOrgX);
    1056        2153 :         TABSaturatedAdd(m_nMaxY, m_nComprOrgY);
    1057             :     }
    1058             :     else
    1059             :     {
    1060             :         // Region center/label point, relative to compr. coord. origin
    1061             :         // No it is not relative to the Object block center
    1062          61 :         m_nLabelX = poObjBlock->ReadInt32();
    1063          61 :         m_nLabelY = poObjBlock->ReadInt32();
    1064             : 
    1065          61 :         m_nMinX = poObjBlock->ReadInt32();  // Read MBR
    1066          61 :         m_nMinY = poObjBlock->ReadInt32();
    1067          61 :         m_nMaxX = poObjBlock->ReadInt32();
    1068          61 :         m_nMaxY = poObjBlock->ReadInt32();
    1069             :     }
    1070             : 
    1071        2214 :     if (!IsCompressedType())
    1072             :     {
    1073             :         // Init. Compr. Origin to a default value in case type is ever changed
    1074          61 :         m_nComprOrgX =
    1075          61 :             static_cast<GInt32>((static_cast<GIntBig>(m_nMinX) + m_nMaxX) / 2);
    1076          61 :         m_nComprOrgY =
    1077          61 :             static_cast<GInt32>((static_cast<GIntBig>(m_nMinY) + m_nMaxY) / 2);
    1078             :     }
    1079             : 
    1080        2214 :     m_nPenId = poObjBlock->ReadByte();  // Pen index
    1081             : 
    1082        2214 :     if (m_nType == TAB_GEOM_REGION || m_nType == TAB_GEOM_REGION_C ||
    1083        1695 :         m_nType == TAB_GEOM_V450_REGION || m_nType == TAB_GEOM_V450_REGION_C ||
    1084        1695 :         m_nType == TAB_GEOM_V800_REGION || m_nType == TAB_GEOM_V800_REGION_C)
    1085             :     {
    1086         519 :         m_nBrushId = poObjBlock->ReadByte();  // Brush index... REGION only
    1087             :     }
    1088             :     else
    1089             :     {
    1090        1695 :         m_nBrushId = 0;
    1091             :     }
    1092             : 
    1093        2214 :     if (CPLGetLastErrorType() == CE_Failure)
    1094           0 :         return -1;
    1095             : 
    1096        2214 :     return 0;
    1097             : }
    1098             : 
    1099             : /**********************************************************************
    1100             :  *                   TABMAPObjPLine::WriteObj()
    1101             :  *
    1102             :  * Write Object information with the type+object id
    1103             :  *
    1104             :  * Returns 0 on success, -1 on error.
    1105             :  **********************************************************************/
    1106         512 : int TABMAPObjPLine::WriteObj(TABMAPObjectBlock *poObjBlock)
    1107             : {
    1108             :     // Write object type and id
    1109         512 :     TABMAPObjHdr::WriteObjTypeAndId(poObjBlock);
    1110             : 
    1111         512 :     poObjBlock->WriteInt32(m_nCoordBlockPtr);
    1112             : 
    1113             :     // Combine smooth flag in the coord data size.
    1114         512 :     if (m_bSmooth)
    1115           0 :         poObjBlock->WriteInt32(m_nCoordDataSize | 0x80000000);
    1116             :     else
    1117         512 :         poObjBlock->WriteInt32(m_nCoordDataSize);
    1118             : 
    1119             :     // Number of line segments applies only to MULTIPLINE/REGION but not PLINE
    1120         512 :     if (m_nType == TAB_GEOM_V800_REGION || m_nType == TAB_GEOM_V800_REGION_C ||
    1121         512 :         m_nType == TAB_GEOM_V800_MULTIPLINE ||
    1122         512 :         m_nType == TAB_GEOM_V800_MULTIPLINE_C)
    1123             :     {
    1124             :         /* V800 REGIONS/MULTIPLINES use an int32 */
    1125           0 :         poObjBlock->WriteInt32(m_numLineSections);
    1126             :         /* ... followed by 33 unknown bytes */
    1127           0 :         poObjBlock->WriteZeros(33);
    1128             :     }
    1129         512 :     else if (m_nType != TAB_GEOM_PLINE_C && m_nType != TAB_GEOM_PLINE)
    1130             :     {
    1131             :         /* V300 and V450 REGIONS/MULTIPLINES use an int16 */
    1132         105 :         poObjBlock->WriteInt16(static_cast<GInt16>(m_numLineSections));
    1133             :     }
    1134             : 
    1135         512 :     if (IsCompressedType())
    1136             :     {
    1137             :         // Region center/label point, relative to compr. coord. origin
    1138             :         // No it is not relative to the Object block center
    1139         502 :         poObjBlock->WriteInt16(TABInt16Diff(m_nLabelX, m_nComprOrgX));
    1140         502 :         poObjBlock->WriteInt16(TABInt16Diff(m_nLabelY, m_nComprOrgY));
    1141             : 
    1142             :         // Compressed coordinate origin (present only in compressed case!)
    1143         502 :         poObjBlock->WriteInt32(m_nComprOrgX);
    1144         502 :         poObjBlock->WriteInt32(m_nComprOrgY);
    1145             :     }
    1146             :     else
    1147             :     {
    1148             :         // Region center/label point
    1149          10 :         poObjBlock->WriteInt32(m_nLabelX);
    1150          10 :         poObjBlock->WriteInt32(m_nLabelY);
    1151             :     }
    1152             : 
    1153             :     // MBR
    1154         512 :     if (IsCompressedType())
    1155             :     {
    1156             :         // MBR relative to PLINE origin (and not object block center)
    1157         502 :         poObjBlock->WriteInt16(TABInt16Diff(m_nMinX, m_nComprOrgX));
    1158         502 :         poObjBlock->WriteInt16(TABInt16Diff(m_nMinY, m_nComprOrgY));
    1159         502 :         poObjBlock->WriteInt16(TABInt16Diff(m_nMaxX, m_nComprOrgX));
    1160         502 :         poObjBlock->WriteInt16(TABInt16Diff(m_nMaxY, m_nComprOrgY));
    1161             :     }
    1162             :     else
    1163             :     {
    1164          10 :         poObjBlock->WriteInt32(m_nMinX);
    1165          10 :         poObjBlock->WriteInt32(m_nMinY);
    1166          10 :         poObjBlock->WriteInt32(m_nMaxX);
    1167          10 :         poObjBlock->WriteInt32(m_nMaxY);
    1168             :     }
    1169             : 
    1170         512 :     poObjBlock->WriteByte(m_nPenId);  // Pen index
    1171             : 
    1172         512 :     if (m_nType == TAB_GEOM_REGION || m_nType == TAB_GEOM_REGION_C ||
    1173         415 :         m_nType == TAB_GEOM_V450_REGION || m_nType == TAB_GEOM_V450_REGION_C ||
    1174         415 :         m_nType == TAB_GEOM_V800_REGION || m_nType == TAB_GEOM_V800_REGION_C)
    1175             :     {
    1176          97 :         poObjBlock->WriteByte(m_nBrushId);  // Brush index... REGION only
    1177             :     }
    1178             : 
    1179         512 :     if (CPLGetLastErrorType() == CE_Failure)
    1180           0 :         return -1;
    1181             : 
    1182         512 :     return 0;
    1183             : }
    1184             : 
    1185             : /**********************************************************************
    1186             :  *                   class TABMAPObjPoint
    1187             :  *
    1188             :  **********************************************************************/
    1189             : 
    1190             : /**********************************************************************
    1191             :  *                   TABMAPObjPoint::ReadObj()
    1192             :  *
    1193             :  * Read Object information starting after the object id
    1194             :  **********************************************************************/
    1195      545104 : int TABMAPObjPoint::ReadObj(TABMAPObjectBlock *poObjBlock)
    1196             : {
    1197      545104 :     poObjBlock->ReadIntCoord(IsCompressedType(), m_nX, m_nY);
    1198             : 
    1199      545104 :     m_nSymbolId = poObjBlock->ReadByte();  // Symbol index
    1200             : 
    1201      545104 :     SetMBR(m_nX, m_nY, m_nX, m_nY);
    1202             : 
    1203      545104 :     if (CPLGetLastErrorType() == CE_Failure)
    1204           0 :         return -1;
    1205             : 
    1206      545104 :     return 0;
    1207             : }
    1208             : 
    1209             : /**********************************************************************
    1210             :  *                   TABMAPObjPoint::WriteObj()
    1211             :  *
    1212             :  * Write Object information with the type+object id
    1213             :  *
    1214             :  * Returns 0 on success, -1 on error.
    1215             :  **********************************************************************/
    1216       25630 : int TABMAPObjPoint::WriteObj(TABMAPObjectBlock *poObjBlock)
    1217             : {
    1218             :     // Write object type and id
    1219       25630 :     TABMAPObjHdr::WriteObjTypeAndId(poObjBlock);
    1220             : 
    1221       25630 :     poObjBlock->WriteIntCoord(m_nX, m_nY, IsCompressedType());
    1222             : 
    1223       25630 :     poObjBlock->WriteByte(m_nSymbolId);  // Symbol index
    1224             : 
    1225       25630 :     if (CPLGetLastErrorType() == CE_Failure)
    1226           0 :         return -1;
    1227             : 
    1228       25630 :     return 0;
    1229             : }
    1230             : 
    1231             : /**********************************************************************
    1232             :  *                   class TABMAPObjFontPoint
    1233             :  *
    1234             :  **********************************************************************/
    1235             : 
    1236             : /**********************************************************************
    1237             :  *                   TABMAPObjFontPoint::ReadObj()
    1238             :  *
    1239             :  * Read Object information starting after the object id
    1240             :  **********************************************************************/
    1241           6 : int TABMAPObjFontPoint::ReadObj(TABMAPObjectBlock *poObjBlock)
    1242             : {
    1243           6 :     m_nSymbolId = poObjBlock->ReadByte();  // Symbol index
    1244           6 :     m_nPointSize = poObjBlock->ReadByte();
    1245           6 :     m_nFontStyle = poObjBlock->ReadInt16();  // font style
    1246             : 
    1247           6 :     m_nR = poObjBlock->ReadByte();
    1248           6 :     m_nG = poObjBlock->ReadByte();
    1249           6 :     m_nB = poObjBlock->ReadByte();
    1250             : 
    1251           6 :     poObjBlock->ReadByte();  // ??? BG Color ???
    1252           6 :     poObjBlock->ReadByte();  // ???
    1253           6 :     poObjBlock->ReadByte();  // ???
    1254             : 
    1255           6 :     m_nAngle = poObjBlock->ReadInt16();
    1256             : 
    1257           6 :     poObjBlock->ReadIntCoord(IsCompressedType(), m_nX, m_nY);
    1258             : 
    1259           6 :     m_nFontId = poObjBlock->ReadByte();  // Font name index
    1260             : 
    1261           6 :     SetMBR(m_nX, m_nY, m_nX, m_nY);
    1262             : 
    1263           6 :     if (CPLGetLastErrorType() == CE_Failure)
    1264           0 :         return -1;
    1265             : 
    1266           6 :     return 0;
    1267             : }
    1268             : 
    1269             : /**********************************************************************
    1270             :  *                   TABMAPObjFontPoint::WriteObj()
    1271             :  *
    1272             :  * Write Object information with the type+object id
    1273             :  *
    1274             :  * Returns 0 on success, -1 on error.
    1275             :  **********************************************************************/
    1276           2 : int TABMAPObjFontPoint::WriteObj(TABMAPObjectBlock *poObjBlock)
    1277             : {
    1278             :     // Write object type and id
    1279           2 :     TABMAPObjHdr::WriteObjTypeAndId(poObjBlock);
    1280             : 
    1281           2 :     poObjBlock->WriteByte(m_nSymbolId);  // symbol shape
    1282           2 :     poObjBlock->WriteByte(m_nPointSize);
    1283           2 :     poObjBlock->WriteInt16(m_nFontStyle);  // font style
    1284             : 
    1285           2 :     poObjBlock->WriteByte(m_nR);
    1286           2 :     poObjBlock->WriteByte(m_nG);
    1287           2 :     poObjBlock->WriteByte(m_nB);
    1288             : 
    1289           2 :     poObjBlock->WriteByte(0);
    1290           2 :     poObjBlock->WriteByte(0);
    1291           2 :     poObjBlock->WriteByte(0);
    1292             : 
    1293           2 :     poObjBlock->WriteInt16(m_nAngle);
    1294             : 
    1295           2 :     poObjBlock->WriteIntCoord(m_nX, m_nY, IsCompressedType());
    1296             : 
    1297           2 :     poObjBlock->WriteByte(m_nFontId);  // Font name index
    1298             : 
    1299           2 :     if (CPLGetLastErrorType() == CE_Failure)
    1300           0 :         return -1;
    1301             : 
    1302           2 :     return 0;
    1303             : }
    1304             : 
    1305             : /**********************************************************************
    1306             :  *                   class TABMAPObjCustomPoint
    1307             :  *
    1308             :  **********************************************************************/
    1309             : 
    1310             : /**********************************************************************
    1311             :  *                   TABMAPObjCustomPoint::ReadObj()
    1312             :  *
    1313             :  * Read Object information starting after the object id
    1314             :  **********************************************************************/
    1315           6 : int TABMAPObjCustomPoint::ReadObj(TABMAPObjectBlock *poObjBlock)
    1316             : {
    1317           6 :     m_nUnknown_ = poObjBlock->ReadByte();     // ???
    1318           6 :     m_nCustomStyle = poObjBlock->ReadByte();  // 0x01=Show BG, 0x02=Apply Color
    1319             : 
    1320           6 :     poObjBlock->ReadIntCoord(IsCompressedType(), m_nX, m_nY);
    1321             : 
    1322           6 :     m_nSymbolId = poObjBlock->ReadByte();  // Symbol index
    1323           6 :     m_nFontId = poObjBlock->ReadByte();    // Font index
    1324             : 
    1325           6 :     SetMBR(m_nX, m_nY, m_nX, m_nY);
    1326             : 
    1327           6 :     if (CPLGetLastErrorType() == CE_Failure)
    1328           0 :         return -1;
    1329             : 
    1330           6 :     return 0;
    1331             : }
    1332             : 
    1333             : /**********************************************************************
    1334             :  *                   TABMAPObjCustomPoint::WriteObj()
    1335             :  *
    1336             :  * Write Object information with the type+object id
    1337             :  *
    1338             :  * Returns 0 on success, -1 on error.
    1339             :  **********************************************************************/
    1340           2 : int TABMAPObjCustomPoint::WriteObj(TABMAPObjectBlock *poObjBlock)
    1341             : {
    1342             :     // Write object type and id
    1343           2 :     TABMAPObjHdr::WriteObjTypeAndId(poObjBlock);
    1344             : 
    1345           2 :     poObjBlock->WriteByte(m_nUnknown_);     // ???
    1346           2 :     poObjBlock->WriteByte(m_nCustomStyle);  // 0x01=Show BG, 0x02=Apply Color
    1347           2 :     poObjBlock->WriteIntCoord(m_nX, m_nY, IsCompressedType());
    1348             : 
    1349           2 :     poObjBlock->WriteByte(m_nSymbolId);  // Symbol index
    1350           2 :     poObjBlock->WriteByte(m_nFontId);    // Font index
    1351             : 
    1352           2 :     if (CPLGetLastErrorType() == CE_Failure)
    1353           0 :         return -1;
    1354             : 
    1355           2 :     return 0;
    1356             : }
    1357             : 
    1358             : /**********************************************************************
    1359             :  *                   class TABMAPObjRectEllipse
    1360             :  *
    1361             :  **********************************************************************/
    1362             : 
    1363             : /**********************************************************************
    1364             :  *                   TABMAPObjRectEllipse::ReadObj()
    1365             :  *
    1366             :  * Read Object information starting after the object id
    1367             :  **********************************************************************/
    1368          12 : int TABMAPObjRectEllipse::ReadObj(TABMAPObjectBlock *poObjBlock)
    1369             : {
    1370          12 :     if (m_nType == TAB_GEOM_ROUNDRECT || m_nType == TAB_GEOM_ROUNDRECT_C)
    1371             :     {
    1372           4 :         if (IsCompressedType())
    1373             :         {
    1374           0 :             m_nCornerWidth = poObjBlock->ReadInt16();
    1375           0 :             m_nCornerHeight = poObjBlock->ReadInt16();
    1376             :         }
    1377             :         else
    1378             :         {
    1379           4 :             m_nCornerWidth = poObjBlock->ReadInt32();
    1380           4 :             m_nCornerHeight = poObjBlock->ReadInt32();
    1381             :         }
    1382             :     }
    1383             : 
    1384          12 :     poObjBlock->ReadIntCoord(IsCompressedType(), m_nMinX, m_nMinY);
    1385          12 :     poObjBlock->ReadIntCoord(IsCompressedType(), m_nMaxX, m_nMaxY);
    1386             : 
    1387          12 :     m_nPenId = poObjBlock->ReadByte();    // Pen index
    1388          12 :     m_nBrushId = poObjBlock->ReadByte();  // Brush index
    1389             : 
    1390          12 :     if (CPLGetLastErrorType() == CE_Failure)
    1391           0 :         return -1;
    1392             : 
    1393          12 :     return 0;
    1394             : }
    1395             : 
    1396             : /**********************************************************************
    1397             :  *                   TABMAPObjRectEllipse::WriteObj()
    1398             :  *
    1399             :  * Write Object information with the type+object id
    1400             :  *
    1401             :  * Returns 0 on success, -1 on error.
    1402             :  **********************************************************************/
    1403           0 : int TABMAPObjRectEllipse::WriteObj(TABMAPObjectBlock *poObjBlock)
    1404             : {
    1405             :     // Write object type and id
    1406           0 :     TABMAPObjHdr::WriteObjTypeAndId(poObjBlock);
    1407             : 
    1408           0 :     if (m_nType == TAB_GEOM_ROUNDRECT || m_nType == TAB_GEOM_ROUNDRECT_C)
    1409             :     {
    1410           0 :         if (IsCompressedType())
    1411             :         {
    1412           0 :             poObjBlock->WriteInt16(static_cast<GInt16>(m_nCornerWidth));
    1413           0 :             poObjBlock->WriteInt16(static_cast<GInt16>(m_nCornerHeight));
    1414             :         }
    1415             :         else
    1416             :         {
    1417           0 :             poObjBlock->WriteInt32(m_nCornerWidth);
    1418           0 :             poObjBlock->WriteInt32(m_nCornerHeight);
    1419             :         }
    1420             :     }
    1421             : 
    1422           0 :     poObjBlock->WriteIntMBRCoord(m_nMinX, m_nMinY, m_nMaxX, m_nMaxY,
    1423             :                                  IsCompressedType());
    1424             : 
    1425           0 :     poObjBlock->WriteByte(m_nPenId);    // Pen index
    1426           0 :     poObjBlock->WriteByte(m_nBrushId);  // Brush index
    1427             : 
    1428           0 :     if (CPLGetLastErrorType() == CE_Failure)
    1429           0 :         return -1;
    1430             : 
    1431           0 :     return 0;
    1432             : }
    1433             : 
    1434             : /**********************************************************************
    1435             :  *                   class TABMAPObjArc
    1436             :  *
    1437             :  **********************************************************************/
    1438             : 
    1439             : /**********************************************************************
    1440             :  *                   TABMAPObjArc::ReadObj()
    1441             :  *
    1442             :  * Read Object information starting after the object id
    1443             :  **********************************************************************/
    1444           8 : int TABMAPObjArc::ReadObj(TABMAPObjectBlock *poObjBlock)
    1445             : {
    1446           8 :     m_nStartAngle = poObjBlock->ReadInt16();
    1447           8 :     m_nEndAngle = poObjBlock->ReadInt16();
    1448             : 
    1449             :     // An arc is defined by its defining ellipse's MBR:
    1450           8 :     poObjBlock->ReadIntCoord(IsCompressedType(), m_nArcEllipseMinX,
    1451           8 :                              m_nArcEllipseMinY);
    1452           8 :     poObjBlock->ReadIntCoord(IsCompressedType(), m_nArcEllipseMaxX,
    1453           8 :                              m_nArcEllipseMaxY);
    1454             : 
    1455             :     // Read the Arc's actual MBR
    1456           8 :     poObjBlock->ReadIntCoord(IsCompressedType(), m_nMinX, m_nMinY);
    1457           8 :     poObjBlock->ReadIntCoord(IsCompressedType(), m_nMaxX, m_nMaxY);
    1458             : 
    1459           8 :     m_nPenId = poObjBlock->ReadByte();  // Pen index
    1460             : 
    1461           8 :     if (CPLGetLastErrorType() == CE_Failure)
    1462           0 :         return -1;
    1463             : 
    1464           8 :     return 0;
    1465             : }
    1466             : 
    1467             : /**********************************************************************
    1468             :  *                   TABMAPObjArc::WriteObj()
    1469             :  *
    1470             :  * Write Object information with the type+object id
    1471             :  *
    1472             :  * Returns 0 on success, -1 on error.
    1473             :  **********************************************************************/
    1474           0 : int TABMAPObjArc::WriteObj(TABMAPObjectBlock *poObjBlock)
    1475             : {
    1476             :     // Write object type and id
    1477           0 :     TABMAPObjHdr::WriteObjTypeAndId(poObjBlock);
    1478             : 
    1479           0 :     poObjBlock->WriteInt16(static_cast<GInt16>(m_nStartAngle));
    1480           0 :     poObjBlock->WriteInt16(static_cast<GInt16>(m_nEndAngle));
    1481             : 
    1482             :     // An arc is defined by its defining ellipse's MBR:
    1483           0 :     poObjBlock->WriteIntMBRCoord(m_nArcEllipseMinX, m_nArcEllipseMinY,
    1484             :                                  m_nArcEllipseMaxX, m_nArcEllipseMaxY,
    1485             :                                  IsCompressedType());
    1486             : 
    1487             :     // Write the Arc's actual MBR
    1488           0 :     poObjBlock->WriteIntMBRCoord(m_nMinX, m_nMinY, m_nMaxX, m_nMaxY,
    1489             :                                  IsCompressedType());
    1490             : 
    1491           0 :     poObjBlock->WriteByte(m_nPenId);  // Pen index
    1492             : 
    1493           0 :     if (CPLGetLastErrorType() == CE_Failure)
    1494           0 :         return -1;
    1495             : 
    1496           0 :     return 0;
    1497             : }
    1498             : 
    1499             : /**********************************************************************
    1500             :  *                   class TABMAPObjText
    1501             :  *
    1502             :  **********************************************************************/
    1503             : 
    1504             : /**********************************************************************
    1505             :  *                   TABMAPObjText::ReadObj()
    1506             :  *
    1507             :  * Read Object information starting after the object id
    1508             :  **********************************************************************/
    1509           8 : int TABMAPObjText::ReadObj(TABMAPObjectBlock *poObjBlock)
    1510             : {
    1511           8 :     m_nCoordBlockPtr = poObjBlock->ReadInt32();  // String position
    1512           8 :     m_nCoordDataSize = poObjBlock->ReadInt16();  // String length
    1513           8 :     if (m_nCoordDataSize < 0)
    1514             :     {
    1515           0 :         CPLError(CE_Failure, CPLE_AssertionFailed, "m_nCoordDataSize < 0");
    1516           0 :         return -1;
    1517             :     }
    1518           8 :     m_nTextAlignment = poObjBlock->ReadInt16();  // just./spacing/arrow
    1519             : 
    1520           8 :     m_nAngle = poObjBlock->ReadInt16();  // Tenths of degree
    1521             : 
    1522           8 :     m_nFontStyle = poObjBlock->ReadInt16();  // Font style/effect
    1523             : 
    1524           8 :     m_nFGColorR = poObjBlock->ReadByte();
    1525           8 :     m_nFGColorG = poObjBlock->ReadByte();
    1526           8 :     m_nFGColorB = poObjBlock->ReadByte();
    1527             : 
    1528           8 :     m_nBGColorR = poObjBlock->ReadByte();
    1529           8 :     m_nBGColorG = poObjBlock->ReadByte();
    1530           8 :     m_nBGColorB = poObjBlock->ReadByte();
    1531             : 
    1532             :     // Label line end point
    1533           8 :     poObjBlock->ReadIntCoord(IsCompressedType(), m_nLineEndX, m_nLineEndY);
    1534             : 
    1535             :     // Text Height
    1536           8 :     if (IsCompressedType())
    1537           0 :         m_nHeight = poObjBlock->ReadInt16();
    1538             :     else
    1539           8 :         m_nHeight = poObjBlock->ReadInt32();
    1540             : 
    1541             :     // Font name
    1542           8 :     m_nFontId = poObjBlock->ReadByte();  // Font name index
    1543             : 
    1544             :     // MBR after rotation
    1545           8 :     poObjBlock->ReadIntCoord(IsCompressedType(), m_nMinX, m_nMinY);
    1546           8 :     poObjBlock->ReadIntCoord(IsCompressedType(), m_nMaxX, m_nMaxY);
    1547             : 
    1548           8 :     m_nPenId = poObjBlock->ReadByte();  // Pen index
    1549             : 
    1550           8 :     if (CPLGetLastErrorType() == CE_Failure)
    1551           0 :         return -1;
    1552             : 
    1553           8 :     return 0;
    1554             : }
    1555             : 
    1556             : /**********************************************************************
    1557             :  *                   TABMAPObjText::WriteObj()
    1558             :  *
    1559             :  * Write Object information with the type+object id
    1560             :  *
    1561             :  * Returns 0 on success, -1 on error.
    1562             :  **********************************************************************/
    1563           4 : int TABMAPObjText::WriteObj(TABMAPObjectBlock *poObjBlock)
    1564             : {
    1565             :     // Write object type and id
    1566           4 :     TABMAPObjHdr::WriteObjTypeAndId(poObjBlock);
    1567             : 
    1568           4 :     poObjBlock->WriteInt32(m_nCoordBlockPtr);  // String position
    1569           4 :     poObjBlock->WriteInt16(
    1570           4 :         static_cast<GInt16>(m_nCoordDataSize));  // String length
    1571           4 :     poObjBlock->WriteInt16(
    1572           4 :         static_cast<GInt16>(m_nTextAlignment));  // just./spacing/arrow
    1573             : 
    1574           4 :     poObjBlock->WriteInt16(static_cast<GInt16>(m_nAngle));  // Tenths of degree
    1575             : 
    1576           4 :     poObjBlock->WriteInt16(m_nFontStyle);  // Font style/effect
    1577             : 
    1578           4 :     poObjBlock->WriteByte(m_nFGColorR);
    1579           4 :     poObjBlock->WriteByte(m_nFGColorG);
    1580           4 :     poObjBlock->WriteByte(m_nFGColorB);
    1581             : 
    1582           4 :     poObjBlock->WriteByte(m_nBGColorR);
    1583           4 :     poObjBlock->WriteByte(m_nBGColorG);
    1584           4 :     poObjBlock->WriteByte(m_nBGColorB);
    1585             : 
    1586             :     // Label line end point
    1587           4 :     poObjBlock->WriteIntCoord(m_nLineEndX, m_nLineEndY, IsCompressedType());
    1588             : 
    1589             :     // Text Height
    1590           4 :     if (IsCompressedType())
    1591           0 :         poObjBlock->WriteInt16(static_cast<GInt16>(m_nHeight));
    1592             :     else
    1593           4 :         poObjBlock->WriteInt32(m_nHeight);
    1594             : 
    1595             :     // Font name
    1596           4 :     poObjBlock->WriteByte(m_nFontId);  // Font name index
    1597             : 
    1598             :     // MBR after rotation
    1599           4 :     poObjBlock->WriteIntMBRCoord(m_nMinX, m_nMinY, m_nMaxX, m_nMaxY,
    1600             :                                  IsCompressedType());
    1601             : 
    1602           4 :     poObjBlock->WriteByte(m_nPenId);  // Pen index
    1603             : 
    1604           4 :     if (CPLGetLastErrorType() == CE_Failure)
    1605           0 :         return -1;
    1606             : 
    1607           4 :     return 0;
    1608             : }
    1609             : 
    1610             : /**********************************************************************
    1611             :  *                   class TABMAPObjMultiPoint
    1612             :  *
    1613             :  * Applies to PLINE, MULTIPLINE and REGION object types
    1614             :  **********************************************************************/
    1615             : 
    1616             : /**********************************************************************
    1617             :  *                   TABMAPObjMultiPoint::ReadObj()
    1618             :  *
    1619             :  * Read Object information starting after the object id which should
    1620             :  * have been read by TABMAPObjHdr::ReadNextObj() already.
    1621             :  * This function should be called only by TABMAPObjHdr::ReadNextObj().
    1622             :  *
    1623             :  * Returns 0 on success, -1 on error.
    1624             :  **********************************************************************/
    1625           4 : int TABMAPObjMultiPoint::ReadObj(TABMAPObjectBlock *poObjBlock)
    1626             : {
    1627           4 :     m_nCoordBlockPtr = poObjBlock->ReadInt32();
    1628           4 :     m_nNumPoints = poObjBlock->ReadInt32();
    1629             : 
    1630           4 :     const int nPointSize = (IsCompressedType()) ? 2 * 2 : 2 * 4;
    1631           4 :     if (m_nNumPoints < 0 || m_nNumPoints > INT_MAX / nPointSize)
    1632             :     {
    1633           0 :         CPLError(CE_Failure, CPLE_AssertionFailed, "Invalid m_nNumPoints = %d",
    1634             :                  m_nNumPoints);
    1635           0 :         return -1;
    1636             :     }
    1637           4 :     m_nCoordDataSize = m_nNumPoints * nPointSize;
    1638             : 
    1639             : #ifdef TABDUMP
    1640             :     printf("MULTIPOINT: id=%d, type=%d, " /*ok*/
    1641             :            "CoordBlockPtr=%d, CoordDataSize=%d, numPoints=%d\n",
    1642             :            m_nId, m_nType, m_nCoordBlockPtr, m_nCoordDataSize, m_nNumPoints);
    1643             : #endif
    1644             : 
    1645             :     // ?????
    1646           4 :     poObjBlock->ReadInt32();
    1647           4 :     poObjBlock->ReadInt32();
    1648           4 :     poObjBlock->ReadInt32();
    1649           4 :     poObjBlock->ReadByte();
    1650           4 :     poObjBlock->ReadByte();
    1651           4 :     poObjBlock->ReadByte();
    1652             : 
    1653           4 :     if (m_nType == TAB_GEOM_V800_MULTIPOINT ||
    1654           4 :         m_nType == TAB_GEOM_V800_MULTIPOINT_C)
    1655             :     {
    1656             :         /* V800 MULTIPOINTS have another 33 unknown bytes... all zeros */
    1657           0 :         poObjBlock->ReadInt32();
    1658           0 :         poObjBlock->ReadInt32();
    1659           0 :         poObjBlock->ReadInt32();
    1660           0 :         poObjBlock->ReadInt32();
    1661           0 :         poObjBlock->ReadInt32();
    1662           0 :         poObjBlock->ReadInt32();
    1663           0 :         poObjBlock->ReadInt32();
    1664           0 :         poObjBlock->ReadInt32();
    1665           0 :         poObjBlock->ReadByte();
    1666             :     }
    1667             : 
    1668           4 :     m_nSymbolId = poObjBlock->ReadByte();
    1669             : 
    1670             :     // ?????
    1671           4 :     poObjBlock->ReadByte();
    1672             : 
    1673           4 :     if (IsCompressedType())
    1674             :     {
    1675             :         // Region center/label point, relative to compr. coord. origin
    1676             :         // No it is not relative to the Object block center
    1677           4 :         m_nLabelX = poObjBlock->ReadInt16();
    1678           4 :         m_nLabelY = poObjBlock->ReadInt16();
    1679             : 
    1680             :         // Compressed coordinate origin
    1681           4 :         m_nComprOrgX = poObjBlock->ReadInt32();
    1682           4 :         m_nComprOrgY = poObjBlock->ReadInt32();
    1683             : 
    1684           4 :         TABSaturatedAdd(m_nLabelX, m_nComprOrgX);
    1685           4 :         TABSaturatedAdd(m_nLabelY, m_nComprOrgY);
    1686             : 
    1687           4 :         m_nMinX = poObjBlock->ReadInt16();  // Read MBR
    1688           4 :         m_nMinY = poObjBlock->ReadInt16();
    1689           4 :         m_nMaxX = poObjBlock->ReadInt16();
    1690           4 :         m_nMaxY = poObjBlock->ReadInt16();
    1691           4 :         TABSaturatedAdd(m_nMinX, m_nComprOrgX);
    1692           4 :         TABSaturatedAdd(m_nMinY, m_nComprOrgY);
    1693           4 :         TABSaturatedAdd(m_nMaxX, m_nComprOrgX);
    1694           4 :         TABSaturatedAdd(m_nMaxY, m_nComprOrgY);
    1695             :     }
    1696             :     else
    1697             :     {
    1698             :         // Region center/label point
    1699           0 :         m_nLabelX = poObjBlock->ReadInt32();
    1700           0 :         m_nLabelY = poObjBlock->ReadInt32();
    1701             : 
    1702           0 :         m_nMinX = poObjBlock->ReadInt32();  // Read MBR
    1703           0 :         m_nMinY = poObjBlock->ReadInt32();
    1704           0 :         m_nMaxX = poObjBlock->ReadInt32();
    1705           0 :         m_nMaxY = poObjBlock->ReadInt32();
    1706             : 
    1707             :         // Init. Compr. Origin to a default value in case type is ever changed
    1708           0 :         m_nComprOrgX =
    1709           0 :             static_cast<GInt32>((static_cast<GIntBig>(m_nMinX) + m_nMaxX) / 2);
    1710           0 :         m_nComprOrgY =
    1711           0 :             static_cast<GInt32>((static_cast<GIntBig>(m_nMinY) + m_nMaxY) / 2);
    1712             :     }
    1713             : 
    1714           4 :     if (CPLGetLastErrorType() == CE_Failure)
    1715           0 :         return -1;
    1716             : 
    1717           4 :     return 0;
    1718             : }
    1719             : 
    1720             : /**********************************************************************
    1721             :  *                   TABMAPObjMultiPoint::WriteObj()
    1722             :  *
    1723             :  * Write Object information with the type+object id
    1724             :  *
    1725             :  * Returns 0 on success, -1 on error.
    1726             :  **********************************************************************/
    1727           0 : int TABMAPObjMultiPoint::WriteObj(TABMAPObjectBlock *poObjBlock)
    1728             : {
    1729             :     // Write object type and id
    1730           0 :     TABMAPObjHdr::WriteObjTypeAndId(poObjBlock);
    1731             : 
    1732           0 :     poObjBlock->WriteInt32(m_nCoordBlockPtr);
    1733             : 
    1734             :     // Number of points
    1735           0 :     poObjBlock->WriteInt32(m_nNumPoints);
    1736             : 
    1737             :     //  unknown bytes
    1738           0 :     poObjBlock->WriteZeros(15);
    1739             : 
    1740           0 :     if (m_nType == TAB_GEOM_V800_MULTIPOINT ||
    1741           0 :         m_nType == TAB_GEOM_V800_MULTIPOINT_C)
    1742             :     {
    1743             :         /* V800 MULTIPOINTS have another 33 unknown bytes... all zeros */
    1744           0 :         poObjBlock->WriteZeros(33);
    1745             :     }
    1746             : 
    1747             :     // Symbol Id
    1748           0 :     poObjBlock->WriteByte(m_nSymbolId);
    1749             : 
    1750             :     // ????
    1751           0 :     poObjBlock->WriteByte(0);
    1752             : 
    1753             :     // MBR
    1754           0 :     if (IsCompressedType())
    1755             :     {
    1756             :         // Region center/label point, relative to compr. coord. origin
    1757             :         // No it is not relative to the Object block center
    1758           0 :         poObjBlock->WriteInt16(TABInt16Diff(m_nLabelX, m_nComprOrgX));
    1759           0 :         poObjBlock->WriteInt16(TABInt16Diff(m_nLabelY, m_nComprOrgY));
    1760             : 
    1761           0 :         poObjBlock->WriteInt32(m_nComprOrgX);
    1762           0 :         poObjBlock->WriteInt32(m_nComprOrgY);
    1763             : 
    1764             :         // MBR relative to object origin (and not object block center)
    1765           0 :         poObjBlock->WriteInt16(TABInt16Diff(m_nMinX, m_nComprOrgX));
    1766           0 :         poObjBlock->WriteInt16(TABInt16Diff(m_nMinY, m_nComprOrgY));
    1767           0 :         poObjBlock->WriteInt16(TABInt16Diff(m_nMaxX, m_nComprOrgX));
    1768           0 :         poObjBlock->WriteInt16(TABInt16Diff(m_nMaxY, m_nComprOrgY));
    1769             :     }
    1770             :     else
    1771             :     {
    1772             :         // Region center/label point
    1773           0 :         poObjBlock->WriteInt32(m_nLabelX);
    1774           0 :         poObjBlock->WriteInt32(m_nLabelY);
    1775             : 
    1776           0 :         poObjBlock->WriteInt32(m_nMinX);
    1777           0 :         poObjBlock->WriteInt32(m_nMinY);
    1778           0 :         poObjBlock->WriteInt32(m_nMaxX);
    1779           0 :         poObjBlock->WriteInt32(m_nMaxY);
    1780             :     }
    1781             : 
    1782           0 :     if (CPLGetLastErrorType() == CE_Failure)
    1783           0 :         return -1;
    1784             : 
    1785           0 :     return 0;
    1786             : }
    1787             : 
    1788             : /**********************************************************************
    1789             :  *                   class TABMAPObjCollection
    1790             :  *
    1791             :  **********************************************************************/
    1792             : 
    1793             : /**********************************************************************
    1794             :  *                   TABMAPObjCollection::ReadObj()
    1795             :  *
    1796             :  * Read Object information starting after the object id which should
    1797             :  * have been read by TABMAPObjHdr::ReadNextObj() already.
    1798             :  * This function should be called only by TABMAPObjHdr::ReadNextObj().
    1799             :  *
    1800             :  * Returns 0 on success, -1 on error.
    1801             :  **********************************************************************/
    1802           4 : int TABMAPObjCollection::ReadObj(TABMAPObjectBlock *poObjBlock)
    1803             : {
    1804           4 :     int SIZE_OF_REGION_PLINE_MINI_HDR = 24, SIZE_OF_MPOINT_MINI_HDR = 24;
    1805           4 :     int nVersion = TAB_GEOM_GET_VERSION(m_nType);
    1806             : 
    1807             :     /* Figure the size of the mini-header that we find for each of the
    1808             :      * 3 optional components (center x,y and mbr)
    1809             :      */
    1810           4 :     if (IsCompressedType())
    1811             :     {
    1812             :         /* 6 * int16 */
    1813           4 :         SIZE_OF_REGION_PLINE_MINI_HDR = SIZE_OF_MPOINT_MINI_HDR = 12;
    1814             :     }
    1815             :     else
    1816             :     {
    1817             :         /* 6 * int32 */
    1818           0 :         SIZE_OF_REGION_PLINE_MINI_HDR = SIZE_OF_MPOINT_MINI_HDR = 24;
    1819             :     }
    1820             : 
    1821           4 :     if (nVersion >= 800)
    1822             :     {
    1823             :         /* extra 4 bytes for num_segments in Region/Pline mini-headers */
    1824           0 :         SIZE_OF_REGION_PLINE_MINI_HDR += 4;
    1825             :     }
    1826             : 
    1827           4 :     m_nCoordBlockPtr = poObjBlock->ReadInt32();   // pointer into coord block
    1828           4 :     m_nNumMultiPoints = poObjBlock->ReadInt32();  // no. points in multi point
    1829           4 :     m_nRegionDataSize =
    1830           4 :         poObjBlock->ReadInt32();  // size of region data inc. section hdrs
    1831           4 :     m_nPolylineDataSize =
    1832           4 :         poObjBlock->ReadInt32();  // size of multipline data inc. section hdrs
    1833             : 
    1834           4 :     if (m_nRegionDataSize < 0)
    1835             :     {
    1836           0 :         CPLError(CE_Failure, CPLE_AssertionFailed, "Invalid m_nRegionDataSize");
    1837           0 :         return -1;
    1838             :     }
    1839             : 
    1840           4 :     if (m_nPolylineDataSize < 0)
    1841             :     {
    1842           0 :         CPLError(CE_Failure, CPLE_AssertionFailed, "Invalid m_nRegionDataSize");
    1843           0 :         return -1;
    1844             :     }
    1845             : 
    1846           4 :     if (nVersion < 800)
    1847             :     {
    1848             :         // Num Region/Pline section headers (int16 in V650)
    1849           4 :         m_nNumRegSections = poObjBlock->ReadInt16();
    1850           4 :         m_nNumPLineSections = poObjBlock->ReadInt16();
    1851             :     }
    1852             :     else
    1853             :     {
    1854             :         // Num Region/Pline section headers (int32 in V800)
    1855           0 :         m_nNumRegSections = poObjBlock->ReadInt32();
    1856           0 :         m_nNumPLineSections = poObjBlock->ReadInt32();
    1857             :     }
    1858             : 
    1859           4 :     const int nPointSize = (IsCompressedType()) ? 2 * 2 : 2 * 4;
    1860           4 :     if (m_nNumMultiPoints < 0 || m_nNumMultiPoints > INT_MAX / nPointSize)
    1861             :     {
    1862           0 :         CPLError(CE_Failure, CPLE_AssertionFailed, "Invalid m_nNumMultiPoints");
    1863           0 :         return -1;
    1864             :     }
    1865             : 
    1866           4 :     m_nMPointDataSize = m_nNumMultiPoints * nPointSize;
    1867             : 
    1868             :     /* NB. MapInfo counts 2 extra bytes per Region and Pline section header
    1869             :      * in the RegionDataSize and PolylineDataSize values but those 2 extra
    1870             :      * bytes are not present in the section hdr (possibly due to an alignment
    1871             :      * to a 4 byte boundary in memory in MapInfo?). The real data size in
    1872             :      * the CoordBlock is actually 2 bytes shorter per section header than
    1873             :      * what is written in RegionDataSize and PolylineDataSize values.
    1874             :      *
    1875             :      * We'll adjust the values in memory to be the corrected values.
    1876             :      */
    1877           4 :     if (m_nNumRegSections < 0 || m_nNumRegSections > INT_MAX / 2 ||
    1878           4 :         m_nRegionDataSize < 2 * m_nNumRegSections)
    1879             :     {
    1880           0 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    1881             :                  "Invalid m_nNumRegSections / m_nRegionDataSize");
    1882           0 :         return -1;
    1883             :     }
    1884           4 :     m_nRegionDataSize = m_nRegionDataSize - (2 * m_nNumRegSections);
    1885             : 
    1886           4 :     if (m_nNumPLineSections < 0 || m_nNumPLineSections > INT_MAX / 2 ||
    1887           4 :         m_nPolylineDataSize < 2 * m_nNumPLineSections)
    1888             :     {
    1889           0 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    1890             :                  "Invalid m_nNumPLineSections / m_nPolylineDataSize");
    1891           0 :         return -1;
    1892             :     }
    1893           4 :     m_nPolylineDataSize = m_nPolylineDataSize - (2 * m_nNumPLineSections);
    1894             : 
    1895             :     /* Compute total coord block data size, required when splitting blocks */
    1896           4 :     m_nCoordDataSize = 0;
    1897             : 
    1898           4 :     if (m_nNumRegSections > 0)
    1899             :     {
    1900           4 :         if (m_nRegionDataSize > INT_MAX - SIZE_OF_REGION_PLINE_MINI_HDR ||
    1901           4 :             m_nCoordDataSize >
    1902           4 :                 INT_MAX - (SIZE_OF_REGION_PLINE_MINI_HDR + m_nRegionDataSize))
    1903             :         {
    1904           0 :             CPLError(CE_Failure, CPLE_AssertionFailed,
    1905             :                      "Invalid m_nCoordDataSize / m_nRegionDataSize");
    1906           0 :             return -1;
    1907             :         }
    1908           4 :         m_nCoordDataSize += SIZE_OF_REGION_PLINE_MINI_HDR + m_nRegionDataSize;
    1909             :     }
    1910           4 :     if (m_nNumPLineSections > 0)
    1911             :     {
    1912           4 :         if (m_nPolylineDataSize > INT_MAX - SIZE_OF_REGION_PLINE_MINI_HDR ||
    1913           4 :             m_nCoordDataSize >
    1914           4 :                 INT_MAX - (SIZE_OF_REGION_PLINE_MINI_HDR + m_nPolylineDataSize))
    1915             :         {
    1916           0 :             CPLError(CE_Failure, CPLE_AssertionFailed,
    1917             :                      "Invalid m_nCoordDataSize / m_nPolylineDataSize");
    1918           0 :             return -1;
    1919             :         }
    1920           4 :         m_nCoordDataSize += SIZE_OF_REGION_PLINE_MINI_HDR + m_nPolylineDataSize;
    1921             :     }
    1922           4 :     if (m_nNumMultiPoints > 0)
    1923             :     {
    1924           4 :         if (m_nMPointDataSize > INT_MAX - SIZE_OF_MPOINT_MINI_HDR ||
    1925           4 :             m_nCoordDataSize >
    1926           4 :                 INT_MAX - (SIZE_OF_MPOINT_MINI_HDR + m_nMPointDataSize))
    1927             :         {
    1928           0 :             CPLError(CE_Failure, CPLE_AssertionFailed,
    1929             :                      "Invalid m_nCoordDataSize / m_nMPointDataSize");
    1930           0 :             return -1;
    1931             :         }
    1932           4 :         m_nCoordDataSize += SIZE_OF_MPOINT_MINI_HDR + m_nMPointDataSize;
    1933             :     }
    1934             : 
    1935             : #ifdef TABDUMP
    1936             :     printf("COLLECTION: id=%d, type=%d (0x%x), " /*ok*/
    1937             :            "CoordBlockPtr=%d, numRegionSections=%d (size=%d+%d), "
    1938             :            "numPlineSections=%d (size=%d+%d), numPoints=%d (size=%d+%d)\n",
    1939             :            m_nId, m_nType, m_nType, m_nCoordBlockPtr, m_nNumRegSections,
    1940             :            m_nRegionDataSize, SIZE_OF_REGION_PLINE_MINI_HDR,
    1941             :            m_nNumPLineSections, m_nPolylineDataSize,
    1942             :            SIZE_OF_REGION_PLINE_MINI_HDR, m_nNumMultiPoints, m_nMPointDataSize,
    1943             :            SIZE_OF_MPOINT_MINI_HDR);
    1944             : #endif
    1945             : 
    1946           4 :     if (nVersion >= 800)
    1947             :     {
    1948             :         // Extra byte in V800 files... value always 4???
    1949           0 :         int nValue = poObjBlock->ReadByte();
    1950           0 :         if (nValue != 4)
    1951             :         {
    1952           0 :             CPLError(CE_Failure, CPLE_AssertionFailed,
    1953             :                      "TABMAPObjCollection::ReadObj(): Byte 29 in Collection "
    1954             :                      "object header not equal to 4 as expected. Value is %d. "
    1955             :                      "Please report this error to the MITAB list so that "
    1956             :                      "MITAB can be extended to support this case.",
    1957             :                      nValue);
    1958             :             // We don't return right away, the error should be caught at the
    1959             :             // end of this function.
    1960             :         }
    1961             :     }
    1962             : 
    1963             :     // ??? All zeros ???
    1964           4 :     poObjBlock->ReadInt32();
    1965           4 :     poObjBlock->ReadInt32();
    1966           4 :     poObjBlock->ReadInt32();
    1967           4 :     poObjBlock->ReadByte();
    1968           4 :     poObjBlock->ReadByte();
    1969           4 :     poObjBlock->ReadByte();
    1970             : 
    1971           4 :     m_nMultiPointSymbolId = poObjBlock->ReadByte();
    1972             : 
    1973           4 :     poObjBlock->ReadByte();  // ???
    1974           4 :     m_nRegionPenId = poObjBlock->ReadByte();
    1975           4 :     m_nPolylinePenId = poObjBlock->ReadByte();
    1976           4 :     m_nRegionBrushId = poObjBlock->ReadByte();
    1977             : 
    1978           4 :     if (IsCompressedType())
    1979             :     {
    1980             : #ifdef TABDUMP
    1981             :         printf("COLLECTION: READING ComprOrg @ %d\n", /*ok*/
    1982             :                poObjBlock->GetCurAddress());
    1983             : #endif
    1984             :         // Compressed coordinate origin
    1985           4 :         m_nComprOrgX = poObjBlock->ReadInt32();
    1986           4 :         m_nComprOrgY = poObjBlock->ReadInt32();
    1987             : 
    1988           4 :         m_nMinX = poObjBlock->ReadInt16();  // Read MBR
    1989           4 :         m_nMinY = poObjBlock->ReadInt16();
    1990           4 :         m_nMaxX = poObjBlock->ReadInt16();
    1991           4 :         m_nMaxY = poObjBlock->ReadInt16();
    1992           4 :         TABSaturatedAdd(m_nMinX, m_nComprOrgX);
    1993           4 :         TABSaturatedAdd(m_nMinY, m_nComprOrgY);
    1994           4 :         TABSaturatedAdd(m_nMaxX, m_nComprOrgX);
    1995           4 :         TABSaturatedAdd(m_nMaxY, m_nComprOrgY);
    1996             : #ifdef TABDUMP
    1997             :         printf("COLLECTION: ComprOrgX,Y= (%d,%d)\n", /*ok*/
    1998             :                m_nComprOrgX, m_nComprOrgY);
    1999             : #endif
    2000             :     }
    2001             :     else
    2002             :     {
    2003           0 :         m_nMinX = poObjBlock->ReadInt32();  // Read MBR
    2004           0 :         m_nMinY = poObjBlock->ReadInt32();
    2005           0 :         m_nMaxX = poObjBlock->ReadInt32();
    2006           0 :         m_nMaxY = poObjBlock->ReadInt32();
    2007             : 
    2008             :         // Init. Compr. Origin to a default value in case type is ever changed
    2009           0 :         m_nComprOrgX =
    2010           0 :             static_cast<GInt32>((static_cast<GIntBig>(m_nMinX) + m_nMaxX) / 2);
    2011           0 :         m_nComprOrgY =
    2012           0 :             static_cast<GInt32>((static_cast<GIntBig>(m_nMinY) + m_nMaxY) / 2);
    2013             :     }
    2014             : 
    2015           4 :     if (CPLGetLastErrorType() == CE_Failure)
    2016           0 :         return -1;
    2017             : 
    2018           4 :     return 0;
    2019             : }
    2020             : 
    2021             : /**********************************************************************
    2022             :  *                   TABMAPObjCollection::WriteObj()
    2023             :  *
    2024             :  * Write Object information with the type+object id
    2025             :  *
    2026             :  * Returns 0 on success, -1 on error.
    2027             :  **********************************************************************/
    2028           0 : int TABMAPObjCollection::WriteObj(TABMAPObjectBlock *poObjBlock)
    2029             : {
    2030             :     // Write object type and id
    2031           0 :     TABMAPObjHdr::WriteObjTypeAndId(poObjBlock);
    2032             : 
    2033           0 :     int nVersion = TAB_GEOM_GET_VERSION(m_nType);
    2034             : 
    2035             :     /* NB. MapInfo counts 2 extra bytes per Region and Pline section header
    2036             :      * in the RegionDataSize and PolylineDataSize values but those 2 extra
    2037             :      * bytes are not present in the section hdr (possibly due to an alignment
    2038             :      * to a 4 byte boundary in memory in MapInfo?). The real data size in
    2039             :      * the CoordBlock is actually 2 bytes shorter per section header than
    2040             :      * what is written in RegionDataSize and PolylineDataSize values.
    2041             :      *
    2042             :      * The values in memory are the corrected values so we need to add 2 bytes
    2043             :      * per section header in the values that we write on disk to emulate
    2044             :      * MapInfo's behavior.
    2045             :      */
    2046           0 :     GInt32 nRegionDataSizeMI = m_nRegionDataSize + (2 * m_nNumRegSections);
    2047           0 :     GInt32 nPolylineDataSizeMI =
    2048           0 :         m_nPolylineDataSize + (2 * m_nNumPLineSections);
    2049             : 
    2050           0 :     poObjBlock->WriteInt32(m_nCoordBlockPtr);   // pointer into coord block
    2051           0 :     poObjBlock->WriteInt32(m_nNumMultiPoints);  // no. points in multi point
    2052           0 :     poObjBlock->WriteInt32(
    2053             :         nRegionDataSizeMI);  // size of region data inc. section hdrs
    2054           0 :     poObjBlock->WriteInt32(
    2055             :         nPolylineDataSizeMI);  // size of Mpolyline data inc. section hdrs
    2056             : 
    2057           0 :     if (nVersion < 800)
    2058             :     {
    2059             :         // Num Region/Pline section headers (int16 in V650)
    2060           0 :         poObjBlock->WriteInt16(static_cast<GInt16>(m_nNumRegSections));
    2061           0 :         poObjBlock->WriteInt16(static_cast<GInt16>(m_nNumPLineSections));
    2062             :     }
    2063             :     else
    2064             :     {
    2065             :         // Num Region/Pline section headers (int32 in V800)
    2066           0 :         poObjBlock->WriteInt32(m_nNumRegSections);
    2067           0 :         poObjBlock->WriteInt32(m_nNumPLineSections);
    2068             :     }
    2069             : 
    2070           0 :     if (nVersion >= 800)
    2071             :     {
    2072             :         // Extra byte in V800 files... value always 4???
    2073           0 :         poObjBlock->WriteByte(4);
    2074             :     }
    2075             : 
    2076             :     // Unknown data ?????
    2077           0 :     poObjBlock->WriteInt32(0);
    2078           0 :     poObjBlock->WriteInt32(0);
    2079           0 :     poObjBlock->WriteInt32(0);
    2080           0 :     poObjBlock->WriteByte(0);
    2081           0 :     poObjBlock->WriteByte(0);
    2082           0 :     poObjBlock->WriteByte(0);
    2083             : 
    2084           0 :     poObjBlock->WriteByte(m_nMultiPointSymbolId);
    2085             : 
    2086           0 :     poObjBlock->WriteByte(0);
    2087           0 :     poObjBlock->WriteByte(m_nRegionPenId);
    2088           0 :     poObjBlock->WriteByte(m_nPolylinePenId);
    2089           0 :     poObjBlock->WriteByte(m_nRegionBrushId);
    2090             : 
    2091           0 :     if (IsCompressedType())
    2092             :     {
    2093             : #ifdef TABDUMP
    2094             :         printf("COLLECTION: WRITING ComprOrgX,Y= (%d,%d) @ %d\n", /*ok*/
    2095             :                m_nComprOrgX, m_nComprOrgY, poObjBlock->GetCurAddress());
    2096             : #endif
    2097             :         // Compressed coordinate origin
    2098           0 :         poObjBlock->WriteInt32(m_nComprOrgX);
    2099           0 :         poObjBlock->WriteInt32(m_nComprOrgY);
    2100             : 
    2101           0 :         poObjBlock->WriteInt16(TABInt16Diff(m_nMinX, m_nComprOrgX));  // MBR
    2102           0 :         poObjBlock->WriteInt16(TABInt16Diff(m_nMinY, m_nComprOrgY));
    2103           0 :         poObjBlock->WriteInt16(TABInt16Diff(m_nMaxX, m_nComprOrgX));
    2104           0 :         poObjBlock->WriteInt16(TABInt16Diff(m_nMaxY, m_nComprOrgY));
    2105             :     }
    2106             :     else
    2107             :     {
    2108           0 :         poObjBlock->WriteInt32(m_nMinX);  // MBR
    2109           0 :         poObjBlock->WriteInt32(m_nMinY);
    2110           0 :         poObjBlock->WriteInt32(m_nMaxX);
    2111           0 :         poObjBlock->WriteInt32(m_nMaxY);
    2112             :     }
    2113             : 
    2114           0 :     if (CPLGetLastErrorType() == CE_Failure)
    2115           0 :         return -1;
    2116             : 
    2117           0 :     return 0;
    2118             : }

Generated by: LCOV version 1.14