LTP GCOV extension - code coverage report
Current view: directory - ogr/ogrsf_frmts/mitab - mitab_mapcoordblock.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 224
Code covered: 72.3 % Executed lines: 162

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

Generated by: LTP GCOV extension version 1.5