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

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

Generated by: LCOV version 1.14