LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/mitab - mitab_mapcoordblock.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 229 166 72.5 %
Date: 2012-12-26 Functions: 22 17 77.3 %

       1                 : /**********************************************************************
       2                 :  * $Id: mitab_mapcoordblock.cpp,v 1.18 2010-07-07 19:00:15 aboudreault Exp $
       3                 :  *
       4                 :  * Name:     mitab_mapcoordblock.cpp
       5                 :  * Project:  MapInfo TAB Read/Write library
       6                 :  * Language: C++
       7                 :  * Purpose:  Implementation of the TABMAPCoordBlock class used to handle
       8                 :  *           reading/writing of the .MAP files' coordinate 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_mapcoordblock.cpp,v $
      34                 :  * Revision 1.18  2010-07-07 19:00:15  aboudreault
      35                 :  * Cleanup Win32 Compile Warnings (GDAL bug #2930)
      36                 :  *
      37                 :  * Revision 1.17  2008-02-01 19:36:31  dmorissette
      38                 :  * Initial support for V800 REGION and MULTIPLINE (bug 1496)
      39                 :  *
      40                 :  * Revision 1.16  2007/02/23 18:56:44  dmorissette
      41                 :  * Fixed another problem writing collections when the header of objects
      42                 :  * part of a collection were split on multiple blocks. Fix WriteBytes()
      43                 :  * to reload next coord block in TABReadWrite mode if there is one (bug 1663)
      44                 :  *
      45                 :  * Revision 1.15  2006/11/28 18:49:08  dmorissette
      46                 :  * Completed changes to split TABMAPObjectBlocks properly and produce an
      47                 :  * optimal spatial index (bug 1585)
      48                 :  *
      49                 :  * Revision 1.14  2005/10/06 19:15:31  dmorissette
      50                 :  * Collections: added support for reading/writing pen/brush/symbol ids and
      51                 :  * for writing collection objects to .TAB/.MAP (bug 1126)
      52                 :  *
      53                 :  * Revision 1.13  2004/06/30 20:29:04  dmorissette
      54                 :  * Fixed refs to old address danmo@videotron.ca
      55                 :  *
      56                 :  * Revision 1.12  2002/08/27 17:18:23  warmerda
      57                 :  * improved CPL error testing
      58                 :  *
      59                 :  * Revision 1.11  2001/11/17 21:54:06  daniel
      60                 :  * Made several changes in order to support writing objects in 16 bits coordinate format.
      61                 :  * New TABMAPObjHdr-derived classes are used to hold object info in mem until block is full.
      62                 :  *
      63                 :  * Revision 1.10  2001/05/09 17:45:12  daniel
      64                 :  * Support reading and writing data blocks > 512 bytes (for text objects).
      65                 :  *
      66                 :  * Revision 1.9  2000/10/10 19:05:12  daniel
      67                 :  * Fixed ReadBytes() to allow strings overlapping on 2 blocks
      68                 :  *
      69                 :  * Revision 1.8  2000/02/28 16:58:55  daniel
      70                 :  * Added V450 object types with num_points > 32767 and pen width in points
      71                 :  *
      72                 :  * Revision 1.7  2000/01/15 22:30:44  daniel
      73                 :  * Switch to MIT/X-Consortium OpenSource license
      74                 :  *
      75                 :  * Revision 1.6  1999/11/08 04:29:31  daniel
      76                 :  * Fixed problem with compressed coord. offset for regions and multiplines
      77                 :  *
      78                 :  * Revision 1.5  1999/10/06 15:19:11  daniel
      79                 :  * Do not automatically init. curr. feature MBR when block is initialized
      80                 :  *
      81                 :  * Revision 1.4  1999/10/06 13:18:55  daniel
      82                 :  * Fixed uninitialized class members
      83                 :  *
      84                 :  * Revision 1.3  1999/09/29 04:25:42  daniel
      85                 :  * Fixed typo in GetFeatureMBR()
      86                 :  *
      87                 :  * Revision 1.2  1999/09/26 14:59:36  daniel
      88                 :  * Implemented write support
      89                 :  *
      90                 :  * Revision 1.1  1999/07/12 04:18:24  daniel
      91                 :  * Initial checkin
      92                 :  *
      93                 :  **********************************************************************/
      94                 : 
      95                 : #include "mitab.h"
      96                 : 
      97                 : /*=====================================================================
      98                 :  *                      class TABMAPCoordBlock
      99                 :  *====================================================================*/
     100                 : 
     101                 : #define MAP_COORD_HEADER_SIZE   8
     102                 : 
     103                 : /**********************************************************************
     104                 :  *                   TABMAPCoordBlock::TABMAPCoordBlock()
     105                 :  *
     106                 :  * Constructor.
     107                 :  **********************************************************************/
     108               4 : TABMAPCoordBlock::TABMAPCoordBlock(TABAccess eAccessMode /*= TABRead*/):
     109               4 :     TABRawBinBlock(eAccessMode, TRUE)
     110                 : {
     111               4 :     m_nComprOrgX = m_nComprOrgY = m_nNextCoordBlock = m_numDataBytes = 0;
     112                 : 
     113               4 :     m_numBlocksInChain = 1;  // Current block counts as 1
     114                 :  
     115               4 :     m_poBlockManagerRef = NULL;
     116                 : 
     117               4 :     m_nTotalDataSize = 0;
     118               4 :     m_nFeatureDataSize = 0;
     119                 : 
     120               4 :     m_nFeatureXMin = m_nMinX = 1000000000;
     121               4 :     m_nFeatureYMin = m_nMinY = 1000000000;
     122               4 :     m_nFeatureXMax = m_nMaxX = -1000000000;
     123               4 :     m_nFeatureYMax = m_nMaxY = -1000000000;
     124                 : 
     125               4 : }
     126                 : 
     127                 : /**********************************************************************
     128                 :  *                   TABMAPCoordBlock::~TABMAPCoordBlock()
     129                 :  *
     130                 :  * Destructor.
     131                 :  **********************************************************************/
     132               4 : TABMAPCoordBlock::~TABMAPCoordBlock()
     133                 : {
     134                 : 
     135               4 : }
     136                 : 
     137                 : 
     138                 : /**********************************************************************
     139                 :  *                   TABMAPCoordBlock::InitBlockFromData()
     140                 :  *
     141                 :  * Perform some initialization on the block after its binary data has
     142                 :  * been set or changed (or loaded from a file).
     143                 :  *
     144                 :  * Returns 0 if succesful or -1 if an error happened, in which case 
     145                 :  * CPLError() will have been called.
     146                 :  **********************************************************************/
     147              16 : int     TABMAPCoordBlock::InitBlockFromData(GByte *pabyBuf,
     148                 :                                             int nBlockSize, int nSizeUsed, 
     149                 :                                             GBool bMakeCopy /* = TRUE */,
     150                 :                                             FILE *fpSrc /* = NULL */, 
     151                 :                                             int nOffset /* = 0 */)
     152                 : {
     153                 :     int nStatus;
     154                 : 
     155                 :     /*-----------------------------------------------------------------
     156                 :      * First of all, we must call the base class' InitBlockFromData()
     157                 :      *----------------------------------------------------------------*/
     158                 :     nStatus = TABRawBinBlock::InitBlockFromData(pabyBuf, nBlockSize, nSizeUsed,
     159              16 :                                                 bMakeCopy, fpSrc, nOffset);
     160              16 :     if (nStatus != 0)   
     161               0 :         return nStatus;
     162                 : 
     163                 :     /*-----------------------------------------------------------------
     164                 :      * Validate block type
     165                 :      *----------------------------------------------------------------*/
     166              16 :     if (m_nBlockType != TABMAP_COORD_BLOCK)
     167                 :     {
     168                 :         CPLError(CE_Failure, CPLE_FileIO,
     169                 :                  "InitBlockFromData(): Invalid Block Type: got %d expected %d",
     170               0 :                  m_nBlockType, TABMAP_COORD_BLOCK);
     171               0 :         CPLFree(m_pabyBuf);
     172               0 :         m_pabyBuf = NULL;
     173               0 :         return -1;
     174                 :     }
     175                 : 
     176                 :     /*-----------------------------------------------------------------
     177                 :      * Init member variables
     178                 :      *----------------------------------------------------------------*/
     179              16 :     GotoByteInBlock(0x002);
     180              16 :     m_numDataBytes = ReadInt16();       /* Excluding 8 bytes header */
     181                 : 
     182              16 :     m_nNextCoordBlock = ReadInt32();
     183                 : 
     184                 :     // Set the real SizeUsed based on numDataBytes
     185              16 :     m_nSizeUsed = m_numDataBytes + MAP_COORD_HEADER_SIZE;
     186                 : 
     187                 :     /*-----------------------------------------------------------------
     188                 :      * The read ptr is now located at the beginning of the data part.
     189                 :      *----------------------------------------------------------------*/
     190              16 :     GotoByteInBlock(MAP_COORD_HEADER_SIZE);
     191                 : 
     192              16 :     return 0;
     193                 : }
     194                 : 
     195                 : /**********************************************************************
     196                 :  *                   TABMAPCoordBlock::CommitToFile()
     197                 :  *
     198                 :  * Commit the current state of the binary block to the file to which 
     199                 :  * it has been previously attached.
     200                 :  *
     201                 :  * This method makes sure all values are properly set in the map object
     202                 :  * block header and then calls TABRawBinBlock::CommitToFile() to do
     203                 :  * the actual writing to disk.
     204                 :  *
     205                 :  * Returns 0 if succesful or -1 if an error happened, in which case 
     206                 :  * CPLError() will have been called.
     207                 :  **********************************************************************/
     208               4 : int     TABMAPCoordBlock::CommitToFile()
     209                 : {
     210               4 :     int nStatus = 0;
     211                 : 
     212               4 :     CPLErrorReset();
     213                 : 
     214               4 :     if ( m_pabyBuf == NULL )
     215                 :     {
     216                 :         CPLError(CE_Failure, CPLE_AssertionFailed, 
     217               0 :                  "CommitToFile(): Block has not been initialized yet!");
     218               0 :         return -1;
     219                 :     }
     220                 : 
     221                 :     /*-----------------------------------------------------------------
     222                 :      * Make sure 8 bytes block header is up to date.
     223                 :      *----------------------------------------------------------------*/
     224               4 :     GotoByteInBlock(0x000);
     225                 : 
     226               4 :     WriteInt16(TABMAP_COORD_BLOCK);    // Block type code
     227               4 :     WriteInt16((GInt16)(m_nSizeUsed - MAP_COORD_HEADER_SIZE)); // num. bytes used
     228               4 :     WriteInt32(m_nNextCoordBlock);
     229                 : 
     230               4 :     if( CPLGetLastErrorType() == CE_Failure )
     231               0 :         nStatus = CPLGetLastErrorNo();
     232                 : 
     233                 :     /*-----------------------------------------------------------------
     234                 :      * OK, call the base class to write the block to disk.
     235                 :      *----------------------------------------------------------------*/
     236               4 :     if (nStatus == 0)
     237               4 :         nStatus = TABRawBinBlock::CommitToFile();
     238                 : 
     239               4 :     return nStatus;
     240                 : }
     241                 : 
     242                 : /**********************************************************************
     243                 :  *                   TABMAPCoordBlock::InitNewBlock()
     244                 :  *
     245                 :  * Initialize a newly created block so that it knows to which file it
     246                 :  * is attached, its block size, etc . and then perform any specific 
     247                 :  * initialization for this block type, including writing a default 
     248                 :  * block header, etc. and leave the block ready to receive data.
     249                 :  *
     250                 :  * This is an alternative to calling ReadFromFile() or InitBlockFromData()
     251                 :  * that puts the block in a stable state without loading any initial
     252                 :  * data in it.
     253                 :  *
     254                 :  * Returns 0 if succesful or -1 if an error happened, in which case 
     255                 :  * CPLError() will have been called.
     256                 :  **********************************************************************/
     257               6 : int     TABMAPCoordBlock::InitNewBlock(FILE *fpSrc, int nBlockSize, 
     258                 :                                         int nFileOffset /* = 0*/)
     259                 : {
     260               6 :     CPLErrorReset();
     261                 : 
     262                 :     /*-----------------------------------------------------------------
     263                 :      * Start with the default initialisation
     264                 :      *----------------------------------------------------------------*/
     265               6 :     if ( TABRawBinBlock::InitNewBlock(fpSrc, nBlockSize, nFileOffset) != 0)
     266               0 :         return -1;
     267                 : 
     268                 :     /*-----------------------------------------------------------------
     269                 :      * And then set default values for the block header.
     270                 :      *
     271                 :      * IMPORTANT: Do not reset m_nComprOrg here because its value needs to be
     272                 :      * maintained between blocks in the same chain.
     273                 :      *----------------------------------------------------------------*/
     274               6 :     m_nNextCoordBlock = 0;
     275                 :  
     276               6 :     m_numDataBytes = 0;
     277                 : 
     278                 :     // m_nMin/Max are used to keep track of current block MBR
     279                 :     // FeatureMin/Max should not be reset here since feature coords can
     280                 :     // be split on several blocks
     281               6 :     m_nMinX = 1000000000;
     282               6 :     m_nMinY = 1000000000;
     283               6 :     m_nMaxX = -1000000000;
     284               6 :     m_nMaxY = -1000000000;
     285                 : 
     286               6 :     if (m_eAccess != TABRead)
     287                 :     {
     288               4 :         GotoByteInBlock(0x000);
     289                 : 
     290               4 :         WriteInt16(TABMAP_COORD_BLOCK); // Block type code
     291               4 :         WriteInt16(0);                  // num. bytes used, excluding header
     292               4 :         WriteInt32(0);                  // Pointer to next coord block
     293                 :     }
     294                 : 
     295               6 :     if (CPLGetLastErrorType() == CE_Failure )
     296               0 :         return -1;
     297                 : 
     298               6 :     return 0;
     299                 : }
     300                 : 
     301                 : /**********************************************************************
     302                 :  *                   TABMAPObjectBlock::SetNextCoordBlock()
     303                 :  *
     304                 :  * Set the address (offset from beginning of file) of the coord. block
     305                 :  * that follows the current one.
     306                 :  **********************************************************************/
     307               2 : void     TABMAPCoordBlock::SetNextCoordBlock(GInt32 nNextCoordBlockAddress)
     308                 : {
     309               2 :     m_nNextCoordBlock = nNextCoordBlockAddress;
     310               2 : }
     311                 : 
     312                 : 
     313                 : /**********************************************************************
     314                 :  *                   TABMAPObjectBlock::SetComprCoordOrigin()
     315                 :  *
     316                 :  * Set the Compressed integer coordinates space origin to be used when
     317                 :  * reading compressed coordinates using ReadIntCoord().
     318                 :  **********************************************************************/
     319              62 : void     TABMAPCoordBlock::SetComprCoordOrigin(GInt32 nX, GInt32 nY)
     320                 : {
     321              62 :     m_nComprOrgX = nX;
     322              62 :     m_nComprOrgY = nY;
     323              62 : }
     324                 : 
     325                 : /**********************************************************************
     326                 :  *                   TABMAPObjectBlock::ReadIntCoord()
     327                 :  *
     328                 :  * Read the next pair of integer coordinates value from the block, and
     329                 :  * apply the translation relative to the origin of the coord. space
     330                 :  * previously set using SetComprCoordOrigin() if bCompressed=TRUE.
     331                 :  *
     332                 :  * This means that the returned coordinates are always absolute integer
     333                 :  * coordinates, even when the source coords are in compressed form.
     334                 :  *
     335                 :  * Returns 0 if succesful or -1 if an error happened, in which case 
     336                 :  * CPLError() will have been called.
     337                 :  **********************************************************************/
     338             102 : int     TABMAPCoordBlock::ReadIntCoord(GBool bCompressed, 
     339                 :                                         GInt32 &nX, GInt32 &nY)
     340                 : {
     341             102 :     if (bCompressed)
     342                 :     {   
     343              92 :         nX = m_nComprOrgX + ReadInt16();
     344              92 :         nY = m_nComprOrgY + ReadInt16();
     345                 :     }
     346                 :     else
     347                 :     {
     348              10 :         nX = ReadInt32();
     349              10 :         nY = ReadInt32();
     350                 :     }
     351                 : 
     352             102 :     if (CPLGetLastErrorType() == CE_Failure)
     353               0 :         return -1;
     354                 : 
     355             102 :     return 0;
     356                 : }
     357                 : 
     358                 : /**********************************************************************
     359                 :  *                   TABMAPObjectBlock::ReadIntCoords()
     360                 :  *
     361                 :  * Read the specified number of pairs of X,Y integer coordinates values
     362                 :  * from the block, and apply the translation relative to the origin of
     363                 :  * the coord. space previously set using SetComprCoordOrigin() if 
     364                 :  * bCompressed=TRUE.
     365                 :  *
     366                 :  * This means that the returned coordinates are always absolute integer
     367                 :  * coordinates, even when the source coords are in compressed form.
     368                 :  *
     369                 :  * panXY should point to an array big enough to receive the specified
     370                 :  * number of coordinates.
     371                 :  *
     372                 :  * Returns 0 if succesful or -1 if an error happened, in which case 
     373                 :  * CPLError() will have been called.
     374                 :  **********************************************************************/
     375              51 : int     TABMAPCoordBlock::ReadIntCoords(GBool bCompressed, int numCoordPairs, 
     376                 :                                         GInt32 *panXY)
     377                 : {
     378              51 :     int i, numValues = numCoordPairs*2;
     379                 : 
     380              51 :     if (bCompressed)
     381                 :     {   
     382             971 :         for(i=0; i<numValues; i+=2)
     383                 :         {
     384             925 :             panXY[i]   = m_nComprOrgX + ReadInt16();
     385             925 :             panXY[i+1] = m_nComprOrgY + ReadInt16();
     386             925 :             if (CPLGetLastErrorType() != 0)
     387               0 :                 return -1;
     388                 :         }
     389                 :     }
     390                 :     else
     391                 :     {
     392             310 :         for(i=0; i<numValues; i+=2)
     393                 :         {
     394             305 :             panXY[i]   = ReadInt32();
     395             305 :             panXY[i+1] = ReadInt32();
     396             305 :             if (CPLGetLastErrorType() != 0)
     397               0 :                 return -1;
     398                 :         }
     399                 :     }
     400                 : 
     401              51 :     return 0;
     402                 : }
     403                 : 
     404                 : /**********************************************************************
     405                 :  *                   TABMAPObjectBlock::ReadCoordSecHdrs()
     406                 :  *
     407                 :  * Read a set of coordinate section headers for PLINE MULTIPLE or REGIONs
     408                 :  * and store the result in the array of structures pasHdrs[].  It is assumed
     409                 :  * that pasHdrs points to an allocated array of at least numSections 
     410                 :  * TABMAPCoordSecHdr structures.
     411                 :  *
     412                 :  * The function will also set the values of numVerticesTotal to the 
     413                 :  * total number of coordinates in the object (the sum of all sections 
     414                 :  * headers read).
     415                 :  *
     416                 :  * At the end of the call, this TABMAPCoordBlock object will be located
     417                 :  * at the beginning of the coordinate data.
     418                 :  *
     419                 :  * In V450 the numVertices is stored on an int32 instead of an int16
     420                 :  *
     421                 :  * In V800 the numHoles is stored on an int32 instead of an int16
     422                 :  *
     423                 :  * IMPORTANT: This function makes the assumption that coordinates for all
     424                 :  *            the sections are grouped together immediately after the
     425                 :  *            last section header block (i.e. that the coord. data is not
     426                 :  *            located all over the place).  If it is not the case then
     427                 :  *            an error will be produced and the code to read region and
     428                 :  *            multipline objects will have to be updated. 
     429                 :  *
     430                 :  * Returns 0 if succesful or -1 if an error happened, in which case 
     431                 :  * CPLError() will have been called.
     432                 :  **********************************************************************/
     433              51 : int     TABMAPCoordBlock::ReadCoordSecHdrs(GBool bCompressed, 
     434                 :                                            int nVersion,
     435                 :                                            int numSections,
     436                 :                                            TABMAPCoordSecHdr *pasHdrs,
     437                 :                                            GInt32    &numVerticesTotal)
     438                 : {
     439                 :     int i, nTotalHdrSizeUncompressed;
     440                 : 
     441              51 :     CPLErrorReset();
     442                 : 
     443                 :     /*-------------------------------------------------------------
     444                 :      * Note about header+vertices size vs compressed coordinates:
     445                 :      * The uncompressed header sections are actually 16 bytes, but the
     446                 :      * offset calculations are based on prior decompression of the 
     447                 :      * coordinates.  Our coordinate offset calculations have
     448                 :      * to take this fact into account.
     449                 :      * Also, V450 header section uses int32 instead of int16 for numVertices
     450                 :      * and we add another 2 bytes to align with a 4 bytes boundary.
     451                 :      * V800 header section uses int32 for numHoles but there is no need
     452                 :      * for the 2 alignment bytes so the size is the same as V450
     453                 :      *------------------------------------------------------------*/
     454              51 :     if (nVersion >= 450)
     455               0 :         nTotalHdrSizeUncompressed = 28 * numSections;
     456                 :     else
     457              51 :         nTotalHdrSizeUncompressed = 24 * numSections;
     458                 : 
     459              51 :     numVerticesTotal = 0;
     460                 : 
     461             102 :     for(i=0; i<numSections; i++)
     462                 :     {
     463                 :         /*-------------------------------------------------------------
     464                 :          * Read the coord. section header blocks
     465                 :          *------------------------------------------------------------*/
     466                 : #ifdef TABDUMP
     467                 :         int nHdrAddress = GetCurAddress();
     468                 : #endif
     469              51 :         if (nVersion >= 450)
     470               0 :             pasHdrs[i].numVertices = ReadInt32();
     471                 :         else
     472              51 :             pasHdrs[i].numVertices = ReadInt16();
     473              51 :         if (nVersion >= 800)
     474               0 :             pasHdrs[i].numHoles = ReadInt32();
     475                 :         else
     476              51 :             pasHdrs[i].numHoles = ReadInt16();
     477              51 :         ReadIntCoord(bCompressed, pasHdrs[i].nXMin, pasHdrs[i].nYMin);
     478              51 :         ReadIntCoord(bCompressed, pasHdrs[i].nXMax, pasHdrs[i].nYMax);
     479              51 :         pasHdrs[i].nDataOffset = ReadInt32();
     480                 : 
     481              51 :         if (CPLGetLastErrorType() != 0)
     482               0 :             return -1;
     483                 : 
     484              51 :         numVerticesTotal += pasHdrs[i].numVertices;
     485                 : 
     486                 : 
     487              51 :         pasHdrs[i].nVertexOffset = (pasHdrs[i].nDataOffset - 
     488              51 :                                     nTotalHdrSizeUncompressed ) / 8;
     489                 : #ifdef TABDUMP
     490                 :         printf("READING pasHdrs[%d] @ %d = \n"
     491                 :                "              { numVertices = %d, numHoles = %d, \n"
     492                 :                "                nXMin=%d, nYMin=%d, nXMax=%d, nYMax=%d,\n"
     493                 :                "                nDataOffset=%d, nVertexOffset=%d }\n",
     494                 :                i, nHdrAddress, pasHdrs[i].numVertices, pasHdrs[i].numHoles, 
     495                 :                pasHdrs[i].nXMin, pasHdrs[i].nYMin, pasHdrs[i].nXMax, 
     496                 :                pasHdrs[i].nYMax, pasHdrs[i].nDataOffset, 
     497                 :                pasHdrs[i].nVertexOffset);
     498                 :         printf("                dX = %d, dY = %d  (center = %d , %d)\n",
     499                 :                pasHdrs[i].nXMax - pasHdrs[i].nXMin,
     500                 :                pasHdrs[i].nYMax - pasHdrs[i].nYMin,
     501                 :                m_nComprOrgX, m_nComprOrgY);
     502                 : #endif
     503                 :     }
     504                 : 
     505             102 :     for(i=0; i<numSections; i++)
     506                 :     {
     507                 :         /*-------------------------------------------------------------
     508                 :          * Make sure all coordinates are grouped together
     509                 :          * (Well... at least check that all the vertex indices are enclosed
     510                 :          * inside the [0..numVerticesTotal] range.)
     511                 :          *------------------------------------------------------------*/
     512             153 :         if ( pasHdrs[i].nVertexOffset < 0 || 
     513              51 :              (pasHdrs[i].nVertexOffset +
     514              51 :                            pasHdrs[i].numVertices ) > numVerticesTotal)
     515                 :         {
     516                 :             CPLError(CE_Failure, CPLE_AssertionFailed,
     517                 :                      "Unsupported case or corrupt file: MULTIPLINE/REGION "
     518               0 :                      "object vertices do not appear to be grouped together.");
     519               0 :             return -1;
     520                 :         }
     521                 :     }
     522                 : 
     523              51 :     return 0;
     524                 : }
     525                 : 
     526                 : /**********************************************************************
     527                 :  *                   TABMAPObjectBlock::WriteCoordSecHdrs()
     528                 :  *
     529                 :  * Write a set of coordinate section headers for PLINE MULTIPLE or REGIONs.
     530                 :  * pasHdrs should point to an array of numSections TABMAPCoordSecHdr 
     531                 :  * structures that have been properly initialized.
     532                 :  *
     533                 :  * In V450 the numVertices is stored on an int32 instead of an int16
     534                 :  *
     535                 :  * In V800 the numHoles is stored on an int32 instead of an int16
     536                 :  *
     537                 :  * At the end of the call, this TABMAPCoordBlock object will be ready to
     538                 :  * receive the coordinate data.
     539                 :  *
     540                 :  * Returns 0 if succesful or -1 if an error happened, in which case 
     541                 :  * CPLError() will have been called.
     542                 :  **********************************************************************/
     543              11 : int     TABMAPCoordBlock::WriteCoordSecHdrs(int nVersion,
     544                 :                                             int numSections,
     545                 :                                             TABMAPCoordSecHdr *pasHdrs,
     546                 :                                             GBool bCompressed /*=FALSE*/)
     547                 : {
     548                 :     int i;
     549                 : 
     550              11 :     CPLErrorReset();
     551                 : 
     552              22 :     for(i=0; i<numSections; i++)
     553                 :     {
     554                 :         /*-------------------------------------------------------------
     555                 :          * Write the coord. section header blocks
     556                 :          *------------------------------------------------------------*/
     557                 : #ifdef TABDUMP
     558                 :         printf("WRITING pasHdrs[%d] @ %d = \n"
     559                 :                "              { numVertices = %d, numHoles = %d, \n"
     560                 :                "                nXMin=%d, nYMin=%d, nXMax=%d, nYMax=%d,\n"
     561                 :                "                nDataOffset=%d, nVertexOffset=%d }\n",
     562                 :                i, GetCurAddress(), pasHdrs[i].numVertices, pasHdrs[i].numHoles, 
     563                 :                pasHdrs[i].nXMin, pasHdrs[i].nYMin, pasHdrs[i].nXMax, 
     564                 :                pasHdrs[i].nYMax, pasHdrs[i].nDataOffset, 
     565                 :                pasHdrs[i].nVertexOffset);
     566                 :         printf("                dX = %d, dY = %d  (center = %d , %d)\n",
     567                 :                pasHdrs[i].nXMax - pasHdrs[i].nXMin,
     568                 :                pasHdrs[i].nYMax - pasHdrs[i].nYMin,
     569                 :                m_nComprOrgX, m_nComprOrgY);
     570                 : #endif
     571                 : 
     572              11 :         if (nVersion >= 450)
     573               0 :             WriteInt32(pasHdrs[i].numVertices);
     574                 :         else
     575              11 :             WriteInt16((GInt16)pasHdrs[i].numVertices);
     576              11 :         if (nVersion >= 800)
     577               0 :             WriteInt32(pasHdrs[i].numHoles);
     578                 :         else
     579              11 :             WriteInt16((GInt16)pasHdrs[i].numHoles);
     580              11 :         WriteIntCoord(pasHdrs[i].nXMin, pasHdrs[i].nYMin, bCompressed);
     581              11 :         WriteIntCoord(pasHdrs[i].nXMax, pasHdrs[i].nYMax, bCompressed);
     582              11 :         WriteInt32(pasHdrs[i].nDataOffset);
     583                 : 
     584              11 :         if (CPLGetLastErrorType() == CE_Failure )
     585               0 :             return -1;
     586                 :     }
     587                 : 
     588              11 :     return 0;
     589                 : }
     590                 : 
     591                 : 
     592                 : /**********************************************************************
     593                 :  *                   TABMAPCoordBlock::WriteIntCoord()
     594                 :  *
     595                 :  * Write a pair of integer coordinates values to the current position in the
     596                 :  * the block.
     597                 :  *
     598                 :  * Returns 0 if succesful or -1 if an error happened, in which case 
     599                 :  * CPLError() will have been called.
     600                 :  **********************************************************************/
     601                 : 
     602             272 : int     TABMAPCoordBlock::WriteIntCoord(GInt32 nX, GInt32 nY,
     603                 :                                         GBool bCompressed /*=FALSE*/)
     604                 : {
     605                 : 
     606             272 :     if ((!bCompressed && (WriteInt32(nX) != 0 || WriteInt32(nY) != 0 ) ) ||
     607                 :         (bCompressed && (WriteInt16((GInt16)(nX - m_nComprOrgX)) != 0 ||
     608                 :                          WriteInt16((GInt16)(nY - m_nComprOrgY)) != 0) ) )
     609                 :     {
     610               0 :         return -1;
     611                 :     }
     612                 : 
     613                 :     /*-----------------------------------------------------------------
     614                 :      * Update block MBR
     615                 :      *----------------------------------------------------------------*/
     616                 :     //__TODO__ Do we still need to track the block MBR???
     617             272 :     if (nX < m_nMinX)
     618              22 :         m_nMinX = nX;
     619             272 :     if (nX > m_nMaxX)
     620              13 :         m_nMaxX = nX;
     621                 :     
     622             272 :     if (nY < m_nMinY)
     623              21 :         m_nMinY = nY;
     624             272 :     if (nY > m_nMaxY)
     625              24 :         m_nMaxY = nY;
     626                 :     
     627                 :     /*-------------------------------------------------------------
     628                 :      * Also keep track of current feature MBR.
     629                 :      *------------------------------------------------------------*/
     630             272 :     if (nX < m_nFeatureXMin)
     631              11 :         m_nFeatureXMin = nX;
     632             272 :     if (nX > m_nFeatureXMax)
     633              22 :         m_nFeatureXMax = nX;
     634                 : 
     635             272 :     if (nY < m_nFeatureYMin)
     636              11 :         m_nFeatureYMin = nY;
     637             272 :     if (nY > m_nFeatureYMax)
     638              22 :         m_nFeatureYMax = nY;
     639                 : 
     640             272 :     return 0;
     641                 : }
     642                 : 
     643                 : /**********************************************************************
     644                 :  *                   TABMAPCoordBlock::SetMAPBlockManagerRef()
     645                 :  *
     646                 :  * Pass a reference to the block manager object for the file this 
     647                 :  * block belongs to.  The block manager will be used by this object
     648                 :  * when it needs to automatically allocate a new block.
     649                 :  **********************************************************************/
     650               2 : void TABMAPCoordBlock::SetMAPBlockManagerRef(TABBinBlockManager *poBlockMgr)
     651                 : {
     652               2 :     m_poBlockManagerRef = poBlockMgr;
     653               2 : };
     654                 : 
     655                 : 
     656                 : /**********************************************************************
     657                 :  *                   TABMAPCoordBlock::ReadBytes()
     658                 :  *
     659                 :  * Cover function for TABRawBinBlock::ReadBytes() that will automagically
     660                 :  * load the next coordinate block in the chain before reading the 
     661                 :  * requested bytes if we are at the end of the current block and if
     662                 :  * m_nNextCoordBlock is a valid block.
     663                 :  *
     664                 :  * Then the control is passed to TABRawBinBlock::ReadBytes() to finish the
     665                 :  * work:
     666                 :  * Copy the number of bytes from the data block's internal buffer to
     667                 :  * the user's buffer pointed by pabyDstBuf.
     668                 :  *
     669                 :  * Passing pabyDstBuf = NULL will only move the read pointer by the
     670                 :  * specified number of bytes as if the copy had happened... but it 
     671                 :  * won't crash.
     672                 :  *
     673                 :  * Returns 0 if succesful or -1 if an error happened, in which case 
     674                 :  * CPLError() will have been called.
     675                 :  **********************************************************************/
     676            2849 : int     TABMAPCoordBlock::ReadBytes(int numBytes, GByte *pabyDstBuf)
     677                 : {
     678                 :     int nStatus;
     679                 : 
     680            2849 :     if (m_pabyBuf && 
     681                 :         m_nCurPos >= (m_numDataBytes+MAP_COORD_HEADER_SIZE) && 
     682                 :         m_nNextCoordBlock > 0)
     683                 :     {
     684                 :         // We're at end of current block... advance to next block.
     685                 : 
     686              10 :         if ( (nStatus=GotoByteInFile(m_nNextCoordBlock, TRUE)) != 0)
     687                 :         {
     688                 :             // Failed.... an error has already been reported.
     689               0 :             return nStatus;
     690                 :         }
     691                 : 
     692              10 :         GotoByteInBlock(MAP_COORD_HEADER_SIZE); // Move pointer past header
     693              10 :         m_numBlocksInChain++;
     694                 :     }
     695                 : 
     696            2849 :     if (m_pabyBuf && 
     697                 :         m_nCurPos < (m_numDataBytes+MAP_COORD_HEADER_SIZE) && 
     698                 :         m_nCurPos+numBytes > (m_numDataBytes+MAP_COORD_HEADER_SIZE) && 
     699                 :         m_nNextCoordBlock > 0)
     700                 :     {
     701                 :         // Data overlaps on more than one block
     702                 :         // Read until end of this block and then recursively call ReadBytes()
     703                 :         // for the rest.
     704                 :         int numBytesInThisBlock = 
     705               0 :                       (m_numDataBytes+MAP_COORD_HEADER_SIZE)-m_nCurPos;
     706               0 :         nStatus = TABRawBinBlock::ReadBytes(numBytesInThisBlock, pabyDstBuf);
     707               0 :         if (nStatus == 0)
     708                 :             nStatus = TABMAPCoordBlock::ReadBytes(numBytes-numBytesInThisBlock,
     709               0 :                                                pabyDstBuf+numBytesInThisBlock);
     710               0 :         return nStatus;
     711                 :     }
     712                 : 
     713                 : 
     714            2849 :     return TABRawBinBlock::ReadBytes(numBytes, pabyDstBuf);
     715                 : }
     716                 : 
     717                 : 
     718                 : /**********************************************************************
     719                 :  *                   TABMAPCoordBlock::WriteBytes()
     720                 :  *
     721                 :  * Cover function for TABRawBinBlock::WriteBytes() that will automagically
     722                 :  * CommitToFile() the current block and create a new one if we are at 
     723                 :  * the end of the current block.
     724                 :  *
     725                 :  * Then the control is passed to TABRawBinBlock::WriteBytes() to finish the
     726                 :  * work.
     727                 :  *
     728                 :  * Passing pabySrcBuf = NULL will only move the write pointer by the
     729                 :  * specified number of bytes as if the copy had happened... but it 
     730                 :  * won't crash.
     731                 :  *
     732                 :  * Returns 0 if succesful or -1 if an error happened, in which case 
     733                 :  * CPLError() will have been called.
     734                 :  **********************************************************************/
     735             601 : int  TABMAPCoordBlock::WriteBytes(int nBytesToWrite, GByte *pabySrcBuf)
     736                 : {
     737             601 :     if (m_eAccess != TABWrite && m_eAccess != TABReadWrite )
     738                 :     {
     739                 :         CPLError(CE_Failure, CPLE_AppDefined,
     740               0 :                  "WriteBytes(): Block does not support write operations.");
     741               0 :         return -1;
     742                 :     }
     743                 : 
     744             601 :     if (m_poBlockManagerRef && (m_nBlockSize - m_nCurPos) < nBytesToWrite)
     745                 :     {
     746               2 :         if (nBytesToWrite <= (m_nBlockSize-MAP_COORD_HEADER_SIZE))
     747                 :         {
     748                 :             // Data won't fit in this block but can fit inside a single
     749                 :             // block, so we'll allocate a new block for it.  This will 
     750                 :             // prevent us from overlapping coordinate values on 2 blocks, but
     751                 :             // still allows strings longer than one block (see 'else' below).
     752                 :             //
     753                 : 
     754               2 :             if ( m_nNextCoordBlock != 0 )
     755                 :             {
     756                 :                 // We're in read/write mode and there is already an allocated
     757                 :                 // block following this one in the chain ... just reload it 
     758                 :                 // and continue writing to it
     759                 : 
     760               0 :                 CPLAssert( m_eAccess == TABReadWrite );
     761                 : 
     762               0 :                 if (CommitToFile() != 0 ||
     763               0 :                      ReadFromFile(m_fp, m_nNextCoordBlock, m_nBlockSize) != 0)
     764                 :                 {
     765                 :                     // An error message should have already been reported.
     766               0 :                     return -1;
     767                 :                 }
     768                 :             }
     769                 :             else
     770                 :             {
     771                 :                 // Need to alloc a new block.
     772                 : 
     773               2 :                 int nNewBlockOffset = m_poBlockManagerRef->AllocNewBlock();
     774               2 :                 SetNextCoordBlock(nNewBlockOffset);
     775                 : 
     776               4 :                 if (CommitToFile() != 0 ||
     777               2 :                     InitNewBlock(m_fp, m_nBlockSize, nNewBlockOffset) != 0)
     778                 :                 {
     779                 :                     // An error message should have already been reported.
     780               0 :                     return -1;
     781                 :                 }
     782                 : 
     783               2 :                 m_numBlocksInChain++;
     784                 :             }
     785                 :         }
     786                 :         else
     787                 :         {
     788                 :             // Data to write is longer than one block... so we'll have to
     789                 :             // split it over multiple block through multiple calls.
     790                 :             //
     791               0 :             int nStatus = 0;
     792               0 :             while(nStatus == 0 && nBytesToWrite > 0)
     793                 :             {
     794               0 :                 int nBytes = m_nBlockSize-MAP_COORD_HEADER_SIZE;
     795               0 :                 if ( (m_nBlockSize - m_nCurPos) > 0 )
     796                 :                 {
     797                 :                     // Use free room in current block
     798               0 :                     nBytes = (m_nBlockSize - m_nCurPos);
     799                 :                 }
     800                 : 
     801               0 :                 nBytes = MIN(nBytes, nBytesToWrite);
     802                 : 
     803                 :                 // The following call will result in a new block being 
     804                 :                 // allocated in the if() block above.
     805                 :                 nStatus = TABMAPCoordBlock::WriteBytes(nBytes, 
     806               0 :                                                        pabySrcBuf);
     807                 : 
     808               0 :                 nBytesToWrite -= nBytes;
     809               0 :                 pabySrcBuf += nBytes;
     810                 :             }
     811               0 :             return nStatus;
     812                 :         }
     813                 :     }
     814                 : 
     815             601 :     if (m_nCurPos >= MAP_COORD_HEADER_SIZE)
     816                 :     {
     817                 :         // Keep track of Coordinate data... this means ignore header bytes
     818                 :         // that could be written.
     819             577 :         m_nTotalDataSize += nBytesToWrite;
     820             577 :         m_nFeatureDataSize += nBytesToWrite;
     821                 :     }
     822                 : 
     823             601 :     return TABRawBinBlock::WriteBytes(nBytesToWrite, pabySrcBuf);
     824                 : }
     825                 : 
     826                 : /**********************************************************************
     827                 :  *                   TABMAPObjectBlock::SeekEnd()
     828                 :  *
     829                 :  * Move read/write pointer to end of used part of the block
     830                 :  **********************************************************************/
     831              11 : void     TABMAPCoordBlock::SeekEnd()
     832                 : {
     833              11 :     m_nCurPos = m_nSizeUsed;
     834              11 : }
     835                 : 
     836                 : /**********************************************************************
     837                 :  *                   TABMAPCoordBlock::StartNewFeature()
     838                 :  *
     839                 :  * Reset all member vars that are used to keep track of data size
     840                 :  * and MBR for the current feature.  This is info is not needed by
     841                 :  * the coord blocks themselves, but it helps a lot the callers to
     842                 :  * have this class take care of that for them.
     843                 :  *
     844                 :  * See Also: GetFeatureDataSize() and GetFeatureMBR()
     845                 :  **********************************************************************/
     846              11 : void TABMAPCoordBlock::StartNewFeature()
     847                 : {
     848              11 :     m_nFeatureDataSize = 0;
     849                 : 
     850              11 :     m_nFeatureXMin = 1000000000;
     851              11 :     m_nFeatureYMin = 1000000000;
     852              11 :     m_nFeatureXMax = -1000000000;
     853              11 :     m_nFeatureYMax = -1000000000;
     854              11 : }
     855                 : 
     856                 : /**********************************************************************
     857                 :  *                   TABMAPCoordBlock::GetFeatureMBR()
     858                 :  *
     859                 :  * Return the MBR of all the coords written using WriteIntCoord() since
     860                 :  * the last call to StartNewFeature().
     861                 :  **********************************************************************/
     862               0 : void TABMAPCoordBlock::GetFeatureMBR(GInt32 &nXMin, GInt32 &nYMin, 
     863                 :                                      GInt32 &nXMax, GInt32 &nYMax)
     864                 : {
     865               0 :     nXMin = m_nFeatureXMin;
     866               0 :     nYMin = m_nFeatureYMin;
     867               0 :     nXMax = m_nFeatureXMax;
     868               0 :     nYMax = m_nFeatureYMax; 
     869               0 : }
     870                 : 
     871                 : 
     872                 : /**********************************************************************
     873                 :  *                   TABMAPCoordBlock::Dump()
     874                 :  *
     875                 :  * Dump block contents... available only in DEBUG mode.
     876                 :  **********************************************************************/
     877                 : #ifdef DEBUG
     878                 : 
     879               0 : void TABMAPCoordBlock::Dump(FILE *fpOut /*=NULL*/)
     880                 : {
     881               0 :     if (fpOut == NULL)
     882               0 :         fpOut = stdout;
     883                 : 
     884               0 :     fprintf(fpOut, "----- TABMAPCoordBlock::Dump() -----\n");
     885               0 :     if (m_pabyBuf == NULL)
     886                 :     {
     887               0 :         fprintf(fpOut, "Block has not been initialized yet.");
     888                 :     }
     889                 :     else
     890                 :     {
     891                 :         fprintf(fpOut,"Coordinate Block (type %d) at offset %d.\n", 
     892               0 :                                                  m_nBlockType, m_nFileOffset);
     893               0 :         fprintf(fpOut,"  m_numDataBytes        = %d\n", m_numDataBytes);
     894               0 :         fprintf(fpOut,"  m_nNextCoordBlock     = %d\n", m_nNextCoordBlock);
     895                 :     }
     896                 : 
     897               0 :     fflush(fpOut);
     898               0 : }
     899                 : 
     900                 : #endif // DEBUG
     901                 : 
     902                 : 
     903                 : 

Generated by: LCOV version 1.7