LTP GCOV extension - code coverage report
Current view: directory - ogr/ogrsf_frmts/mitab - mitab_mapobjectblock.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 671
Code covered: 34.4 % Executed lines: 231

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

Generated by: LTP GCOV extension version 1.5