LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/mitab - mitab_mapheaderblock.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 281 428 65.7 %
Date: 2024-11-21 22:18:42 Functions: 17 19 89.5 %

          Line data    Source code
       1             : /**********************************************************************
       2             :  *
       3             :  * Name:     mitab_mapheaderblock.cpp
       4             :  * Project:  MapInfo TAB Read/Write library
       5             :  * Language: C++
       6             :  * Purpose:  Implementation of the TABHeaderBlock class used to handle
       7             :  *           reading/writing of the .MAP files' header block
       8             :  * Author:   Daniel Morissette, dmorissette@dmsolutions.ca
       9             :  *
      10             :  **********************************************************************
      11             :  * Copyright (c) 1999-2002, Daniel Morissette
      12             :  * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
      13             :  *
      14             :  * SPDX-License-Identifier: MIT
      15             :  **********************************************************************/
      16             : 
      17             : #include "cpl_port.h"
      18             : #include "mitab.h"
      19             : 
      20             : #include <cmath>
      21             : #include <cstddef>
      22             : 
      23             : #include "cpl_conv.h"
      24             : #include "cpl_error.h"
      25             : #include "cpl_vsi.h"
      26             : #include "mitab_priv.h"
      27             : 
      28             : /*---------------------------------------------------------------------
      29             :  * Set various constants used in generating the header block.
      30             :  *--------------------------------------------------------------------*/
      31             : constexpr GInt32 HDR_MAGIC_COOKIE = 42424242;
      32             : constexpr GInt16 HDR_VERSION_NUMBER = 500;
      33             : 
      34             : constexpr GByte HDR_DEF_ORG_QUADRANT = 1;  // N-E Quadrant
      35             : constexpr GByte HDR_DEF_REFLECTXAXIS = 0;
      36             : 
      37             : /*---------------------------------------------------------------------
      38             :  * The header block starts with an array of map object length constants.
      39             :  *--------------------------------------------------------------------*/
      40             : constexpr GByte HDR_OBJ_LEN_ARRAY_SIZE = 73;
      41             : constexpr GByte gabyObjLenArray[HDR_OBJ_LEN_ARRAY_SIZE] = {
      42             :     0x00, 0x0a, 0x0e, 0x15, 0x0e, 0x16, 0x1b, 0xa2, 0xa6, 0xab, 0x1a,
      43             :     0x2a, 0x2f, 0xa5, 0xa9, 0xb5, 0xa7, 0xb5, 0xd9, 0x0f, 0x17, 0x23,
      44             :     0x13, 0x1f, 0x2b, 0x0f, 0x17, 0x23, 0x4f, 0x57, 0x63, 0x9c, 0xa4,
      45             :     0xa9, 0xa0, 0xa8, 0xad, 0xa4, 0xa8, 0xad, 0x16, 0x1a, 0x39, 0x0d,
      46             :     0x11, 0x37, 0xa5, 0xa9, 0xb5, 0xa4, 0xa8, 0xad, 0xb2, 0xb6, 0xdc,
      47             :     0xbd, 0xbd, 0xf4, 0x2b, 0x2f, 0x55, 0xc8, 0xcc, 0xd8, 0xc7, 0xcb,
      48             :     0xd0, 0xd3, 0xd7, 0xfd, 0xc2, 0xc2, 0xf9};
      49             : 
      50             : /*=====================================================================
      51             :  *                      class TABMAPHeaderBlock
      52             :  *====================================================================*/
      53             : 
      54             : /**********************************************************************
      55             :  *                   TABMAPHeaderBlock::TABMAPHeaderBlock()
      56             :  *
      57             :  * Constructor.
      58             :  **********************************************************************/
      59        2759 : TABMAPHeaderBlock::TABMAPHeaderBlock(TABAccess eAccessMode /*= TABRead*/)
      60        2759 :     : TABRawBinBlock(eAccessMode, TRUE)
      61             : {
      62             :     // TODO(schwehr): Consider using initializer list for most values.
      63        2759 :     InitMembersWithDefaultValues();
      64             : 
      65             :     // We don't want to reset it once it is set.
      66        2759 :     m_bIntBoundsOverflow = FALSE;
      67        2759 : }
      68             : 
      69             : /**********************************************************************
      70             :  *                   TABMAPHeaderBlock::~TABMAPHeaderBlock()
      71             :  *
      72             :  * Destructor.
      73             :  **********************************************************************/
      74        5518 : TABMAPHeaderBlock::~TABMAPHeaderBlock()
      75             : {
      76        5518 : }
      77             : 
      78             : /**********************************************************************
      79             :  *            TABMAPHeaderBlock::InitMembersWithDefaultValues()
      80             :  **********************************************************************/
      81        2884 : void TABMAPHeaderBlock::InitMembersWithDefaultValues()
      82             : {
      83             :     /*-----------------------------------------------------------------
      84             :      * Set acceptable default values for member vars.
      85             :      *----------------------------------------------------------------*/
      86        2884 :     m_nMAPVersionNumber = HDR_VERSION_NUMBER;
      87        2884 :     m_nRegularBlockSize = TAB_MIN_BLOCK_SIZE;
      88             : 
      89        2884 :     m_dCoordsys2DistUnits = 1.0;
      90        2884 :     m_nXMin = -1000000000;
      91        2884 :     m_nYMin = -1000000000;
      92        2884 :     m_nXMax = 1000000000;
      93        2884 :     m_nYMax = 1000000000;
      94        2884 :     m_bIntBoundsOverflow = FALSE;
      95             : 
      96        2884 :     m_nFirstIndexBlock = 0;
      97        2884 :     m_nFirstGarbageBlock = 0;
      98        2884 :     m_nFirstToolBlock = 0;
      99             : 
     100        2884 :     m_numPointObjects = 0;
     101        2884 :     m_numLineObjects = 0;
     102        2884 :     m_numRegionObjects = 0;
     103        2884 :     m_numTextObjects = 0;
     104        2884 :     m_nMaxCoordBufSize = 0;
     105             : 
     106        2884 :     m_nDistUnitsCode = 7;  // Meters
     107        2884 :     m_nMaxSpIndexDepth = 0;
     108        2884 :     m_nCoordPrecision = 3;                          // ??? 3 Digits of precision
     109        2884 :     m_nCoordOriginQuadrant = HDR_DEF_ORG_QUADRANT;  // ??? N-E quadrant
     110        2884 :     m_nReflectXAxisCoord = HDR_DEF_REFLECTXAXIS;
     111        2884 :     m_nMaxObjLenArrayId = HDR_OBJ_LEN_ARRAY_SIZE - 1;  // See gabyObjLenArray[]
     112        2884 :     m_numPenDefs = 0;
     113        2884 :     m_numBrushDefs = 0;
     114        2884 :     m_numSymbolDefs = 0;
     115        2884 :     m_numFontDefs = 0;
     116        2884 :     m_numMapToolBlocks = 0;
     117             : 
     118        2884 :     m_sProj.nProjId = 0;
     119        2884 :     m_sProj.nEllipsoidId = 0;
     120        2884 :     m_sProj.nUnitsId = 7;
     121        2884 :     m_sProj.nDatumId = 0;
     122        2884 :     m_XScale = 1000.0;  // Default coord range (before SetCoordSysBounds())
     123        2884 :     m_YScale = 1000.0;  // will be [-1000000.000 .. 1000000.000]
     124        2884 :     m_XDispl = 0.0;
     125        2884 :     m_YDispl = 0.0;
     126        2884 :     m_XPrecision = 0.0;  // not specified
     127        2884 :     m_YPrecision = 0.0;  // not specified
     128             : 
     129       20188 :     for (int i = 0; i < 6; i++)
     130       17304 :         m_sProj.adProjParams[i] = 0.0;
     131             : 
     132        2884 :     m_sProj.dDatumShiftX = 0.0;
     133        2884 :     m_sProj.dDatumShiftY = 0.0;
     134        2884 :     m_sProj.dDatumShiftZ = 0.0;
     135       17304 :     for (int i = 0; i < 5; i++)
     136       14420 :         m_sProj.adDatumParams[i] = 0.0;
     137             : 
     138        2884 :     m_sProj.nAffineFlag = 0;  // Only in version 500 and up
     139        2884 :     m_sProj.nAffineUnits = 7;
     140        2884 :     m_sProj.dAffineParamA = 0.0;
     141        2884 :     m_sProj.dAffineParamB = 0.0;
     142        2884 :     m_sProj.dAffineParamC = 0.0;
     143        2884 :     m_sProj.dAffineParamD = 0.0;
     144        2884 :     m_sProj.dAffineParamE = 0.0;
     145        2884 :     m_sProj.dAffineParamF = 0.0;
     146        2884 : }
     147             : 
     148             : /**********************************************************************
     149             :  *                   TABMAPHeaderBlock::InitBlockFromData()
     150             :  *
     151             :  * Perform some initialization on the block after its binary data has
     152             :  * been set or changed (or loaded from a file).
     153             :  *
     154             :  * Returns 0 if successful or -1 if an error happened, in which case
     155             :  * CPLError() will have been called.
     156             :  **********************************************************************/
     157        2634 : int TABMAPHeaderBlock::InitBlockFromData(GByte *pabyBuf, int nBlockSize,
     158             :                                          int nSizeUsed,
     159             :                                          GBool bMakeCopy /* = TRUE */,
     160             :                                          VSILFILE *fpSrc /* = NULL */,
     161             :                                          int nOffset /* = 0 */)
     162             : {
     163             :     /*-----------------------------------------------------------------
     164             :      * First of all, we must call the base class' InitBlockFromData()
     165             :      *----------------------------------------------------------------*/
     166        2634 :     const int nStatus = TABRawBinBlock::InitBlockFromData(
     167             :         pabyBuf, nBlockSize, nSizeUsed, bMakeCopy, fpSrc, nOffset);
     168        2634 :     if (nStatus != 0)
     169           0 :         return nStatus;
     170             : 
     171             :     /*-----------------------------------------------------------------
     172             :      * Validate block type
     173             :      * Header blocks have a magic cookie at byte 0x100
     174             :      *----------------------------------------------------------------*/
     175        2634 :     GotoByteInBlock(0x100);
     176        2634 :     const GInt32 nMagicCookie = ReadInt32();
     177        2634 :     if (nMagicCookie != HDR_MAGIC_COOKIE)
     178             :     {
     179           0 :         CPLError(CE_Failure, CPLE_FileIO,
     180             :                  "ReadFromFile(): Invalid Magic Cookie: got %d expected %d",
     181             :                  nMagicCookie, HDR_MAGIC_COOKIE);
     182           0 :         CPLFree(m_pabyBuf);
     183           0 :         m_pabyBuf = nullptr;
     184           0 :         return -1;
     185             :     }
     186             : 
     187             :     /*-----------------------------------------------------------------
     188             :      * Init member variables
     189             :      * Instead of having over 30 get/set methods, we'll make all data
     190             :      * members public and we will initialize them here.
     191             :      * For this reason, this class should be used with care.
     192             :      *----------------------------------------------------------------*/
     193        2634 :     GotoByteInBlock(0x104);
     194        2634 :     m_nMAPVersionNumber = ReadInt16();
     195        2634 :     m_nRegularBlockSize = ReadInt16();
     196        2634 :     if (m_nRegularBlockSize < TAB_MIN_BLOCK_SIZE)
     197             :     {
     198           0 :         CPLError(CE_Failure, CPLE_FileIO,
     199           0 :                  "ReadFromFile(): Invalid block size %d", m_nRegularBlockSize);
     200           0 :         CPLFree(m_pabyBuf);
     201           0 :         m_pabyBuf = nullptr;
     202           0 :         return -1;
     203             :     }
     204             : 
     205        2634 :     m_dCoordsys2DistUnits = ReadDouble();
     206        2634 :     m_nXMin = ReadInt32();
     207        2634 :     m_nYMin = ReadInt32();
     208        2634 :     m_nXMax = ReadInt32();
     209        2634 :     m_nYMax = ReadInt32();
     210        2634 :     if (m_nXMin > m_nXMax || m_nYMin > m_nYMax)
     211             :     {
     212           0 :         CPLError(CE_Warning, CPLE_AppDefined,
     213             :                  "Reading corrupted MBR from .map header");
     214           0 :         CPLErrorReset();
     215             :     }
     216             : 
     217        2634 :     GotoByteInBlock(0x130);  // Skip 16 unknown bytes
     218             : 
     219        2634 :     m_nFirstIndexBlock = ReadInt32();
     220        2634 :     m_nFirstGarbageBlock = ReadInt32();
     221        2634 :     m_nFirstToolBlock = ReadInt32();
     222             : 
     223        2634 :     m_numPointObjects = ReadInt32();
     224        2634 :     m_numLineObjects = ReadInt32();
     225        2634 :     m_numRegionObjects = ReadInt32();
     226        2634 :     m_numTextObjects = ReadInt32();
     227        2634 :     m_nMaxCoordBufSize = ReadInt32();
     228             : 
     229        2634 :     GotoByteInBlock(0x15e);  // Skip 14 unknown bytes
     230             : 
     231        2634 :     m_nDistUnitsCode = ReadByte();
     232        2634 :     m_nMaxSpIndexDepth = ReadByte();
     233        2634 :     m_nCoordPrecision = ReadByte();
     234        2634 :     m_nCoordOriginQuadrant = ReadByte();
     235        2634 :     m_nReflectXAxisCoord = ReadByte();
     236        2634 :     m_nMaxObjLenArrayId = ReadByte();  // See gabyObjLenArray[]
     237        2634 :     m_numPenDefs = ReadByte();
     238        2634 :     m_numBrushDefs = ReadByte();
     239        2634 :     m_numSymbolDefs = ReadByte();
     240        2634 :     m_numFontDefs = ReadByte();
     241        2634 :     m_numMapToolBlocks = ReadByte();
     242             : 
     243        2634 :     ReadByte();  // skip unused byte
     244             : 
     245             :     /* DatumId was never set (always 0) until MapInfo 7.8. See bug 910
     246             :      * MAP Version Number is 500 in this case.
     247             :      */
     248        2634 :     if (m_nMAPVersionNumber >= 500)
     249        2634 :         m_sProj.nDatumId = ReadInt16();
     250             :     else
     251             :     {
     252           0 :         ReadInt16();  // Skip.
     253           0 :         m_sProj.nDatumId = 0;
     254             :     }
     255        2634 :     ReadByte();  // Skip unknown byte
     256        2634 :     m_sProj.nProjId = ReadByte();
     257        2634 :     m_sProj.nEllipsoidId = ReadByte();
     258        2634 :     m_sProj.nUnitsId = ReadByte();
     259        2634 :     m_XScale = ReadDouble();
     260        2634 :     m_YScale = ReadDouble();
     261        2634 :     if (m_XScale == 0.0 || m_YScale == 0.0)
     262             :     {
     263           0 :         CPLError(CE_Failure, CPLE_FileIO,
     264             :                  "ReadFromFile(): Null xscale and/or yscale");
     265           0 :         CPLFree(m_pabyBuf);
     266           0 :         m_pabyBuf = nullptr;
     267           0 :         return -1;
     268             :     }
     269        2634 :     m_XDispl = ReadDouble();
     270        2634 :     m_YDispl = ReadDouble();
     271             : 
     272             :     /* In V.100 files, the scale and displacement do not appear to be set.
     273             :      * we'll use m_nCoordPrecision to define the scale factor instead.
     274             :      */
     275        2634 :     if (m_nMAPVersionNumber <= 100)
     276             :     {
     277           0 :         m_XScale = pow(10.0, m_nCoordPrecision);
     278           0 :         m_YScale = m_XScale;
     279           0 :         m_XDispl = 0.0;
     280           0 :         m_YDispl = 0.0;
     281             :     }
     282             : 
     283       18438 :     for (int i = 0; i < 6; i++)
     284       15804 :         m_sProj.adProjParams[i] = ReadDouble();
     285             : 
     286        2634 :     m_sProj.dDatumShiftX = ReadDouble();
     287        2634 :     m_sProj.dDatumShiftY = ReadDouble();
     288        2634 :     m_sProj.dDatumShiftZ = ReadDouble();
     289       15804 :     for (int i = 0; i < 5; i++)
     290             :     {
     291             :         /* In V.200 files, the next 5 datum params are unused and they
     292             :          * sometimes contain junk bytes... in this case we set adDatumParams[]
     293             :          * to 0 for the rest of the lib to be happy.
     294             :          */
     295       13170 :         m_sProj.adDatumParams[i] = ReadDouble();
     296       13170 :         if (m_nMAPVersionNumber <= 200)
     297           0 :             m_sProj.adDatumParams[i] = 0.0;
     298             :     }
     299             : 
     300        2634 :     m_sProj.nAffineFlag = 0;
     301        2634 :     if (m_nMAPVersionNumber >= 500 && m_nSizeUsed > TAB_MIN_BLOCK_SIZE)
     302             :     {
     303             :         // Read Affine parameters A,B,C,D,E,F
     304             :         // only if version 500+ and block is larger than TAB_MIN_BLOCK_SIZE
     305             :         // bytes
     306        1317 :         int nInUse = ReadByte();
     307        1317 :         if (nInUse)
     308             :         {
     309           0 :             m_sProj.nAffineFlag = 1;
     310           0 :             m_sProj.nAffineUnits = ReadByte();
     311           0 :             GotoByteInBlock(0x0208);  // Skip unused bytes
     312           0 :             m_sProj.dAffineParamA = ReadDouble();
     313           0 :             m_sProj.dAffineParamB = ReadDouble();
     314           0 :             m_sProj.dAffineParamC = ReadDouble();
     315           0 :             m_sProj.dAffineParamD = ReadDouble();
     316           0 :             m_sProj.dAffineParamE = ReadDouble();
     317           0 :             m_sProj.dAffineParamF = ReadDouble();
     318             :         }
     319             :     }
     320             : 
     321        2634 :     if (m_sProj.nProjId == 35 && m_nMAPVersionNumber >= 500 &&
     322           2 :         m_nSizeUsed >= 0x0268 + 8)
     323             :     {
     324           1 :         GotoByteInBlock(0x0268);
     325           1 :         m_sProj.adProjParams[6] = ReadDouble();
     326             :     }
     327             : 
     328        2634 :     UpdatePrecision();
     329             : 
     330        2634 :     return 0;
     331             : }
     332             : 
     333             : /**********************************************************************
     334             :  *                   TABMAPHeaderBlock::Int2Coordsys()
     335             :  *
     336             :  * Convert from long integer (internal) to coordinates system units
     337             :  * as defined in the file's coordsys clause.
     338             :  *
     339             :  * Note that the false easting/northing and the conversion factor from
     340             :  * datum to coordsys units are not included in the calculation.
     341             :  *
     342             :  * Returns 0 on success, -1 on error.
     343             :  **********************************************************************/
     344      628123 : int TABMAPHeaderBlock::Int2Coordsys(GInt32 nX, GInt32 nY, double &dX,
     345             :                                     double &dY)
     346             : {
     347      628123 :     if (m_pabyBuf == nullptr)
     348           0 :         return -1;
     349             : 
     350             :     // For some obscure reason, some guy decided that it would be
     351             :     // more fun to be able to define our own origin quadrant!
     352             :     //
     353             :     // In version 100 .tab files (version 400 .map), it is possible to have
     354             :     // a quadrant 0 and it should be treated the same way as quadrant 3
     355             : 
     356      628123 :     if (m_nCoordOriginQuadrant == 2 || m_nCoordOriginQuadrant == 3 ||
     357      628118 :         m_nCoordOriginQuadrant == 0)
     358           5 :         dX = -1.0 * (nX + m_XDispl) / m_XScale;
     359             :     else
     360      628118 :         dX = (nX - m_XDispl) / m_XScale;
     361             : 
     362      628123 :     if (m_nCoordOriginQuadrant == 3 || m_nCoordOriginQuadrant == 4 ||
     363      628123 :         m_nCoordOriginQuadrant == 0)
     364           0 :         dY = -1.0 * (nY + m_YDispl) / m_YScale;
     365             :     else
     366      628123 :         dY = (nY - m_YDispl) / m_YScale;
     367             : 
     368             :     // Round coordinates to the desired precision
     369      628123 :     if (m_XPrecision > 0 && m_YPrecision > 0)
     370             :     {
     371      628113 :         dX = round(dX * m_XPrecision) / m_XPrecision;
     372      628113 :         dY = round(dY * m_YPrecision) / m_YPrecision;
     373             :     }
     374             :     // printf("Int2Coordsys: (%d, %d) -> (%.10g, %.10g)\n", nX, nY, dX, dY);
     375             : 
     376      628123 :     return 0;
     377             : }
     378             : 
     379             : /**********************************************************************
     380             :  *                   TABMAPHeaderBlock::Coordsys2Int()
     381             :  *
     382             :  * Convert from coordinates system units as defined in the file's
     383             :  * coordsys clause to long integer (internal) coordinates.
     384             :  *
     385             :  * Note that the false easting/northing and the conversion factor from
     386             :  * datum to coordsys units are not included in the calculation.
     387             :  *
     388             :  * Returns 0 on success, -1 on error.
     389             :  **********************************************************************/
     390      115469 : int TABMAPHeaderBlock::Coordsys2Int(double dX, double dY, GInt32 &nX,
     391             :                                     GInt32 &nY,
     392             :                                     GBool bIgnoreOverflow /*=FALSE*/)
     393             : {
     394      115469 :     if (m_pabyBuf == nullptr)
     395           0 :         return -1;
     396             : 
     397             :     // For some obscure reason, some guy decided that it would be
     398             :     // more fun to be able to define our own origin quadrant!
     399             :     //
     400             :     // In version 100 .tab files (version 400 .map), it is possible to have
     401             :     // a quadrant 0 and it should be treated the same way as quadrant 3
     402             : 
     403             :     /*-----------------------------------------------------------------
     404             :      * NOTE: double values must be used here, the limit of integer value
     405             :      * have been reached some times due to the very big numbers used here.
     406             :      *----------------------------------------------------------------*/
     407      115469 :     double dTempX = 0.0;
     408      115469 :     double dTempY = 0.0;
     409             : 
     410      115469 :     if (m_nCoordOriginQuadrant == 2 || m_nCoordOriginQuadrant == 3 ||
     411      115469 :         m_nCoordOriginQuadrant == 0)
     412           0 :         dTempX = -1.0 * dX * m_XScale - m_XDispl;
     413             :     else
     414      115469 :         dTempX = dX * m_XScale + m_XDispl;
     415             : 
     416      115469 :     if (m_nCoordOriginQuadrant == 3 || m_nCoordOriginQuadrant == 4 ||
     417      115469 :         m_nCoordOriginQuadrant == 0)
     418           0 :         dTempY = -1.0 * dY * m_YScale - m_YDispl;
     419             :     else
     420      115469 :         dTempY = dY * m_YScale + m_YDispl;
     421             : 
     422             :     /*-----------------------------------------------------------------
     423             :      * Make sure we'll never output coordinates outside of the valid
     424             :      * integer coordinates range: (-1e9, -1e9) - (1e9, 1e9)
     425             :      * Integer coordinates outside of that range will confuse MapInfo.
     426             :      *----------------------------------------------------------------*/
     427      115469 :     GBool bIntBoundsOverflow = FALSE;
     428      115469 :     if (dTempX < -1000000000)
     429             :     {
     430           0 :         dTempX = -1000000000;
     431           0 :         bIntBoundsOverflow = TRUE;
     432             :     }
     433      115469 :     if (dTempX > 1000000000)
     434             :     {
     435           0 :         dTempX = 1000000000;
     436           0 :         bIntBoundsOverflow = TRUE;
     437             :     }
     438      115469 :     if (dTempY < -1000000000)
     439             :     {
     440           0 :         dTempY = -1000000000;
     441           0 :         bIntBoundsOverflow = TRUE;
     442             :     }
     443      115469 :     if (dTempY > 1000000000)
     444             :     {
     445           0 :         dTempY = 1000000000;
     446           0 :         bIntBoundsOverflow = TRUE;
     447             :     }
     448             : 
     449      115469 :     nX = static_cast<GInt32>(ROUND_INT(dTempX));
     450      115469 :     nY = static_cast<GInt32>(ROUND_INT(dTempY));
     451             : 
     452      115469 :     if (bIntBoundsOverflow && !bIgnoreOverflow)
     453             :     {
     454           0 :         m_bIntBoundsOverflow = TRUE;
     455             : #ifdef DEBUG
     456           0 :         CPLError(
     457             :             CE_Warning, static_cast<CPLErrorNum>(TAB_WarningBoundsOverflow),
     458             :             "Integer bounds overflow: (%f, %f) -> (%d, %d)\n", dX, dY, nX, nY);
     459             : #endif
     460             :     }
     461             : 
     462      115469 :     return 0;
     463             : }
     464             : 
     465             : /**********************************************************************
     466             :  *                   TABMAPHeaderBlock::ComprInt2Coordsys()
     467             :  *
     468             :  * Convert from compressed integer (internal) to coordinates system units
     469             :  * as defined in the file's coordsys clause.
     470             :  * The difference between long integer and compressed integer coords is
     471             :  * that compressed coordinates are scaled displacement relative to an
     472             :  * object centroid.
     473             :  *
     474             :  * Note that the false easting/northing and the conversion factor from
     475             :  * datum to coordsys units are not included in the calculation.
     476             :  *
     477             :  * Returns 0 on success, -1 on error.
     478             :  **********************************************************************/
     479           0 : int TABMAPHeaderBlock::ComprInt2Coordsys(GInt32 nCenterX, GInt32 nCenterY,
     480             :                                          int nDeltaX, int nDeltaY, double &dX,
     481             :                                          double &dY)
     482             : {
     483           0 :     if (m_pabyBuf == nullptr)
     484           0 :         return -1;
     485             : 
     486           0 :     return Int2Coordsys(nCenterX + nDeltaX, nCenterY + nDeltaY, dX, dY);
     487             : }
     488             : 
     489             : /**********************************************************************
     490             :  *                   TABMAPHeaderBlock::Int2CoordsysDist()
     491             :  *
     492             :  * Convert a pair of X and Y size (or distance) value from long integer
     493             :  * (internal) to coordinates system units as defined in the file's
     494             :  * coordsys clause.
     495             :  *
     496             :  * The difference with Int2Coordsys() is that this function only applies
     497             :  * the scaling factor: it does not apply the displacement.
     498             :  *
     499             :  * Since the calculations on the X and Y values are independent, either
     500             :  * one can be omitted (i.e. passed as 0)
     501             :  *
     502             :  * Returns 0 on success, -1 on error.
     503             :  **********************************************************************/
     504          12 : int TABMAPHeaderBlock::Int2CoordsysDist(GInt32 nX, GInt32 nY, double &dX,
     505             :                                         double &dY)
     506             : {
     507          12 :     if (m_pabyBuf == nullptr)
     508           0 :         return -1;
     509             : 
     510          12 :     dX = nX / m_XScale;
     511          12 :     dY = nY / m_YScale;
     512             : 
     513          12 :     return 0;
     514             : }
     515             : 
     516             : /**********************************************************************
     517             :  *                   TABMAPHeaderBlock::Coordsys2IntDist()
     518             :  *
     519             :  * Convert a pair of X and Y size (or distance) values from coordinates
     520             :  * system units as defined in the file's coordsys clause to long integer
     521             :  * (internal) coordinates.
     522             :  *
     523             :  * The difference with Coordsys2Int() is that this function only applies
     524             :  * the scaling factor: it does not apply the displacement.
     525             :  *
     526             :  * Since the calculations on the X and Y values are independent, either
     527             :  * one can be omitted (i.e. passed as 0)
     528             :  *
     529             :  * Returns 0 on success, -1 on error.
     530             :  **********************************************************************/
     531           4 : int TABMAPHeaderBlock::Coordsys2IntDist(double dX, double dY, GInt32 &nX,
     532             :                                         GInt32 &nY)
     533             : {
     534           4 :     if (m_pabyBuf == nullptr)
     535           0 :         return -1;
     536             : 
     537           4 :     nX = static_cast<GInt32>(dX * m_XScale);
     538           4 :     nY = static_cast<GInt32>(dY * m_YScale);
     539             : 
     540           4 :     return 0;
     541             : }
     542             : 
     543             : /**********************************************************************
     544             :  *                   TABMAPHeaderBlock::SetCoordsysBounds()
     545             :  *
     546             :  * Take projection coordinates bounds of the newly created dataset and
     547             :  * compute new values for the X/Y Scales and X/Y displacement.
     548             :  *
     549             :  * This function must be called after creating a new dataset and before any
     550             :  * of the coordinates conversion functions can be used.
     551             :  *
     552             :  * Returns 0 on success, -1 on error.
     553             :  **********************************************************************/
     554         122 : int TABMAPHeaderBlock::SetCoordsysBounds(double dXMin, double dYMin,
     555             :                                          double dXMax, double dYMax)
     556             : {
     557             :     // printf("SetCoordsysBounds(%10g, %10g, %10g, %10g)\n", dXMin, dYMin,
     558             :     // dXMax, dYMax);
     559             :     /*-----------------------------------------------------------------
     560             :      * Check for 0-width or 0-height bounds
     561             :      *----------------------------------------------------------------*/
     562         122 :     if (dXMax == dXMin)
     563             :     {
     564           0 :         dXMin -= 1.0;
     565           0 :         dXMax += 1.0;
     566             :     }
     567             : 
     568         122 :     if (dYMax == dYMin)
     569             :     {
     570           0 :         dYMin -= 1.0;
     571           0 :         dYMax += 1.0;
     572             :     }
     573             : 
     574             :     /*-----------------------------------------------------------------
     575             :      * X and Y scales are used to map coordsys coordinates to integer
     576             :      * internal coordinates.  We want to find the scale and displacement
     577             :      * values that will result in an integer coordinate range of
     578             :      * (-1e9, -1e9) - (1e9, 1e9)
     579             :      *
     580             :      * Note that we ALWAYS generate datasets with the OriginQuadrant = 1
     581             :      * so that we avoid reverted X/Y axis complications, etc.
     582             :      *----------------------------------------------------------------*/
     583         122 :     m_XScale = 2e9 / (dXMax - dXMin);
     584         122 :     m_YScale = 2e9 / (dYMax - dYMin);
     585             : 
     586         122 :     m_XDispl = -1.0 * m_XScale * (dXMax + dXMin) / 2;
     587         122 :     m_YDispl = -1.0 * m_YScale * (dYMax + dYMin) / 2;
     588             : 
     589         122 :     m_nXMin = -1000000000;
     590         122 :     m_nYMin = -1000000000;
     591         122 :     m_nXMax = 1000000000;
     592         122 :     m_nYMax = 1000000000;
     593             : 
     594         122 :     UpdatePrecision();
     595             : 
     596         122 :     return 0;
     597             : }
     598             : 
     599             : /**********************************************************************
     600             :  *                   TABMAPHeaderBlock::GetMapObjectSize()
     601             :  *
     602             :  * Return the size of the object body for the specified object type.
     603             :  * The value is looked up in the first 256 bytes of the header.
     604             :  **********************************************************************/
     605      446426 : int TABMAPHeaderBlock::GetMapObjectSize(int nObjType)
     606             : {
     607      446426 :     if (m_pabyBuf == nullptr)
     608             :     {
     609           0 :         CPLError(CE_Failure, CPLE_AssertionFailed,
     610             :                  "Block has not been initialized yet!");
     611           0 :         return -1;
     612             :     }
     613             : 
     614      446426 :     if (nObjType < 0 || nObjType > 255)
     615             :     {
     616           0 :         CPLError(CE_Failure, CPLE_IllegalArg, "Invalid object type %d",
     617             :                  nObjType);
     618           0 :         return -1;
     619             :     }
     620             : 
     621             :     // Byte 0x80 is set for objects that have coordinates inside type 3 blocks
     622      446426 :     return m_pabyBuf[nObjType] & 0x7f;
     623             : }
     624             : 
     625             : /**********************************************************************
     626             :  *                   TABMAPHeaderBlock::MapObjectUsesCoordBlock()
     627             :  *
     628             :  * Return TRUE if the specified map object type has coordinates stored
     629             :  * inside type 3 coordinate blocks.
     630             :  * The info is looked up in the first 256 bytes of the header.
     631             :  **********************************************************************/
     632       23856 : GBool TABMAPHeaderBlock::MapObjectUsesCoordBlock(int nObjType)
     633             : {
     634       23856 :     if (m_pabyBuf == nullptr)
     635             :     {
     636           0 :         CPLError(CE_Failure, CPLE_AssertionFailed,
     637             :                  "Block has not been initialized yet!");
     638           0 :         return FALSE;
     639             :     }
     640             : 
     641       23856 :     if (nObjType < 0 || nObjType > 255)
     642             :     {
     643           0 :         CPLError(CE_Failure, CPLE_IllegalArg, "Invalid object type %d",
     644             :                  nObjType);
     645           0 :         return FALSE;
     646             :     }
     647             : 
     648             :     // Byte 0x80 is set for objects that have coordinates inside type 3 blocks
     649             : 
     650       23856 :     return ((m_pabyBuf[nObjType] & 0x80) != 0) ? TRUE : FALSE;
     651             : }
     652             : 
     653             : /**********************************************************************
     654             :  *                   TABMAPHeaderBlock::GetProjInfo()
     655             :  *
     656             :  * Fill the psProjInfo structure with the projection parameters previously
     657             :  * read from this header block.
     658             :  *
     659             :  * Returns 0 on success, -1 on error.
     660             :  **********************************************************************/
     661        1279 : int TABMAPHeaderBlock::GetProjInfo(TABProjInfo *psProjInfo)
     662             : {
     663        1279 :     if (m_pabyBuf == nullptr)
     664             :     {
     665           0 :         CPLError(CE_Failure, CPLE_AssertionFailed,
     666             :                  "Block has not been initialized yet!");
     667           0 :         return -1;
     668             :     }
     669             : 
     670        1279 :     if (psProjInfo)
     671        1279 :         *psProjInfo = m_sProj;
     672             : 
     673        1279 :     return 0;
     674             : }
     675             : 
     676             : /**********************************************************************
     677             :  *                   TABMAPHeaderBlock::SetProjInfo()
     678             :  *
     679             :  * Set the projection parameters for this dataset.
     680             :  *
     681             :  * Returns 0 on success, -1 on error.
     682             :  **********************************************************************/
     683          29 : int TABMAPHeaderBlock::SetProjInfo(TABProjInfo *psProjInfo)
     684             : {
     685          29 :     if (m_pabyBuf == nullptr)
     686             :     {
     687           0 :         CPLError(CE_Failure, CPLE_AssertionFailed,
     688             :                  "Block has not been initialized yet!");
     689           0 :         return -1;
     690             :     }
     691             : 
     692          29 :     if (psProjInfo)
     693          29 :         m_sProj = *psProjInfo;
     694             : 
     695          29 :     return 0;
     696             : }
     697             : 
     698             : /**********************************************************************
     699             :  *                   TABMAPHeaderBlock::CommitToFile()
     700             :  *
     701             :  * Commit the current state of the binary block to the file to which
     702             :  * it has been previously attached.
     703             :  *
     704             :  * This method makes sure all values are properly set in the header
     705             :  * block buffer and then calls TABRawBinBlock::CommitToFile() to do
     706             :  * the actual writing to disk.
     707             :  *
     708             :  * Returns 0 if successful or -1 if an error happened, in which case
     709             :  * CPLError() will have been called.
     710             :  **********************************************************************/
     711        1201 : int TABMAPHeaderBlock::CommitToFile()
     712             : {
     713             :     int i;
     714             : 
     715        1201 :     if (m_pabyBuf == nullptr || m_nRegularBlockSize == 0)
     716             :     {
     717           0 :         CPLError(CE_Failure, CPLE_AssertionFailed,
     718             :                  "TABRawBinBlock::CommitToFile(): Block has not been "
     719             :                  "initialized yet!");
     720           0 :         return -1;
     721             :     }
     722             : 
     723             :     /*-----------------------------------------------------------------
     724             :      * Reconstruct header to make sure it is in sync with members variables.
     725             :      *----------------------------------------------------------------*/
     726        1201 :     GotoByteInBlock(0x000);
     727        1201 :     WriteBytes(HDR_OBJ_LEN_ARRAY_SIZE, gabyObjLenArray);
     728        1201 :     m_nMaxObjLenArrayId = HDR_OBJ_LEN_ARRAY_SIZE - 1;
     729             : 
     730        1201 :     GotoByteInBlock(0x100);
     731        1201 :     WriteInt32(HDR_MAGIC_COOKIE);
     732             : 
     733        1201 :     if (m_sProj.nAffineFlag && m_nMAPVersionNumber < 500)
     734             :     {
     735             :         // Must be at least version 500 to support affine params
     736             :         // Default value for HDR_VERSION_NUMBER is 500 so this error should
     737             :         // never happen unless the caller changed the value, in which case they
     738             :         // deserve to get a failure
     739           0 :         CPLError(CE_Failure, CPLE_AssertionFailed,
     740             :                  "TABRawBinBlock::CommitToFile(): .MAP version 500 or more is "
     741             :                  "required for affine projection parameter support.");
     742           0 :         return -1;
     743             :     }
     744             : 
     745        1201 :     WriteInt16(m_nMAPVersionNumber);
     746             : 
     747        1201 :     WriteInt16(m_nRegularBlockSize);
     748             : 
     749        1201 :     WriteDouble(m_dCoordsys2DistUnits);
     750        1201 :     WriteInt32(m_nXMin);
     751        1201 :     WriteInt32(m_nYMin);
     752        1201 :     WriteInt32(m_nXMax);
     753        1201 :     WriteInt32(m_nYMax);
     754        1201 :     if (m_nXMin > m_nXMax || m_nYMin > m_nYMax)
     755             :     {
     756           0 :         CPLError(CE_Warning, CPLE_AppDefined,
     757             :                  "Writing corrupted MBR into .map header");
     758             :     }
     759             : 
     760        1201 :     WriteZeros(16);  // ???
     761             : 
     762        1201 :     WriteInt32(m_nFirstIndexBlock);
     763        1201 :     WriteInt32(m_nFirstGarbageBlock);
     764        1201 :     WriteInt32(m_nFirstToolBlock);
     765             : 
     766        1201 :     WriteInt32(m_numPointObjects);
     767        1201 :     WriteInt32(m_numLineObjects);
     768        1201 :     WriteInt32(m_numRegionObjects);
     769        1201 :     WriteInt32(m_numTextObjects);
     770        1201 :     WriteInt32(m_nMaxCoordBufSize);
     771             : 
     772        1201 :     WriteZeros(14);  // ???
     773             : 
     774        1201 :     WriteByte(m_nDistUnitsCode);
     775        1201 :     WriteByte(m_nMaxSpIndexDepth);
     776        1201 :     WriteByte(m_nCoordPrecision);
     777        1201 :     WriteByte(m_nCoordOriginQuadrant);
     778        1201 :     WriteByte(m_nReflectXAxisCoord);
     779        1201 :     WriteByte(m_nMaxObjLenArrayId);  // See gabyObjLenArray[]
     780        1201 :     WriteByte(m_numPenDefs);
     781        1201 :     WriteByte(m_numBrushDefs);
     782        1201 :     WriteByte(m_numSymbolDefs);
     783        1201 :     WriteByte(m_numFontDefs);
     784        1201 :     CPLAssert(m_numMapToolBlocks >= 0 && m_numMapToolBlocks <= 255);
     785        1201 :     WriteByte(static_cast<GByte>(m_numMapToolBlocks));
     786             : 
     787        1201 :     WriteZeros(1);  // unused byte
     788        1201 :     WriteInt16(m_sProj.nDatumId);
     789        1201 :     WriteZeros(1);  // unused byte
     790             : 
     791        1201 :     WriteByte(m_sProj.nProjId);
     792        1201 :     WriteByte(m_sProj.nEllipsoidId);
     793        1201 :     WriteByte(m_sProj.nUnitsId);
     794        1201 :     WriteDouble(m_XScale);
     795        1201 :     WriteDouble(m_YScale);
     796        1201 :     WriteDouble(m_XDispl);
     797        1201 :     WriteDouble(m_YDispl);
     798             : 
     799        8407 :     for (i = 0; i < 6; i++)
     800        7206 :         WriteDouble(m_sProj.adProjParams[i]);
     801             : 
     802        1201 :     WriteDouble(m_sProj.dDatumShiftX);
     803        1201 :     WriteDouble(m_sProj.dDatumShiftY);
     804        1201 :     WriteDouble(m_sProj.dDatumShiftZ);
     805        7206 :     for (i = 0; i < 5; i++)
     806        6005 :         WriteDouble(m_sProj.adDatumParams[i]);
     807             : 
     808        1201 :     if (m_sProj.nAffineFlag)
     809             :     {
     810           0 :         WriteByte(1);  // In Use Flag
     811           0 :         WriteByte(m_sProj.nAffineUnits);
     812           0 :         WriteZeros(6);
     813           0 :         WriteDouble(m_sProj.dAffineParamA);
     814           0 :         WriteDouble(m_sProj.dAffineParamB);
     815           0 :         WriteDouble(m_sProj.dAffineParamC);
     816           0 :         WriteDouble(m_sProj.dAffineParamD);
     817           0 :         WriteDouble(m_sProj.dAffineParamE);
     818           0 :         WriteDouble(m_sProj.dAffineParamF);
     819             : 
     820           0 :         WriteZeros(456);  // Pad rest of block with zeros (Bounds info here ?)
     821             :     }
     822             : 
     823        1201 :     if (m_nMAPVersionNumber >= 500 && m_nBlockSize == 1024 &&
     824        1201 :         m_sProj.nProjId == 35)
     825             :     {
     826           1 :         const auto nCurPosBak = m_nCurPos;
     827           1 :         if (m_nCurPos == 512)
     828           1 :             WriteZeros(512);
     829           1 :         m_nCurPos = 0x0268;
     830           1 :         WriteDouble(m_sProj.adProjParams[6]);
     831           1 :         m_nCurPos = nCurPosBak;
     832             :     }
     833             : 
     834             :     /*-----------------------------------------------------------------
     835             :      * OK, call the base class to write the block to disk.
     836             :      *----------------------------------------------------------------*/
     837             : #ifdef DEBUG_VERBOSE
     838             :     CPLDebug("MITAB", "Committing HEADER block to offset %d", m_nFileOffset);
     839             : #endif
     840        1201 :     return TABRawBinBlock::CommitToFile();
     841             : }
     842             : 
     843             : /**********************************************************************
     844             :  *                   TABMAPHeaderBlock::InitNewBlock()
     845             :  *
     846             :  * Initialize a newly created block so that it knows to which file it
     847             :  * is attached, its block size, etc . and then perform any specific
     848             :  * initialization for this block type, including writing a default
     849             :  * block header, etc. and leave the block ready to receive data.
     850             :  *
     851             :  * This is an alternative to calling ReadFromFile() or InitBlockFromData()
     852             :  * that puts the block in a stable state without loading any initial
     853             :  * data in it.
     854             :  *
     855             :  * Returns 0 if successful or -1 if an error happened, in which case
     856             :  * CPLError() will have been called.
     857             :  **********************************************************************/
     858         125 : int TABMAPHeaderBlock::InitNewBlock(VSILFILE *fpSrc, int nBlockSize,
     859             :                                     int nFileOffset /* = 0*/)
     860             : {
     861             :     /*-----------------------------------------------------------------
     862             :      * Start with the default initialization
     863             :      *----------------------------------------------------------------*/
     864             : 
     865             :     /* .MAP files of Version 500 and up appear to have a 1024 bytes
     866             :      * header.  The last 512 bytes are usually all zeros. */
     867         125 :     if (TABRawBinBlock::InitNewBlock(fpSrc, 1024, nFileOffset) != 0)
     868           0 :         return -1;
     869             : 
     870             :     /*-----------------------------------------------------------------
     871             :      * Set acceptable default values for member vars.
     872             :      *----------------------------------------------------------------*/
     873         125 :     InitMembersWithDefaultValues();
     874             : 
     875         125 :     CPLAssert(nBlockSize >= 0 && nBlockSize <= 32767);
     876         125 :     m_nRegularBlockSize = static_cast<GInt16>(nBlockSize);
     877             : 
     878             :     /*-----------------------------------------------------------------
     879             :      * And Set the map object length array in the buffer...
     880             :      *----------------------------------------------------------------*/
     881         125 :     if (m_eAccess != TABRead)
     882             :     {
     883         123 :         GotoByteInBlock(0x000);
     884         123 :         WriteBytes(HDR_OBJ_LEN_ARRAY_SIZE, gabyObjLenArray);
     885             :     }
     886             : 
     887         125 :     if (CPLGetLastErrorType() == CE_Failure)
     888           0 :         return -1;
     889             : 
     890         125 :     return 0;
     891             : }
     892             : 
     893             : /**********************************************************************
     894             :  * TABMAPHeaderBlock::UpdatePrecision()
     895             :  *
     896             :  * Update x and y maximum achievable precision given current scales
     897             :  * (m_XScale and m_YScale)
     898             :  **********************************************************************/
     899        2756 : void TABMAPHeaderBlock::UpdatePrecision()
     900             : {
     901        2756 :     m_XPrecision = pow(10.0, round(log10(m_XScale)));
     902        2756 :     m_YPrecision = pow(10.0, round(log10(m_YScale)));
     903        2756 : }
     904             : 
     905             : /**********************************************************************
     906             :  *                   TABMAPHeaderBlock::Dump()
     907             :  *
     908             :  * Dump block contents... available only in DEBUG mode.
     909             :  **********************************************************************/
     910             : #ifdef DEBUG
     911             : 
     912           0 : void TABMAPHeaderBlock::Dump(FILE *fpOut /*=NULL*/)
     913             : {
     914           0 :     if (fpOut == nullptr)
     915           0 :         fpOut = stdout;
     916             : 
     917           0 :     fprintf(fpOut, "----- TABMAPHeaderBlock::Dump() -----\n");
     918             : 
     919           0 :     if (m_pabyBuf == nullptr)
     920             :     {
     921           0 :         fprintf(fpOut, "Block has not been initialized yet.");
     922             :     }
     923             :     else
     924             :     {
     925           0 :         fprintf(fpOut, "Version %d header block.\n", m_nMAPVersionNumber);
     926           0 :         fprintf(fpOut, "  m_nRegularBlockSize       = %d\n",
     927           0 :                 m_nRegularBlockSize);
     928           0 :         fprintf(fpOut, "  m_nFirstIndexBlock    = %d\n", m_nFirstIndexBlock);
     929           0 :         fprintf(fpOut, "  m_nFirstGarbageBlock  = %d\n", m_nFirstGarbageBlock);
     930           0 :         fprintf(fpOut, "  m_nFirstToolBlock     = %d\n", m_nFirstToolBlock);
     931           0 :         fprintf(fpOut, "  m_numPointObjects     = %d\n", m_numPointObjects);
     932           0 :         fprintf(fpOut, "  m_numLineObjects      = %d\n", m_numLineObjects);
     933           0 :         fprintf(fpOut, "  m_numRegionObjects    = %d\n", m_numRegionObjects);
     934           0 :         fprintf(fpOut, "  m_numTextObjects      = %d\n", m_numTextObjects);
     935           0 :         fprintf(fpOut, "  m_nMaxCoordBufSize    = %d\n", m_nMaxCoordBufSize);
     936             : 
     937           0 :         fprintf(fpOut, "\n");
     938           0 :         fprintf(fpOut, "  m_dCoordsys2DistUnits = %g\n", m_dCoordsys2DistUnits);
     939           0 :         fprintf(fpOut, "  m_nXMin               = %d\n", m_nXMin);
     940           0 :         fprintf(fpOut, "  m_nYMin               = %d\n", m_nYMin);
     941           0 :         fprintf(fpOut, "  m_nXMax               = %d\n", m_nXMax);
     942           0 :         fprintf(fpOut, "  m_nYMax               = %d\n", m_nYMax);
     943           0 :         fprintf(fpOut, "  m_XScale              = %g\n", m_XScale);
     944           0 :         fprintf(fpOut, "  m_YScale              = %g\n", m_YScale);
     945           0 :         fprintf(fpOut, "  m_XDispl              = %g\n", m_XDispl);
     946           0 :         fprintf(fpOut, "  m_YDispl              = %g\n", m_YDispl);
     947             : 
     948           0 :         fprintf(fpOut, "\n");
     949           0 :         fprintf(fpOut, "  m_nDistUnistCode      = %d\n", m_nDistUnitsCode);
     950           0 :         fprintf(fpOut, "  m_nMaxSpIndexDepth    = %d\n", m_nMaxSpIndexDepth);
     951           0 :         fprintf(fpOut, "  m_nCoordPrecision     = %d\n", m_nCoordPrecision);
     952           0 :         fprintf(fpOut, "  m_nCoordOriginQuadrant= %d\n",
     953           0 :                 m_nCoordOriginQuadrant);
     954           0 :         fprintf(fpOut, "  m_nReflecXAxisCoord   = %d\n", m_nReflectXAxisCoord);
     955           0 :         fprintf(fpOut, "  m_nMaxObjLenArrayId   = %d\n", m_nMaxObjLenArrayId);
     956           0 :         fprintf(fpOut, "  m_numPenDefs          = %d\n", m_numPenDefs);
     957           0 :         fprintf(fpOut, "  m_numBrushDefs        = %d\n", m_numBrushDefs);
     958           0 :         fprintf(fpOut, "  m_numSymbolDefs       = %d\n", m_numSymbolDefs);
     959           0 :         fprintf(fpOut, "  m_numFontDefs         = %d\n", m_numFontDefs);
     960           0 :         fprintf(fpOut, "  m_numMapToolBlocks    = %d\n", m_numMapToolBlocks);
     961             : 
     962           0 :         fprintf(fpOut, "\n");
     963           0 :         fprintf(fpOut, "  m_sProj.nDatumId      = %d\n", m_sProj.nDatumId);
     964           0 :         fprintf(fpOut, "  m_sProj.nProjId       = %d\n",
     965           0 :                 static_cast<int>(m_sProj.nProjId));
     966           0 :         fprintf(fpOut, "  m_sProj.nEllipsoidId  = %d\n",
     967           0 :                 static_cast<int>(m_sProj.nEllipsoidId));
     968           0 :         fprintf(fpOut, "  m_sProj.nUnitsId      = %d\n",
     969           0 :                 static_cast<int>(m_sProj.nUnitsId));
     970           0 :         fprintf(fpOut, "  m_sProj.adProjParams  =");
     971           0 :         for (int i = 0; i < 6; i++)
     972           0 :             fprintf(fpOut, " %g", m_sProj.adProjParams[i]);
     973           0 :         fprintf(fpOut, "\n");
     974             : 
     975           0 :         fprintf(fpOut, "  m_sProj.dDatumShiftX  = %.15g\n",
     976             :                 m_sProj.dDatumShiftX);
     977           0 :         fprintf(fpOut, "  m_sProj.dDatumShiftY  = %.15g\n",
     978             :                 m_sProj.dDatumShiftY);
     979           0 :         fprintf(fpOut, "  m_sProj.dDatumShiftZ  = %.15g\n",
     980             :                 m_sProj.dDatumShiftZ);
     981           0 :         fprintf(fpOut, "  m_sProj.adDatumParams =");
     982           0 :         for (int i = 0; i < 5; i++)
     983           0 :             fprintf(fpOut, " %.15g", m_sProj.adDatumParams[i]);
     984           0 :         fprintf(fpOut, "\n");
     985             : 
     986             :         // Dump array of map object lengths... optional
     987             :         if (FALSE)
     988             :         {
     989             :             fprintf(fpOut,
     990             :                     "-- Header bytes 00-FF: Array of map object lengths --\n");
     991             :             for (int i = 0; i < 256; i++)
     992             :             {
     993             :                 fprintf(fpOut, "0x%2.2x", static_cast<int>(m_pabyBuf[i]));
     994             :                 if (i != 255)
     995             :                     fprintf(fpOut, ",");
     996             :                 if ((i + 1) % 16 == 0)
     997             :                     fprintf(fpOut, "\n");
     998             :             }
     999             :         }
    1000             :     }
    1001             : 
    1002           0 :     fflush(fpOut);
    1003           0 : }
    1004             : 
    1005             : #endif  // DEBUG

Generated by: LCOV version 1.14