LCOV - code coverage report
Current view: directory - frmts/rmf - rmfdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 691 530 76.7 %
Date: 2010-01-09 Functions: 23 21 91.3 %

       1                 : /******************************************************************************
       2                 :  * $Id: rmfdataset.cpp 17636 2009-09-12 23:19:18Z warmerdam $
       3                 :  *
       4                 :  * Project:  Raster Matrix Format
       5                 :  * Purpose:  Read/write raster files used in GIS "Integratsia"
       6                 :  *           (also known as "Panorama" GIS).
       7                 :  * Author:   Andrey Kiselev, dron@ak4719.spb.edu
       8                 :  *
       9                 :  ******************************************************************************
      10                 :  * Copyright (c) 2005, Andrey Kiselev <dron@ak4719.spb.edu>
      11                 :  *
      12                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      13                 :  * copy of this software and associated documentation files (the "Software"),
      14                 :  * to deal in the Software without restriction, including without limitation
      15                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16                 :  * and/or sell copies of the Software, and to permit persons to whom the
      17                 :  * Software is furnished to do so, subject to the following conditions:
      18                 :  *
      19                 :  * The above copyright notice and this permission notice shall be included
      20                 :  * in all copies or substantial portions of the Software.
      21                 :  *
      22                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      23                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      25                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include "ogr_spatialref.h"
      31                 : #include "cpl_string.h"
      32                 : 
      33                 : #include "rmfdataset.h"
      34                 : 
      35                 : CPL_CVSID("$Id: rmfdataset.cpp 17636 2009-09-12 23:19:18Z warmerdam $");
      36                 : 
      37                 : CPL_C_START
      38                 : void    GDALRegister_RMF(void);
      39                 : CPL_C_END
      40                 : 
      41                 : #define RMF_DEFAULT_BLOCKXSIZE 256
      42                 : #define RMF_DEFAULT_BLOCKYSIZE 256
      43                 : 
      44                 : static const char RMF_SigRSW[] = { 'R', 'S', 'W', '\0' };
      45                 : static const char RMF_SigRSW_BE[] = { '\0', 'W', 'S', 'R' };
      46                 : static const char RMF_SigMTW[] = { 'M', 'T', 'W', '\0' };
      47                 : 
      48                 : static const char RMF_UnitsEmpty[] = "";
      49                 : static const char RMF_UnitsM[] = "m";
      50                 : static const char RMF_UnitsCM[] = "cm";
      51                 : static const char RMF_UnitsDM[] = "dm";
      52                 : static const char RMF_UnitsMM[] = "mm";
      53                 : 
      54                 : /************************************************************************/
      55                 : /* ==================================================================== */
      56                 : /*                            RMFRasterBand                             */
      57                 : /* ==================================================================== */
      58                 : /************************************************************************/
      59                 : 
      60                 : /************************************************************************/
      61                 : /*                           RMFRasterBand()                            */
      62                 : /************************************************************************/
      63                 : 
      64              49 : RMFRasterBand::RMFRasterBand( RMFDataset *poDS, int nBand,
      65              49 :                               GDALDataType eType )
      66                 : {
      67              49 :     this->poDS = poDS;
      68              49 :     this->nBand = nBand;
      69                 : 
      70              49 :     eDataType = eType;
      71              49 :     nBytesPerPixel = poDS->sHeader.nBitDepth / 8;
      72              49 :     nDataSize = GDALGetDataTypeSize( eDataType ) / 8;
      73              49 :     nBlockXSize = poDS->sHeader.nTileWidth;
      74              49 :     nBlockYSize = poDS->sHeader.nTileHeight;
      75              49 :     nBlockSize = nBlockXSize * nBlockYSize;
      76              49 :     nBlockBytes = nBlockSize * nDataSize;
      77                 :     nLastTileXBytes =
      78              49 :         (poDS->GetRasterXSize() % poDS->sHeader.nTileWidth) * nDataSize;
      79              49 :     nLastTileHeight = poDS->GetRasterYSize() % poDS->sHeader.nTileHeight;
      80                 : 
      81                 : #if DEBUG
      82                 :     CPLDebug( "RMF",
      83                 :               "Band %d: tile width is %d, tile height is %d, "
      84                 :               " last tile width %d, last tile height %d, "
      85                 :               "bytes per pixel is %d, data type size is %d",
      86                 :               nBand, nBlockXSize, nBlockYSize,
      87                 :               poDS->sHeader.nLastTileWidth, poDS->sHeader.nLastTileHeight,
      88                 :               nBytesPerPixel, nDataSize );
      89                 : #endif
      90              49 : }
      91                 : 
      92                 : /************************************************************************/
      93                 : /*                           ~RMFRasterBand()                           */
      94                 : /************************************************************************/
      95                 : 
      96              98 : RMFRasterBand::~RMFRasterBand()
      97                 : {
      98              98 : }
      99                 : 
     100                 : /************************************************************************/
     101                 : /*                             IReadBlock()                             */
     102                 : /************************************************************************/
     103                 : 
     104              13 : CPLErr RMFRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
     105                 :                                   void * pImage )
     106                 : {
     107              13 :     RMFDataset  *poGDS = (RMFDataset *) poDS;
     108              13 :     GUInt32     nTile = nBlockYOff * poGDS->nXTiles + nBlockXOff;
     109                 :     GUInt32     nTileBytes;
     110                 :     GUInt32     i, nCurBlockYSize;
     111                 : 
     112                 :     CPLAssert( poGDS != NULL
     113                 :                && nBlockXOff >= 0
     114                 :                && nBlockYOff >= 0
     115                 :                && pImage != NULL );
     116                 : 
     117              13 :     memset( pImage, 0, nBlockBytes );
     118                 : 
     119              13 :     if (2 * nTile + 1 >= poGDS->sHeader.nTileTblSize / sizeof(GUInt32))
     120                 :     {
     121               0 :         return CE_Failure;
     122                 :     }
     123                 : 
     124              13 :     nTileBytes = poGDS->paiTiles[2 * nTile + 1];
     125                 : 
     126              26 :     if ( poGDS->sHeader.nLastTileHeight
     127                 :          && (GUInt32) nBlockYOff == poGDS->nYTiles - 1 )
     128              13 :         nCurBlockYSize = poGDS->sHeader.nLastTileHeight;
     129                 :     else
     130               0 :         nCurBlockYSize = nBlockYSize;
     131                 : 
     132              13 :     if ( VSIFSeekL( poGDS->fp, poGDS->paiTiles[2 * nTile], SEEK_SET ) < 0 )
     133                 :     {
     134                 :         // XXX: We will not report error here, because file just may be
     135                 :   // in update state and data for this block will be available later
     136               0 :         if( poGDS->eAccess == GA_Update )
     137               0 :             return CE_None;
     138                 :         else
     139                 :         {
     140                 :             CPLError( CE_Failure, CPLE_FileIO,
     141                 :                 "Can't seek to offset %ld in input file to read data.\n%s\n",
     142               0 :                 (long) poGDS->paiTiles[2 * nTile], VSIStrerror( errno ) );
     143               0 :             return CE_Failure;
     144                 :         }
     145                 :     }
     146                 : 
     147              18 :     if ( poGDS->nBands == 1 &&
     148                 :          ( poGDS->sHeader.nBitDepth == 8
     149                 :            || poGDS->sHeader.nBitDepth == 16
     150                 :            || poGDS->sHeader.nBitDepth == 32
     151                 :            || poGDS->sHeader.nBitDepth == 64 ) )
     152                 :     {
     153               5 :         if ( nTileBytes > nBlockBytes )
     154               0 :             nTileBytes = nBlockBytes;
     155                 :     
     156               5 :         if ( VSIFReadL( pImage, 1, nTileBytes, poGDS->fp ) < nTileBytes )
     157                 :         {
     158                 :             // XXX
     159               0 :             if( poGDS->eAccess == GA_Update )
     160               0 :                 return CE_None;
     161                 :             else
     162                 :             {
     163                 :                 CPLError( CE_Failure, CPLE_FileIO,
     164                 :                           "Can't read from offset %ld in input file.\n%s\n",
     165               0 :                           (long) poGDS->paiTiles[2 * nTile], 
     166               0 :                           VSIStrerror( errno ) );
     167                 :                 // XXX: Do not fail here, just return empty block and continue
     168                 :                 // reading.
     169               0 :                 return CE_None;
     170                 :             }
     171                 :         }
     172                 : 
     173                 : #ifdef CPL_MSB
     174                 :         if ( poGDS->eRMFType == RMFT_MTW )
     175                 :         {
     176                 :             if ( poGDS->sHeader.nBitDepth == 16 )
     177                 :             {
     178                 :                 for ( i = 0; i < nTileBytes; i += 2 )
     179                 :                     CPL_SWAP16PTR( (GByte*)pImage + i );
     180                 :             }
     181                 : 
     182                 :             else if ( poGDS->sHeader.nBitDepth == 32 )
     183                 :             {
     184                 :                 for ( i = 0; i < nTileBytes; i += 4 )
     185                 :                     CPL_SWAP32PTR( (GByte*)pImage + i );
     186                 :             }
     187                 : 
     188                 :             else if ( poGDS->sHeader.nBitDepth == 64 )
     189                 :             {
     190                 :                 for ( i = 0; i < nTileBytes; i += 8 )
     191                 :                     CPL_SWAPDOUBLE( (GByte*)pImage + i );
     192                 :             }
     193                 :         }
     194                 : #endif
     195                 : 
     196                 :     }
     197                 : 
     198               8 :     else if ( poGDS->eRMFType == RMFT_RSW )
     199                 :     {
     200               8 :         GByte   *pabyTile = (GByte *) CPLMalloc( nTileBytes );
     201                 : 
     202               8 :         if ( VSIFReadL( pabyTile, 1, nTileBytes, poGDS->fp ) < nTileBytes )
     203                 :         {
     204                 :             // XXX
     205               0 :             if( poGDS->eAccess == GA_Update )
     206                 :             {
     207               0 :                 CPLFree( pabyTile );
     208               0 :                 return CE_None;
     209                 :             }
     210                 :             else
     211                 :             {
     212                 :                 CPLError( CE_Failure, CPLE_FileIO,
     213                 :                           "Can't read from offset %ld in input file.\n%s\n",
     214               0 :                           (long) poGDS->paiTiles[2 * nTile], 
     215               0 :                           VSIStrerror( errno ) );
     216                 :                 // XXX: Do not fail here, just return empty block and continue
     217                 :                 // reading.
     218               0 :                 CPLFree( pabyTile );
     219               0 :                 return CE_None;
     220                 :             }
     221                 :         }
     222                 : 
     223                 : /* -------------------------------------------------------------------- */
     224                 : /*  If buffer was compressed, decompress it first.                      */
     225                 : /* -------------------------------------------------------------------- */
     226                 :         GUInt32 nRawBytes;
     227               9 :         if ( nLastTileXBytes && (GUInt32)nBlockXOff == poGDS->nXTiles - 1 )
     228                 :         {
     229               1 :             nRawBytes = nLastTileXBytes;
     230               1 :             if ( nLastTileHeight && (GUInt32)nBlockYOff == poGDS->nYTiles - 1 )
     231               0 :                 nRawBytes *= nLastTileHeight;
     232                 :             else
     233               1 :                 nRawBytes *= nBlockYSize;
     234                 :         }
     235                 :         else
     236                 :         {
     237               7 :             nRawBytes = poGDS->nBands * nBlockXSize * nDataSize;
     238               7 :             if ( nLastTileHeight && (GUInt32)nBlockYOff == poGDS->nYTiles - 1 )
     239               0 :                 nRawBytes *= nLastTileHeight;
     240                 :             else
     241               7 :                 nRawBytes *= nBlockYSize;
     242                 :         }
     243                 : 
     244               8 :         if ( poGDS->Decompress && nRawBytes > nTileBytes )
     245                 :         {
     246               0 :             GByte *pszRawBuf = (GByte *)VSIMalloc( nRawBytes );
     247               0 :             if (pszRawBuf == NULL)
     248                 :             {
     249               0 :                 CPLFree( pabyTile );
     250               0 :                 return CE_Failure;
     251                 :             }
     252                 : 
     253               0 :             (*poGDS->Decompress)( pabyTile, nTileBytes, pszRawBuf, nRawBytes );
     254               0 :             CPLFree( pabyTile );
     255               0 :             pabyTile = pszRawBuf;
     256               0 :             nTileBytes = nRawBytes;
     257                 :         }
     258                 : 
     259                 : /* -------------------------------------------------------------------- */
     260                 : /*  Deinterleave pixels from input buffer.                              */
     261                 : /* -------------------------------------------------------------------- */
     262              16 :         if ( poGDS->sHeader.nBitDepth == 24 || poGDS->sHeader.nBitDepth == 32 )
     263                 :         {
     264               8 :             GUInt32 nTileSize = nTileBytes / nBytesPerPixel;
     265                 : 
     266               8 :             if ( nTileSize > nBlockSize )
     267               0 :                 nTileSize = nBlockSize;
     268                 : 
     269           27680 :             for ( i = 0; i < nTileSize; i++ )
     270                 :             {
     271                 :                 // Colour triplets in RMF file organized in reverse order:
     272                 :                 // blue, green, red. When we have 32-bit RMF the forth byte
     273                 :                 // in quadriplet should be discarded as it has no meaning.
     274                 :                 // That is why we always use 3 byte count in the following
     275                 :                 // pabyTemp index.
     276           27672 :                 ((GByte *) pImage)[i] =
     277           27672 :                     pabyTile[i * nBytesPerPixel + 3 - nBand];
     278                 :             }
     279                 :         }
     280                 : 
     281               0 :         else if ( poGDS->sHeader.nBitDepth == 16 )
     282                 :         {
     283               0 :             GUInt32 nTileSize = nTileBytes / nBytesPerPixel;
     284                 : 
     285               0 :             if ( nTileSize > nBlockSize )
     286               0 :                 nTileSize = nBlockSize;
     287                 : 
     288               0 :             for ( i = 0; i < nTileSize; i++ )
     289                 :             {
     290               0 :                 switch ( nBand )
     291                 :                 {
     292                 :                     case 1:
     293               0 :                         ((GByte *) pImage)[i] =
     294               0 :                             (GByte)((((GUInt16*)pabyTile)[i] & 0x7c00) >> 7);
     295               0 :                         break;
     296                 :                     case 2:
     297               0 :                         ((GByte *) pImage)[i] =
     298               0 :                             (GByte)((((GUInt16*)pabyTile)[i] & 0x03e0) >> 2);
     299               0 :                         break;
     300                 :                     case 3:
     301               0 :                         ((GByte *) pImage)[i] =
     302               0 :                             (GByte)(((GUInt16*)pabyTile)[i] & 0x1F) << 3;
     303                 :                         break;
     304                 :                     default:
     305                 :                         break;
     306                 :                 }
     307                 :             }
     308                 :         }
     309                 : 
     310               0 :         else if ( poGDS->sHeader.nBitDepth == 4 )
     311                 :         {
     312               0 :             GByte *pabyTemp = pabyTile;
     313                 : 
     314               0 :             for ( i = 0; i < nBlockSize; i++ )
     315                 :             {
     316                 :                 // Most significant part of the byte represents leftmost pixel
     317               0 :                 if ( i & 0x01 )
     318               0 :                     ((GByte *) pImage)[i] = *pabyTemp++ & 0x0F;
     319                 :                 else
     320               0 :                     ((GByte *) pImage)[i] = (*pabyTemp & 0xF0) >> 4;
     321                 :             }
     322                 :         }
     323                 : 
     324               0 :         else if ( poGDS->sHeader.nBitDepth == 1 )
     325                 :         {
     326               0 :             GByte *pabyTemp = pabyTile;
     327                 : 
     328               0 :             for ( i = 0; i < nBlockSize; i++ )
     329                 :             {
     330               0 :                 switch ( i & 0x7 )
     331                 :                 {
     332                 :                     case 0:
     333               0 :                         ((GByte *) pImage)[i] = (*pabyTemp & 0x80) >> 7;
     334               0 :                         break;
     335                 :                     case 1:
     336               0 :                         ((GByte *) pImage)[i] = (*pabyTemp & 0x40) >> 6;
     337               0 :                         break;
     338                 :                     case 2:
     339               0 :                         ((GByte *) pImage)[i] = (*pabyTemp & 0x20) >> 5;
     340               0 :                         break;
     341                 :                     case 3:
     342               0 :                         ((GByte *) pImage)[i] = (*pabyTemp & 0x10) >> 4;
     343               0 :                         break;
     344                 :                     case 4:
     345               0 :                         ((GByte *) pImage)[i] = (*pabyTemp & 0x08) >> 3;
     346               0 :                         break;
     347                 :                     case 5:
     348               0 :                         ((GByte *) pImage)[i] = (*pabyTemp & 0x04) >> 2;
     349               0 :                         break;
     350                 :                     case 6:
     351               0 :                         ((GByte *) pImage)[i] = (*pabyTemp & 0x02) >> 1;
     352               0 :                         break;
     353                 :                     case 7:
     354               0 :                         ((GByte *) pImage)[i] = *pabyTemp++ & 0x01;
     355                 :                         break;
     356                 :                     default:
     357                 :                         break;
     358                 :                 }
     359                 :             }
     360                 :         }
     361                 : 
     362               8 :         CPLFree( pabyTile );
     363                 :     }
     364                 : 
     365              13 :     if ( nLastTileXBytes
     366                 :          && (GUInt32) nBlockXOff == poGDS->nXTiles - 1 )
     367                 :     {
     368                 :         GUInt32 iRow;
     369                 : 
     370              96 :         for ( iRow = nCurBlockYSize - 1; iRow > 0; iRow-- )
     371                 :         {
     372                 :             memmove( (GByte *)pImage + nBlockXSize * iRow * nDataSize,
     373                 :                      (GByte *)pImage + iRow * nLastTileXBytes,
     374              95 :                      nLastTileXBytes );
     375                 :         }
     376                 :         
     377                 :     }
     378                 : 
     379              13 :     return CE_None;
     380                 : }
     381                 : 
     382                 : /************************************************************************/
     383                 : /*                            IWriteBlock()                             */
     384                 : /************************************************************************/
     385                 : 
     386               7 : CPLErr RMFRasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
     387                 :                                    void * pImage )
     388                 : {
     389               7 :     RMFDataset  *poGDS = (RMFDataset *)poDS;
     390               7 :     GUInt32     nTile = nBlockYOff * poGDS->nXTiles + nBlockXOff;
     391               7 :     GUInt32     nTileBytes = nDataSize * poGDS->nBands;
     392                 :     GUInt32     iInPixel, iOutPixel, nCurBlockYSize;
     393                 :     GByte       *pabyTile;
     394                 : 
     395                 :     CPLAssert( poGDS != NULL
     396                 :                && nBlockXOff >= 0
     397                 :                && nBlockYOff >= 0
     398                 :                && pImage != NULL );
     399                 : 
     400               7 :     if ( poGDS->paiTiles[2 * nTile] )
     401                 :     {
     402               4 :         if ( VSIFSeekL( poGDS->fp, poGDS->paiTiles[2 * nTile], SEEK_SET ) < 0 )
     403                 :         {
     404                 :             CPLError( CE_Failure, CPLE_FileIO,
     405                 :                 "Can't seek to offset %ld in output file to write data.\n%s",
     406               0 :                       (long) poGDS->paiTiles[2 * nTile], 
     407               0 :                       VSIStrerror( errno ) );
     408               0 :             return CE_Failure;
     409                 :         }
     410                 :     }
     411                 :     else
     412                 :     {
     413               3 :         if ( VSIFSeekL( poGDS->fp, 0, SEEK_END ) < 0 )
     414                 :         {
     415                 :             CPLError( CE_Failure, CPLE_FileIO,
     416                 :                 "Can't seek to offset %ld in output file to write data.\n%s",
     417               0 :                       (long) poGDS->paiTiles[2 * nTile], 
     418               0 :                       VSIStrerror( errno ) );
     419               0 :             return CE_Failure;
     420                 :         }
     421               3 :         poGDS->paiTiles[2 * nTile] = (GUInt32) VSIFTellL( poGDS->fp );
     422                 : 
     423               3 :         poGDS->bHeaderDirty = TRUE;
     424                 :     }
     425                 : 
     426               7 :     if ( nLastTileXBytes
     427                 :          && (GUInt32) nBlockXOff == poGDS->nXTiles - 1 )
     428               0 :         nTileBytes *= poGDS->sHeader.nLastTileWidth;
     429                 :     else
     430               7 :         nTileBytes *= nBlockXSize;
     431                 : 
     432              14 :     if ( poGDS->sHeader.nLastTileHeight
     433                 :          && (GUInt32) nBlockYOff == poGDS->nYTiles - 1 )
     434               7 :         nCurBlockYSize = poGDS->sHeader.nLastTileHeight;
     435                 :     else
     436               0 :         nCurBlockYSize = nBlockYSize;
     437                 : 
     438               7 :     nTileBytes *= nCurBlockYSize;
     439                 :         
     440               7 :     pabyTile = (GByte *) VSICalloc( nTileBytes, 1 );
     441               7 :     if ( !pabyTile )
     442                 :     {
     443                 :         CPLError( CE_Failure, CPLE_FileIO,
     444                 :                   "Can't allocate space for the tile buffer.\n%s",
     445               0 :                   VSIStrerror( errno ) );
     446               0 :         return CE_Failure;
     447                 :     }
     448                 : 
     449               7 :     if ( nLastTileXBytes
     450                 :          && (GUInt32) nBlockXOff == poGDS->nXTiles - 1 )
     451                 :     {
     452                 :         GUInt32 iRow;
     453                 : 
     454               0 :         if ( poGDS->nBands == 1 )
     455                 :         {
     456               0 :             for ( iRow = 0; iRow < nCurBlockYSize; iRow++ )
     457                 :             {
     458                 :                 memcpy( pabyTile + iRow * nLastTileXBytes,
     459                 :                          (GByte*)pImage + nBlockXSize * iRow * nDataSize,
     460               0 :                          nLastTileXBytes );
     461                 :             }
     462                 :         }
     463                 :         else
     464                 :         {
     465               0 :             if ( poGDS->paiTiles[2 * nTile + 1] )
     466                 :             {
     467               0 :                 VSIFReadL( pabyTile, 1, nTileBytes, poGDS->fp );
     468               0 :                 VSIFSeekL( poGDS->fp, poGDS->paiTiles[2 * nTile], SEEK_SET );
     469                 :             }
     470                 : 
     471               0 :             for ( iRow = 0; iRow < nCurBlockYSize; iRow++ )
     472                 :             {
     473               0 :                 for ( iInPixel = 0, iOutPixel = nBytesPerPixel - nBand;
     474                 :                       iOutPixel < nLastTileXBytes * poGDS->nBands;
     475                 :                       iInPixel++, iOutPixel += poGDS->nBands )
     476               0 :                     (pabyTile + iRow * nLastTileXBytes * poGDS->nBands)[iOutPixel] =
     477               0 :                         ((GByte *) pImage + nBlockXSize * iRow * nDataSize)[iInPixel];
     478                 :             }
     479                 :         }
     480                 :     }
     481                 :     else
     482                 :     {
     483               7 :         if ( poGDS->nBands == 1 )
     484               1 :             memcpy( pabyTile, pImage, nTileBytes );
     485                 :         else
     486                 :         {
     487               6 :             if ( poGDS->paiTiles[2 * nTile + 1] )
     488                 :             {
     489               4 :                 VSIFReadL( pabyTile, 1, nTileBytes, poGDS->fp );
     490               4 :                 VSIFSeekL( poGDS->fp, poGDS->paiTiles[2 * nTile], SEEK_SET );
     491                 :             }
     492                 : 
     493            7806 :             for ( iInPixel = 0, iOutPixel = nBytesPerPixel - nBand;
     494                 :                   iOutPixel < nTileBytes;
     495                 :                   iInPixel++, iOutPixel += poGDS->nBands )
     496            7800 :                 pabyTile[iOutPixel] = ((GByte *) pImage)[iInPixel];
     497                 : 
     498                 :         }
     499                 :     }
     500                 :     
     501                 : #ifdef CPL_MSB
     502                 :     if ( poGDS->eRMFType == RMFT_MTW )
     503                 :     {
     504                 :         GUInt32 i;
     505                 : 
     506                 :         if ( poGDS->sHeader.nBitDepth == 16 )
     507                 :         {
     508                 :             for ( i = 0; i < nTileBytes; i += 2 )
     509                 :                 CPL_SWAP16PTR( pabyTile + i );
     510                 :         }
     511                 : 
     512                 :         else if ( poGDS->sHeader.nBitDepth == 32 )
     513                 :         {
     514                 :             for ( i = 0; i < nTileBytes; i += 4 )
     515                 :                 CPL_SWAP32PTR( pabyTile + i );
     516                 :         }
     517                 : 
     518                 :         else if ( poGDS->sHeader.nBitDepth == 64 )
     519                 :         {
     520                 :             for ( i = 0; i < nTileBytes; i += 8 )
     521                 :                 CPL_SWAPDOUBLE( pabyTile + i );
     522                 :         }
     523                 :     }
     524                 : #endif
     525                 : 
     526               7 :     if ( VSIFWriteL( pabyTile, 1, nTileBytes, poGDS->fp ) < nTileBytes )
     527                 :     {
     528                 :         CPLError( CE_Failure, CPLE_FileIO,
     529                 :                   "Can't write block with X offset %d and Y offset %d.\n%s",
     530               0 :                   nBlockXOff, nBlockYOff, VSIStrerror( errno ) );
     531               0 :         VSIFree( pabyTile );
     532               0 :         return CE_Failure;
     533                 :     }
     534                 :     
     535               7 :     poGDS->paiTiles[2 * nTile + 1] = nTileBytes;
     536               7 :     VSIFree( pabyTile );
     537                 : 
     538               7 :     poGDS->bHeaderDirty = TRUE;
     539                 : 
     540               7 :     return CE_None;
     541                 : }
     542                 : 
     543                 : /************************************************************************/
     544                 : /*                            GetUnitType()                             */
     545                 : /************************************************************************/
     546                 : 
     547               0 : const char *RMFRasterBand::GetUnitType()
     548                 : 
     549                 : {
     550               0 :     RMFDataset   *poGDS = (RMFDataset *) poDS;
     551                 : 
     552               0 :     return (const char *)poGDS->pszUnitType;
     553                 : }
     554                 : 
     555                 : /************************************************************************/
     556                 : /*                            SetUnitType()                             */
     557                 : /************************************************************************/
     558                 : 
     559               0 : CPLErr RMFRasterBand::SetUnitType( const char *pszNewValue )
     560                 : 
     561                 : {
     562               0 :     RMFDataset   *poGDS = (RMFDataset *) poDS;
     563                 : 
     564               0 :     CPLFree(poGDS->pszUnitType);
     565               0 :     poGDS->pszUnitType = CPLStrdup( pszNewValue );
     566                 : 
     567               0 :     return CE_None;
     568                 : }
     569                 : 
     570                 : /************************************************************************/
     571                 : /*                           GetColorTable()                            */
     572                 : /************************************************************************/
     573                 : 
     574               4 : GDALColorTable *RMFRasterBand::GetColorTable()
     575                 : {
     576               4 :     RMFDataset   *poGDS = (RMFDataset *) poDS;
     577                 : 
     578               4 :     return poGDS->poColorTable;
     579                 : }
     580                 : 
     581                 : /************************************************************************/
     582                 : /*                           SetColorTable()                            */
     583                 : /************************************************************************/
     584                 : 
     585               1 : CPLErr RMFRasterBand::SetColorTable( GDALColorTable *poColorTable )
     586                 : {
     587               1 :     RMFDataset  *poGDS = (RMFDataset *) poDS;
     588                 : 
     589               1 :     if ( poColorTable )
     590                 :     {
     591               1 :         if ( poGDS->eRMFType == RMFT_RSW && poGDS->nBands == 1 )
     592                 :         {
     593                 :             GDALColorEntry  oEntry;
     594                 :             GUInt32         i;
     595                 : 
     596               1 :             if ( !poGDS->pabyColorTable )
     597               0 :                 return CE_Failure;
     598                 : 
     599             257 :             for( i = 0; i < poGDS->nColorTableSize; i++ )
     600                 :             {
     601             256 :                 poColorTable->GetColorEntryAsRGB( i, &oEntry );
     602             256 :                 poGDS->pabyColorTable[i * 4] = (GByte) oEntry.c1;     // Red
     603             256 :                 poGDS->pabyColorTable[i * 4 + 1] = (GByte) oEntry.c2; // Green
     604             256 :                 poGDS->pabyColorTable[i * 4 + 2] = (GByte) oEntry.c3; // Blue
     605             256 :                 poGDS->pabyColorTable[i * 4 + 3] = 0;
     606                 :             }
     607                 : 
     608               1 :             poGDS->bHeaderDirty = TRUE;
     609                 :         }
     610                 :     }
     611                 :     else
     612               0 :         return CE_Failure;
     613                 : 
     614               1 :     return CE_None;
     615                 : }
     616                 : 
     617                 : /************************************************************************/
     618                 : /*                       GetColorInterpretation()                       */
     619                 : /************************************************************************/
     620                 : 
     621              19 : GDALColorInterp RMFRasterBand::GetColorInterpretation()
     622                 : {
     623              19 :     RMFDataset      *poGDS = (RMFDataset *) poDS;
     624                 : 
     625              19 :     if( poGDS->nBands == 3 )
     626                 :     {
     627              12 :         if( nBand == 1 )
     628               4 :             return GCI_RedBand;
     629               8 :         else if( nBand == 2 )
     630               4 :             return GCI_GreenBand;
     631               4 :         else if( nBand == 3 )
     632               4 :             return GCI_BlueBand;
     633                 :         else
     634               0 :             return GCI_Undefined;
     635                 :     }
     636                 :     else
     637                 :     {
     638               7 :         if ( poGDS->eRMFType == RMFT_RSW )
     639               7 :             return GCI_PaletteIndex;
     640                 :         else
     641               0 :             return GCI_Undefined;
     642                 :     }
     643                 : }
     644                 : 
     645                 : /************************************************************************/
     646                 : /* ==================================================================== */
     647                 : /*                              RMFDataset                              */
     648                 : /* ==================================================================== */
     649                 : /************************************************************************/
     650                 : 
     651                 : /************************************************************************/
     652                 : /*                           RMFDataset()                               */
     653                 : /************************************************************************/
     654                 : 
     655              28 : RMFDataset::RMFDataset()
     656                 : {
     657              28 :     pszFilename = NULL;
     658              28 :     fp = NULL;
     659              28 :     nBands = 0;
     660              28 :     nXTiles = 0;
     661              28 :     nYTiles = 0;
     662              28 :     paiTiles = NULL;
     663              28 :     pszProjection = CPLStrdup( "" );
     664              28 :     pszUnitType = CPLStrdup( RMF_UnitsEmpty );
     665              28 :     adfGeoTransform[0] = 0.0;
     666              28 :     adfGeoTransform[1] = 1.0;
     667              28 :     adfGeoTransform[2] = 0.0;
     668              28 :     adfGeoTransform[3] = 0.0;
     669              28 :     adfGeoTransform[4] = 0.0;
     670              28 :     adfGeoTransform[5] = 1.0;
     671              28 :     pabyColorTable = NULL;
     672              28 :     poColorTable = NULL;
     673              28 :     eRMFType = RMFT_RSW;
     674              28 :     memset( &sHeader, 0, sizeof(sHeader) );
     675              28 :     memset( &sExtHeader, 0, sizeof(sExtHeader) );
     676                 : 
     677              28 :     Decompress = NULL;
     678                 : 
     679              28 :     bBigEndian = FALSE;
     680              28 :     bHeaderDirty = FALSE;
     681              28 : }
     682                 : 
     683                 : /************************************************************************/
     684                 : /*                            ~RMFDataset()                             */
     685                 : /************************************************************************/
     686                 : 
     687              56 : RMFDataset::~RMFDataset()
     688                 : {
     689              28 :     FlushCache();
     690                 : 
     691              28 :     if ( paiTiles )
     692              28 :         CPLFree( paiTiles );
     693              28 :     if ( pszProjection )
     694              28 :         CPLFree( pszProjection );
     695              28 :     if ( pszUnitType )
     696              28 :         CPLFree( pszUnitType );
     697              28 :     if ( pabyColorTable )
     698              15 :         CPLFree( pabyColorTable );
     699              28 :     if ( poColorTable != NULL )
     700               6 :         delete poColorTable;
     701              28 :     if( fp != NULL )
     702              28 :         VSIFCloseL( fp );
     703              56 : }
     704                 : 
     705                 : /************************************************************************/
     706                 : /*                          GetGeoTransform()                           */
     707                 : /************************************************************************/
     708                 : 
     709              11 : CPLErr RMFDataset::GetGeoTransform( double * padfTransform )
     710                 : {
     711              11 :     memcpy( padfTransform, adfGeoTransform, sizeof(adfGeoTransform[0]) * 6 );
     712                 : 
     713              11 :     if( sHeader.iGeorefFlag )
     714              11 :         return CE_None;
     715                 :     else
     716               0 :         return CE_Failure;
     717                 : }
     718                 : 
     719                 : /************************************************************************/
     720                 : /*                          SetGeoTransform()                           */
     721                 : /************************************************************************/
     722                 : 
     723               7 : CPLErr RMFDataset::SetGeoTransform( double * padfTransform )
     724                 : {
     725               7 :     memcpy( adfGeoTransform, padfTransform, sizeof(double) * 6 );
     726               7 :     sHeader.dfPixelSize = adfGeoTransform[1];
     727               7 :     if ( sHeader.dfPixelSize != 0.0 )
     728               7 :         sHeader.dfResolution = sHeader.dfScale / sHeader.dfPixelSize;
     729               7 :     sHeader.dfLLX = adfGeoTransform[0];
     730               7 :     sHeader.dfLLY = adfGeoTransform[3] - nRasterYSize * sHeader.dfPixelSize;
     731               7 :     sHeader.iGeorefFlag = 1;
     732                 : 
     733               7 :     bHeaderDirty = TRUE;
     734                 : 
     735               7 :     return CE_None;
     736                 : }
     737                 : 
     738                 : /************************************************************************/
     739                 : /*                          GetProjectionRef()                          */
     740                 : /************************************************************************/
     741                 : 
     742              10 : const char *RMFDataset::GetProjectionRef()
     743                 : {
     744              10 :     if( pszProjection )
     745              10 :         return pszProjection;
     746                 :     else
     747               0 :         return "";
     748                 : }
     749                 : 
     750                 : /************************************************************************/
     751                 : /*                           SetProjection()                            */
     752                 : /************************************************************************/
     753                 : 
     754               7 : CPLErr RMFDataset::SetProjection( const char * pszNewProjection )
     755                 : 
     756                 : {
     757               7 :     if ( pszProjection )
     758               7 :         CPLFree( pszProjection );
     759               7 :     pszProjection = CPLStrdup( (pszNewProjection) ? pszNewProjection : "" );
     760                 : 
     761               7 :     bHeaderDirty = TRUE;
     762                 : 
     763               7 :     return CE_None;
     764                 : }
     765                 : 
     766                 : /************************************************************************/
     767                 : /*                           WriteHeader()                              */
     768                 : /************************************************************************/
     769                 : 
     770              19 : CPLErr RMFDataset::WriteHeader()
     771                 : {
     772                 : /* -------------------------------------------------------------------- */
     773                 : /*  Setup projection.                                                   */
     774                 : /* -------------------------------------------------------------------- */
     775              19 :     if( pszProjection && !EQUAL( pszProjection, "" ) )
     776                 :     {
     777               7 :         OGRSpatialReference oSRS;
     778                 :         long            iProjection, iDatum, iEllips, iZone;
     779               7 :         char            *pszProj =  pszProjection;
     780                 : 
     781               7 :         if ( oSRS.importFromWkt( &pszProj ) == OGRERR_NONE )
     782                 :         {
     783                 :             double  adfPrjParams[7];
     784                 : 
     785                 :             oSRS.exportToPanorama( &iProjection, &iDatum, &iEllips, &iZone,
     786               7 :                                    adfPrjParams );
     787               7 :             sHeader.iProjection = iProjection;
     788               7 :             sHeader.dfStdP1 = adfPrjParams[0];
     789               7 :             sHeader.dfStdP2 = adfPrjParams[1];
     790               7 :             sHeader.dfCenterLat = adfPrjParams[2];
     791               7 :             sHeader.dfCenterLong = adfPrjParams[3];
     792                 : 
     793               7 :             sExtHeader.nEllipsoid = iEllips;
     794               7 :             sExtHeader.nDatum = iDatum;
     795               7 :             sExtHeader.nZone = iZone;
     796               7 :         }
     797                 :     }
     798                 : 
     799                 : #define RMF_WRITE_LONG( ptr, value, offset )            \
     800                 : {                                                       \
     801                 :     GInt32  iLong = CPL_LSBWORD32( value );             \
     802                 :     memcpy( (ptr) + (offset), &iLong, 4 );              \
     803                 : }
     804                 : 
     805                 : #define RMF_WRITE_ULONG( ptr,value, offset )            \
     806                 : {                                                       \
     807                 :     GUInt32 iULong = CPL_LSBWORD32( value );            \
     808                 :     memcpy( (ptr) + (offset), &iULong, 4 );             \
     809                 : }
     810                 : 
     811                 : #define RMF_WRITE_DOUBLE( ptr,value, offset )           \
     812                 : {                                                       \
     813                 :     double  dfDouble = (value);                         \
     814                 :     CPL_LSBPTR64( &dfDouble );                          \
     815                 :     memcpy( (ptr) + (offset), &dfDouble, 8 );           \
     816                 : }
     817                 : 
     818                 : /* -------------------------------------------------------------------- */
     819                 : /*  Write out the main header.                                          */
     820                 : /* -------------------------------------------------------------------- */
     821                 :     {
     822                 :         GByte   abyHeader[RMF_HEADER_SIZE];
     823                 : 
     824              19 :         memset( abyHeader, 0, sizeof(abyHeader) );
     825                 : 
     826              19 :         memcpy( abyHeader, sHeader.bySignature, RMF_SIGNATURE_SIZE );
     827              19 :         RMF_WRITE_ULONG( abyHeader, sHeader.iVersion, 4 );
     828                 :         //
     829              19 :         RMF_WRITE_ULONG( abyHeader, sHeader.nOvrOffset, 12 );
     830              19 :         RMF_WRITE_ULONG( abyHeader, sHeader.iUserID, 16 );
     831              19 :         memcpy( abyHeader + 20, sHeader.byName, RMF_NAME_SIZE );
     832              19 :         RMF_WRITE_ULONG( abyHeader, sHeader.nBitDepth, 52 );
     833              19 :         RMF_WRITE_ULONG( abyHeader, sHeader.nHeight, 56 );
     834              19 :         RMF_WRITE_ULONG( abyHeader, sHeader.nWidth, 60 );
     835              19 :         RMF_WRITE_ULONG( abyHeader, sHeader.nXTiles, 64 );
     836              19 :         RMF_WRITE_ULONG( abyHeader, sHeader.nYTiles, 68 );
     837              19 :         RMF_WRITE_ULONG( abyHeader, sHeader.nTileHeight, 72 );
     838              19 :         RMF_WRITE_ULONG( abyHeader, sHeader.nTileWidth, 76 );
     839              19 :         RMF_WRITE_ULONG( abyHeader, sHeader.nLastTileHeight, 80 );
     840              19 :         RMF_WRITE_ULONG( abyHeader, sHeader.nLastTileWidth, 84 );
     841              19 :         RMF_WRITE_ULONG( abyHeader, sHeader.nROIOffset, 88 );
     842              19 :         RMF_WRITE_ULONG( abyHeader, sHeader.nROISize, 92 );
     843              19 :         RMF_WRITE_ULONG( abyHeader, sHeader.nClrTblOffset, 96 );
     844              19 :         RMF_WRITE_ULONG( abyHeader, sHeader.nClrTblSize, 100 );
     845              19 :         RMF_WRITE_ULONG( abyHeader, sHeader.nTileTblOffset, 104 );
     846              19 :         RMF_WRITE_ULONG( abyHeader, sHeader.nTileTblSize, 108 );
     847              19 :         RMF_WRITE_LONG( abyHeader, sHeader.iMapType, 124 );
     848              19 :         RMF_WRITE_LONG( abyHeader, sHeader.iProjection, 128 );
     849              19 :         RMF_WRITE_DOUBLE( abyHeader, sHeader.dfScale, 136 );
     850              19 :         RMF_WRITE_DOUBLE( abyHeader, sHeader.dfResolution, 144 );
     851              19 :         RMF_WRITE_DOUBLE( abyHeader, sHeader.dfPixelSize, 152 );
     852              19 :         RMF_WRITE_DOUBLE( abyHeader, sHeader.dfLLY, 160 );
     853              19 :         RMF_WRITE_DOUBLE( abyHeader, sHeader.dfLLX, 168 );
     854              19 :         RMF_WRITE_DOUBLE( abyHeader, sHeader.dfStdP1, 176 );
     855              19 :         RMF_WRITE_DOUBLE( abyHeader, sHeader.dfStdP2, 184 );
     856              19 :         RMF_WRITE_DOUBLE( abyHeader, sHeader.dfCenterLong, 192 );
     857              19 :         RMF_WRITE_DOUBLE( abyHeader, sHeader.dfCenterLat, 200 );
     858              19 :         *(abyHeader + 208) = sHeader.iCompression;
     859              19 :         *(abyHeader + 209) = sHeader.iMaskType;
     860              19 :         *(abyHeader + 210) = sHeader.iMaskStep;
     861              19 :         *(abyHeader + 211) = sHeader.iFrameFlag;
     862              19 :         RMF_WRITE_ULONG( abyHeader, sHeader.nFlagsTblOffset, 212 );
     863              19 :         RMF_WRITE_ULONG( abyHeader, sHeader.nFlagsTblSize, 216 );
     864              19 :         RMF_WRITE_ULONG( abyHeader, sHeader.nFileSize0, 220 );
     865              19 :         RMF_WRITE_ULONG( abyHeader, sHeader.nFileSize1, 224 );
     866              19 :         *(abyHeader + 228) = sHeader.iUnknown;
     867              19 :         *(abyHeader + 244) = sHeader.iGeorefFlag;
     868              19 :         *(abyHeader + 245) = sHeader.iInverse;
     869                 :         memcpy( abyHeader + 248, sHeader.abyInvisibleColors,
     870              19 :                 sizeof(sHeader.abyInvisibleColors) );
     871              19 :         RMF_WRITE_DOUBLE( abyHeader, sHeader.adfElevMinMax[0], 280 );
     872              19 :         RMF_WRITE_DOUBLE( abyHeader, sHeader.adfElevMinMax[1], 288 );
     873              19 :         RMF_WRITE_DOUBLE( abyHeader, sHeader.dfNoData, 296 );
     874              19 :         RMF_WRITE_ULONG( abyHeader, sHeader.iElevationUnit, 304 );
     875              19 :         *(abyHeader + 308) = sHeader.iElevationType;
     876              19 :         RMF_WRITE_ULONG( abyHeader, sHeader.nExtHdrOffset, 312 );
     877              19 :         RMF_WRITE_ULONG( abyHeader, sHeader.nExtHdrSize, 316 );
     878                 : 
     879              19 :         VSIFSeekL( fp, 0, SEEK_SET );
     880              19 :         VSIFWriteL( abyHeader, 1, sizeof(abyHeader), fp );
     881                 :     }
     882                 : 
     883                 : /* -------------------------------------------------------------------- */
     884                 : /*  Write out the extended header.                                      */
     885                 : /* -------------------------------------------------------------------- */
     886                 : 
     887              19 :     if ( sHeader.nExtHdrOffset && sHeader.nExtHdrSize )
     888                 :     {
     889              19 :         GByte   *pabyExtHeader = (GByte *)CPLCalloc( sHeader.nExtHdrSize, 1 );
     890                 : 
     891              19 :         RMF_WRITE_LONG( pabyExtHeader, sExtHeader.nEllipsoid, 24 );
     892              19 :         RMF_WRITE_LONG( pabyExtHeader, sExtHeader.nDatum, 32 );
     893              19 :         RMF_WRITE_LONG( pabyExtHeader, sExtHeader.nZone, 36 );
     894                 : 
     895              19 :         VSIFSeekL( fp, sHeader.nExtHdrOffset, SEEK_SET );
     896              19 :         VSIFWriteL( pabyExtHeader, 1, sHeader.nExtHdrSize, fp );
     897                 : 
     898              19 :         CPLFree( pabyExtHeader );
     899                 :     }
     900                 : 
     901                 : #undef RMF_WRITE_DOUBLE
     902                 : #undef RMF_WRITE_ULONG
     903                 : #undef RMF_WRITE_LONG
     904                 : 
     905                 : /* -------------------------------------------------------------------- */
     906                 : /*  Write out the color table.                                          */
     907                 : /* -------------------------------------------------------------------- */
     908                 : 
     909              19 :     if ( sHeader.nClrTblOffset && sHeader.nClrTblSize )
     910                 :     {
     911              14 :         VSIFSeekL( fp, sHeader.nClrTblOffset, SEEK_SET );
     912              14 :         VSIFWriteL( pabyColorTable, 1, sHeader.nClrTblSize, fp );
     913                 :     }
     914                 : 
     915                 : /* -------------------------------------------------------------------- */
     916                 : /*  Write out the block table, swap if needed.                          */
     917                 : /* -------------------------------------------------------------------- */
     918                 :     
     919              19 :     VSIFSeekL( fp, sHeader.nTileTblOffset, SEEK_SET );
     920                 : 
     921                 : #ifdef CPL_MSB
     922                 :     GUInt32 i;
     923                 :     GUInt32 *paiTilesSwapped = (GUInt32 *)CPLMalloc( sHeader.nTileTblSize );
     924                 : 
     925                 :     if ( !paiTilesSwapped )
     926                 :         return CE_Failure;
     927                 : 
     928                 :     memcpy( paiTilesSwapped, paiTiles, sHeader.nTileTblSize );
     929                 :     for ( i = 0; i < sHeader.nTileTblSize / sizeof(GUInt32); i++ )
     930                 :         CPL_SWAP32PTR( paiTilesSwapped + i );
     931                 :     VSIFWriteL( paiTilesSwapped, 1, sHeader.nTileTblSize, fp );
     932                 : 
     933                 :     CPLFree( paiTilesSwapped );
     934                 : #else
     935              19 :     VSIFWriteL( paiTiles, 1, sHeader.nTileTblSize, fp );
     936                 : #endif
     937                 : 
     938              19 :     bHeaderDirty = FALSE;
     939                 : 
     940              19 :     return CE_None;
     941                 : }
     942                 : 
     943                 : /************************************************************************/
     944                 : /*                             FlushCache()                             */
     945                 : /************************************************************************/
     946                 : 
     947              28 : void RMFDataset::FlushCache()
     948                 : 
     949                 : {
     950              28 :     GDALDataset::FlushCache();
     951                 : 
     952              28 :     if ( !bHeaderDirty )
     953              21 :         return;
     954                 : 
     955               7 :     if ( eRMFType == RMFT_MTW )
     956                 :     {
     957               0 :         GDALRasterBand *poBand = GetRasterBand(1);
     958                 : 
     959               0 :         if ( poBand )
     960                 :         {
     961               0 :             poBand->ComputeRasterMinMax( FALSE, sHeader.adfElevMinMax );
     962               0 :             bHeaderDirty = TRUE;
     963                 :         }
     964                 :     }
     965               7 :     WriteHeader();
     966                 : }
     967                 : 
     968                 : /************************************************************************/
     969                 : /*                              Identify()                              */
     970                 : /************************************************************************/
     971                 : 
     972            8905 : int RMFDataset::Identify( GDALOpenInfo *poOpenInfo )
     973                 : 
     974                 : {
     975            8905 :     if( poOpenInfo->fp == NULL )
     976            8312 :         return FALSE;
     977                 : 
     978             593 :     if( memcmp(poOpenInfo->pabyHeader, RMF_SigRSW, sizeof(RMF_SigRSW)) != 0
     979                 :         && memcmp(poOpenInfo->pabyHeader, RMF_SigRSW_BE, sizeof(RMF_SigRSW_BE)) != 0
     980                 :         && memcmp(poOpenInfo->pabyHeader, RMF_SigMTW, sizeof(RMF_SigMTW)) != 0 )
     981             577 :         return FALSE;
     982                 : 
     983              16 :     return TRUE;
     984                 : }
     985                 : 
     986                 : /************************************************************************/
     987                 : /*                                Open()                                */
     988                 : /************************************************************************/
     989                 : 
     990            1178 : GDALDataset *RMFDataset::Open( GDALOpenInfo * poOpenInfo )
     991                 : {
     992            1178 :     if ( !Identify(poOpenInfo) )
     993            1162 :         return NULL;
     994                 : 
     995                 : /* -------------------------------------------------------------------- */
     996                 : /*  Create a corresponding GDALDataset.                                 */
     997                 : /* -------------------------------------------------------------------- */
     998                 :     RMFDataset      *poDS;
     999                 : 
    1000              16 :     poDS = new RMFDataset();
    1001                 : 
    1002              16 :     if( poOpenInfo->eAccess == GA_ReadOnly )
    1003              16 :         poDS->fp = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
    1004                 :     else
    1005               0 :         poDS->fp = VSIFOpenL( poOpenInfo->pszFilename, "r+b" );
    1006              16 :     if ( !poDS->fp )
    1007                 :     {
    1008               0 :         delete poDS;
    1009               0 :         return NULL;
    1010                 :     }
    1011                 : 
    1012                 : #define RMF_READ_ULONG(ptr, value, offset)                              \
    1013                 : {                                                                       \
    1014                 :     if ( poDS->bBigEndian )                                             \
    1015                 :     {                                                                   \
    1016                 :         (value) = CPL_MSBWORD32(*(GUInt32*)((ptr) + (offset)));         \
    1017                 :     }                                                                   \
    1018                 :     else                                                                \
    1019                 :     {                                                                   \
    1020                 :         (value) = CPL_LSBWORD32(*(GUInt32*)((ptr) + (offset)));         \
    1021                 :     }                                                                   \
    1022                 : }
    1023                 : 
    1024                 : #define RMF_READ_LONG(ptr, value, offset)                               \
    1025                 : {                                                                       \
    1026                 :     if ( poDS->bBigEndian )                                             \
    1027                 :     {                                                                   \
    1028                 :         (value) = CPL_MSBWORD32(*(GInt32*)((ptr) + (offset)));          \
    1029                 :     }                                                                   \
    1030                 :     else                                                                \
    1031                 :     {                                                                   \
    1032                 :         (value) = CPL_LSBWORD32(*(GInt32*)((ptr) + (offset)));          \
    1033                 :     }                                                                   \
    1034                 : }
    1035                 : 
    1036                 : #define RMF_READ_DOUBLE(ptr, value, offset)                             \
    1037                 : {                                                                       \
    1038                 :     (value) = *(double*)((ptr) + (offset));                             \
    1039                 :     if ( poDS->bBigEndian )                                             \
    1040                 :     {                                                                   \
    1041                 :         CPL_MSBPTR64(&(value));                                         \
    1042                 :     }                                                                   \
    1043                 :     else                                                                \
    1044                 :     {                                                                   \
    1045                 :         CPL_LSBPTR64(&(value));                                         \
    1046                 :     }                                                                   \
    1047                 : }
    1048                 : 
    1049                 : /* -------------------------------------------------------------------- */
    1050                 : /*  Read the main header.                                               */
    1051                 : /* -------------------------------------------------------------------- */
    1052                 : 
    1053                 :     {
    1054                 :         GByte   abyHeader[RMF_HEADER_SIZE];
    1055                 : 
    1056              16 :         VSIFSeekL( poDS->fp, 0, SEEK_SET );
    1057              16 :         VSIFReadL( abyHeader, 1, sizeof(abyHeader), poDS->fp );
    1058                 : 
    1059              16 :         if ( memcmp(abyHeader, RMF_SigMTW, sizeof(RMF_SigMTW)) == 0 )
    1060               1 :             poDS->eRMFType = RMFT_MTW;
    1061              15 :         else if ( memcmp(abyHeader, RMF_SigRSW_BE, sizeof(RMF_SigRSW_BE)) == 0 )
    1062                 :         {
    1063               1 :             poDS->eRMFType = RMFT_RSW;
    1064               1 :             poDS->bBigEndian = TRUE;
    1065                 :         }
    1066                 :         else
    1067              14 :             poDS->eRMFType = RMFT_RSW;
    1068                 : 
    1069              16 :         memcpy( poDS->sHeader.bySignature, abyHeader, RMF_SIGNATURE_SIZE );
    1070              16 :         RMF_READ_ULONG( abyHeader, poDS->sHeader.iVersion, 4 );
    1071              16 :         RMF_READ_ULONG( abyHeader, poDS->sHeader.nSize, 8 );
    1072              16 :         RMF_READ_ULONG( abyHeader, poDS->sHeader.nOvrOffset, 12 );
    1073              16 :         RMF_READ_ULONG( abyHeader, poDS->sHeader.iUserID, 16 );
    1074                 :         memcpy( poDS->sHeader.byName, abyHeader + 20,
    1075              16 :                 sizeof(poDS->sHeader.byName) );
    1076              16 :         poDS->sHeader.byName[sizeof(poDS->sHeader.byName) - 1] = '\0';
    1077              16 :         RMF_READ_ULONG( abyHeader, poDS->sHeader.nBitDepth, 52 );
    1078              16 :         RMF_READ_ULONG( abyHeader, poDS->sHeader.nHeight, 56 );
    1079              16 :         RMF_READ_ULONG( abyHeader, poDS->sHeader.nWidth, 60 );
    1080              16 :         RMF_READ_ULONG( abyHeader, poDS->sHeader.nXTiles, 64 );
    1081              16 :         RMF_READ_ULONG( abyHeader, poDS->sHeader.nYTiles, 68 );
    1082              16 :         RMF_READ_ULONG( abyHeader, poDS->sHeader.nTileHeight, 72 );
    1083              16 :         RMF_READ_ULONG( abyHeader, poDS->sHeader.nTileWidth, 76 );
    1084              16 :         RMF_READ_ULONG( abyHeader, poDS->sHeader.nLastTileHeight, 80 );
    1085              16 :         RMF_READ_ULONG( abyHeader, poDS->sHeader.nLastTileWidth, 84 );
    1086              16 :         RMF_READ_ULONG( abyHeader, poDS->sHeader.nROIOffset, 88 );
    1087              16 :         RMF_READ_ULONG( abyHeader, poDS->sHeader.nROISize, 92 );
    1088              16 :         RMF_READ_ULONG( abyHeader, poDS->sHeader.nClrTblOffset, 96 );
    1089              16 :         RMF_READ_ULONG( abyHeader, poDS->sHeader.nClrTblSize, 100 );
    1090              16 :         RMF_READ_ULONG( abyHeader, poDS->sHeader.nTileTblOffset, 104 );
    1091              16 :         RMF_READ_ULONG( abyHeader, poDS->sHeader.nTileTblSize, 108 );
    1092              16 :         RMF_READ_LONG( abyHeader, poDS->sHeader.iMapType, 124 );
    1093              16 :         RMF_READ_LONG( abyHeader, poDS->sHeader.iProjection, 128 );
    1094              16 :         RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfScale, 136 );
    1095              16 :         RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfResolution, 144 );
    1096              16 :         RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfPixelSize, 152 );
    1097              16 :         RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfLLY, 160 );
    1098              16 :         RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfLLX, 168 );
    1099              16 :         RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfStdP1, 176 );
    1100              16 :         RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfStdP2, 184 );
    1101              16 :         RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfCenterLong, 192 );
    1102              16 :         RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfCenterLat, 200 );
    1103              16 :         poDS->sHeader.iCompression = *(abyHeader + 208);
    1104              16 :         poDS->sHeader.iMaskType = *(abyHeader + 209);
    1105              16 :         poDS->sHeader.iMaskStep = *(abyHeader + 210);
    1106              16 :         poDS->sHeader.iFrameFlag = *(abyHeader + 211);
    1107              16 :         RMF_READ_ULONG( abyHeader, poDS->sHeader.nFlagsTblOffset, 212 );
    1108              16 :         RMF_READ_ULONG( abyHeader, poDS->sHeader.nFlagsTblSize, 216 );
    1109              16 :         RMF_READ_ULONG( abyHeader, poDS->sHeader.nFileSize0, 220 );
    1110              16 :         RMF_READ_ULONG( abyHeader, poDS->sHeader.nFileSize1, 224 );
    1111              16 :         poDS->sHeader.iUnknown = *(abyHeader + 228);
    1112              16 :         poDS->sHeader.iGeorefFlag = *(abyHeader + 244);
    1113              16 :         poDS->sHeader.iInverse = *(abyHeader + 245);
    1114                 :         memcpy( poDS->sHeader.abyInvisibleColors,
    1115              16 :                 abyHeader + 248, sizeof(poDS->sHeader.abyInvisibleColors) );
    1116              16 :         RMF_READ_DOUBLE( abyHeader, poDS->sHeader.adfElevMinMax[0], 280 );
    1117              16 :         RMF_READ_DOUBLE( abyHeader, poDS->sHeader.adfElevMinMax[1], 288 );
    1118              16 :         RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfNoData, 296 );
    1119              16 :         RMF_READ_ULONG( abyHeader, poDS->sHeader.iElevationUnit, 304 );
    1120              16 :         poDS->sHeader.iElevationType = *(abyHeader + 308);
    1121              16 :         RMF_READ_ULONG( abyHeader, poDS->sHeader.nExtHdrOffset, 312 );
    1122              16 :         RMF_READ_ULONG( abyHeader, poDS->sHeader.nExtHdrSize, 316 );
    1123                 :     }
    1124                 : 
    1125                 : /* -------------------------------------------------------------------- */
    1126                 : /*  Read the extended header.                                           */
    1127                 : /* -------------------------------------------------------------------- */
    1128                 : 
    1129              16 :     if ( poDS->sHeader.nExtHdrOffset && poDS->sHeader.nExtHdrSize )
    1130                 :     {
    1131                 :         GByte *pabyExtHeader =
    1132              11 :             (GByte *)VSICalloc( poDS->sHeader.nExtHdrSize, 1 );
    1133              11 :         if (pabyExtHeader == NULL)
    1134                 :         {
    1135               0 :             delete poDS;
    1136               0 :             return NULL;
    1137                 :         }
    1138                 : 
    1139              11 :         VSIFSeekL( poDS->fp, poDS->sHeader.nExtHdrOffset, SEEK_SET );
    1140              11 :         VSIFReadL( pabyExtHeader, 1, poDS->sHeader.nExtHdrSize, poDS->fp );
    1141                 : 
    1142              11 :         RMF_READ_LONG( pabyExtHeader, poDS->sExtHeader.nEllipsoid, 24 );
    1143              11 :         RMF_READ_LONG( pabyExtHeader, poDS->sExtHeader.nDatum, 32 );
    1144              11 :         RMF_READ_LONG( pabyExtHeader, poDS->sExtHeader.nZone, 36 );
    1145                 : 
    1146              11 :         CPLFree( pabyExtHeader );
    1147                 :     }
    1148                 : 
    1149                 : #undef RMF_READ_DOUBLE
    1150                 : #undef RMF_READ_LONG
    1151                 : #undef RMF_READ_ULONG
    1152                 : 
    1153                 : #ifdef DEBUG
    1154                 : 
    1155                 :     CPLDebug( "RMF", "%s image has width %d, height %d, bit depth %d, "
    1156                 :               "compression scheme %d, %s",
    1157                 :               (poDS->eRMFType == RMFT_MTW) ? "MTW" : "RSW",
    1158                 :               poDS->sHeader.nWidth, poDS->sHeader.nHeight,
    1159                 :               poDS->sHeader.nBitDepth, poDS->sHeader.iCompression,
    1160                 :               poDS->bBigEndian ? "big endian" : "little endian" );
    1161                 :     CPLDebug( "RMF", "Size %d, offset to overview 0x%x, user ID %d, "
    1162                 :               "ROI offset 0x%x, ROI size %d",
    1163                 :               poDS->sHeader.nSize, poDS->sHeader.nOvrOffset,
    1164                 :               poDS->sHeader.iUserID, poDS->sHeader.nROIOffset,
    1165                 :               poDS->sHeader.nROISize );
    1166                 :     CPLDebug( "RMF", "Map type %d, projection %d, scale %f, resolution %f, ",
    1167                 :               poDS->sHeader.iMapType, poDS->sHeader.iProjection,
    1168                 :               poDS->sHeader.dfScale, poDS->sHeader.dfResolution );
    1169                 :     CPLDebug( "RMF", "Georeferencing: pixel size %f, LLX %f, LLY %f",
    1170                 :               poDS->sHeader.dfPixelSize,
    1171                 :               poDS->sHeader.dfLLX, poDS->sHeader.dfLLY );
    1172                 : #endif
    1173                 : 
    1174                 : /* -------------------------------------------------------------------- */
    1175                 : /*  Read array of blocks offsets/sizes.                                 */
    1176                 : /* -------------------------------------------------------------------- */
    1177                 :     GUInt32 i;
    1178                 : 
    1179              16 :     if ( VSIFSeekL( poDS->fp, poDS->sHeader.nTileTblOffset, SEEK_SET ) < 0)
    1180                 :     {
    1181               0 :         delete poDS;
    1182               0 :         return NULL;
    1183                 :     }
    1184                 : 
    1185              16 :     poDS->paiTiles = (GUInt32 *)VSIMalloc( poDS->sHeader.nTileTblSize );
    1186              16 :     if ( !poDS->paiTiles )
    1187                 :     {
    1188               0 :         delete poDS;
    1189               0 :         return NULL;
    1190                 :     }
    1191                 : 
    1192              16 :     if ( VSIFReadL( poDS->paiTiles, 1, poDS->sHeader.nTileTblSize,
    1193                 :                     poDS->fp ) < poDS->sHeader.nTileTblSize )
    1194                 :     {
    1195               0 :         CPLDebug( "RMF", "Can't read tiles offsets/sizes table." );
    1196               0 :         delete poDS;
    1197               0 :         return NULL;
    1198                 :     }
    1199                 : 
    1200                 : #ifdef CPL_MSB
    1201                 :     if ( !poDS->bBigEndian )
    1202                 :     {
    1203                 :         for ( i = 0; i < poDS->sHeader.nTileTblSize / sizeof(GUInt32); i++ )
    1204                 :             CPL_SWAP32PTR( poDS->paiTiles + i );
    1205                 :     }
    1206                 : #else
    1207              16 :     if ( poDS->bBigEndian )
    1208                 :     {
    1209               5 :         for ( i = 0; i < poDS->sHeader.nTileTblSize / sizeof(GUInt32); i++ )
    1210               4 :             CPL_SWAP32PTR( poDS->paiTiles + i );
    1211                 :     }
    1212                 : #endif
    1213                 : 
    1214                 : #if DEBUG
    1215                 :     CPLDebug( "RMF", "List of block offsets/sizes:" );
    1216                 : 
    1217                 :     for ( i = 0; i < poDS->sHeader.nTileTblSize / sizeof(GUInt32); i += 2 )
    1218                 :     {
    1219                 :         CPLDebug( "RMF", "    %d / %d",
    1220                 :                   poDS->paiTiles[i], poDS->paiTiles[i + 1] );
    1221                 :     }
    1222                 : #endif
    1223                 : 
    1224                 : /* -------------------------------------------------------------------- */
    1225                 : /*  Set up essential image parameters.                                  */
    1226                 : /* -------------------------------------------------------------------- */
    1227              16 :     GDALDataType eType = GDT_Byte;
    1228                 : 
    1229              16 :     poDS->nRasterXSize = poDS->sHeader.nWidth;
    1230              16 :     poDS->nRasterYSize = poDS->sHeader.nHeight;
    1231                 : 
    1232              16 :     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
    1233                 :     {
    1234               0 :         delete poDS;
    1235               0 :         return NULL;
    1236                 :     }
    1237                 : 
    1238              16 :     if ( poDS->eRMFType == RMFT_RSW )
    1239                 :     {
    1240              15 :         switch ( poDS->sHeader.nBitDepth )
    1241                 :         {
    1242                 :             case 32:
    1243                 :             case 24:
    1244                 :             case 16:
    1245               8 :                 poDS->nBands = 3;
    1246               8 :                 break;
    1247                 :             case 1:
    1248                 :             case 4:
    1249                 :             case 8:
    1250                 :                 {
    1251                 :                     // Allocate memory for colour table and read it
    1252               6 :                     poDS->nColorTableSize = 1 << poDS->sHeader.nBitDepth;
    1253               6 :                     if ( poDS->nColorTableSize * 4 > poDS->sHeader.nClrTblSize )
    1254                 :                     {
    1255                 :                         CPLDebug( "RMF",
    1256                 :                                   "Wrong color table size. Expected %d, got %d.",
    1257                 :                                   poDS->nColorTableSize * 4,
    1258               0 :                                   poDS->sHeader.nClrTblSize );
    1259               0 :                         delete poDS;
    1260               0 :                         return NULL;
    1261                 :                     }
    1262                 :                     poDS->pabyColorTable =
    1263               6 :                         (GByte *)VSIMalloc( poDS->sHeader.nClrTblSize );
    1264               6 :                     if (poDS->pabyColorTable == NULL)
    1265                 :                     {
    1266               0 :                         CPLDebug( "RMF", "Can't allocate color table." );
    1267               0 :                         delete poDS;
    1268               0 :                         return NULL;
    1269                 :                     }
    1270               6 :                     if ( VSIFSeekL( poDS->fp, poDS->sHeader.nClrTblOffset,
    1271                 :                                     SEEK_SET ) < 0 )
    1272                 :                     {
    1273               0 :                         CPLDebug( "RMF", "Can't seek to color table location." );
    1274               0 :                         delete poDS;
    1275               0 :                         return NULL;
    1276                 :                     }
    1277               6 :                     if ( VSIFReadL( poDS->pabyColorTable, 1,
    1278                 :                                     poDS->sHeader.nClrTblSize, poDS->fp )
    1279                 :                          < poDS->sHeader.nClrTblSize )
    1280                 :                     {
    1281               0 :                         CPLDebug( "RMF", "Can't read color table." );
    1282               0 :                         delete poDS;
    1283               0 :                         return NULL;
    1284                 :                     }
    1285                 : 
    1286                 :                     GDALColorEntry oEntry;
    1287               6 :                     poDS->poColorTable = new GDALColorTable();
    1288            1542 :                     for( i = 0; i < poDS->nColorTableSize; i++ )
    1289                 :                     {
    1290            1536 :                         oEntry.c1 = poDS->pabyColorTable[i * 4];     // Red
    1291            1536 :                         oEntry.c2 = poDS->pabyColorTable[i * 4 + 1]; // Green
    1292            1536 :                         oEntry.c3 = poDS->pabyColorTable[i * 4 + 2]; // Blue
    1293            1536 :                         oEntry.c4 = 255;                             // Alpha
    1294                 : 
    1295            1536 :                         poDS->poColorTable->SetColorEntry( i, &oEntry );
    1296                 :                     }
    1297                 :                 }
    1298               6 :                 poDS->nBands = 1;
    1299                 :                 break;
    1300                 :             default:
    1301                 :                 break;
    1302                 :         }
    1303              15 :         eType = GDT_Byte;
    1304                 :     }
    1305                 :     else
    1306                 :     {
    1307               1 :         poDS->nBands = 1;
    1308               1 :         if ( poDS->sHeader.nBitDepth == 8 )
    1309               0 :             eType = GDT_Byte;
    1310               1 :         else if ( poDS->sHeader.nBitDepth == 16 )
    1311               0 :             eType = GDT_Int16;
    1312               1 :         else if ( poDS->sHeader.nBitDepth == 32 )
    1313               0 :             eType = GDT_Int32;
    1314               1 :         else if ( poDS->sHeader.nBitDepth == 64 )
    1315               1 :             eType = GDT_Float64;
    1316                 :     }
    1317                 :     
    1318              16 :     if (poDS->sHeader.nTileWidth == 0 ||
    1319                 :         poDS->sHeader.nTileHeight == 0)
    1320                 :     {
    1321                 :         CPLDebug ("RMF", "Invalid tile dimension : %d x %d",
    1322               0 :                   poDS->sHeader.nTileWidth, poDS->sHeader.nTileHeight);
    1323               0 :         delete poDS;
    1324               0 :         return NULL;
    1325                 :     }
    1326                 : 
    1327                 :     poDS->nXTiles = ( poDS->nRasterXSize + poDS->sHeader.nTileWidth - 1 ) /
    1328              16 :         poDS->sHeader.nTileWidth;
    1329                 :     poDS->nYTiles = ( poDS->nRasterYSize + poDS->sHeader.nTileHeight - 1 ) /
    1330              16 :         poDS->sHeader.nTileHeight;
    1331                 : 
    1332                 : #if DEBUG
    1333                 :     CPLDebug( "RMF", "Image is %d tiles wide, %d tiles long",
    1334                 :               poDS->nXTiles, poDS->nYTiles );
    1335                 : #endif
    1336                 : 
    1337                 : /* -------------------------------------------------------------------- */
    1338                 : /*  Choose compression scheme.                                          */
    1339                 : /* -------------------------------------------------------------------- */
    1340              16 :     if (poDS->sHeader.iCompression == RMF_COMPRESSION_LZW)
    1341               2 :         poDS->Decompress = &LZWDecompress;
    1342                 :     else    // No compression
    1343              14 :         poDS->Decompress = NULL;
    1344                 : 
    1345                 : /* -------------------------------------------------------------------- */
    1346                 : /*  Create band information objects.                                    */
    1347                 : /* -------------------------------------------------------------------- */
    1348                 :     int iBand;
    1349                 : 
    1350              94 :     for( iBand = 1; iBand <= poDS->nBands; iBand++ )
    1351              31 :         poDS->SetBand( iBand, new RMFRasterBand( poDS, iBand, eType ) );
    1352                 : 
    1353                 : /* -------------------------------------------------------------------- */
    1354                 : /*  Set up projection.                                                  */
    1355                 : /*                                                                      */
    1356                 : /*  XXX: If projection value is not specified, but image still have     */
    1357                 : /*  georeferencing information, assume Gauss-Kruger projection.         */
    1358                 : /* -------------------------------------------------------------------- */
    1359              16 :     if( poDS->sHeader.iProjection > 0 ||
    1360                 :         (poDS->sHeader.dfPixelSize != 0.0 &&
    1361                 :          poDS->sHeader.dfLLX != 0.0 &&
    1362                 :          poDS->sHeader.dfLLY != 0.0) )
    1363                 :     {
    1364              16 :         OGRSpatialReference oSRS;
    1365                 :         GInt32  nProj =
    1366              16 :             (poDS->sHeader.iProjection) ? poDS->sHeader.iProjection : 1L;
    1367                 :         double  padfPrjParams[7];
    1368                 : 
    1369              16 :         padfPrjParams[0] = poDS->sHeader.dfStdP1;
    1370              16 :         padfPrjParams[1] = poDS->sHeader.dfStdP2;
    1371              16 :         padfPrjParams[2] = poDS->sHeader.dfCenterLat;
    1372              16 :         padfPrjParams[3] = poDS->sHeader.dfCenterLong;
    1373              16 :         padfPrjParams[4] = 1.0;
    1374              16 :         padfPrjParams[5] = 0.0;
    1375              16 :         padfPrjParams[6] = 0.0;
    1376                 : 
    1377                 :         oSRS.importFromPanorama( nProj, poDS->sExtHeader.nDatum,
    1378              16 :                                  poDS->sExtHeader.nEllipsoid, padfPrjParams );
    1379              16 :         if ( poDS->pszProjection )
    1380              16 :             CPLFree( poDS->pszProjection );
    1381              16 :         oSRS.exportToWkt( &poDS->pszProjection );
    1382                 :     }
    1383                 : 
    1384                 : /* -------------------------------------------------------------------- */
    1385                 : /*  Set up georeferencing.                                              */
    1386                 : /* -------------------------------------------------------------------- */
    1387              16 :     if ( (poDS->eRMFType == RMFT_RSW && poDS->sHeader.iGeorefFlag) ||
    1388                 :          (poDS->eRMFType == RMFT_MTW && poDS->sHeader.dfPixelSize != 0.0) )
    1389                 :     {
    1390              16 :         poDS->adfGeoTransform[0] = poDS->sHeader.dfLLX;
    1391                 :         poDS->adfGeoTransform[3] = poDS->sHeader.dfLLY
    1392              16 :             + poDS->nRasterYSize * poDS->sHeader.dfPixelSize;
    1393              16 :         poDS->adfGeoTransform[1] = poDS->sHeader.dfPixelSize;
    1394              16 :         poDS->adfGeoTransform[5] = - poDS->sHeader.dfPixelSize;
    1395              16 :         poDS->adfGeoTransform[2] = 0.0;
    1396              16 :         poDS->adfGeoTransform[4] = 0.0;
    1397                 :     }
    1398                 : 
    1399                 : /* -------------------------------------------------------------------- */
    1400                 : /*  Set units.                                                          */
    1401                 : /* -------------------------------------------------------------------- */
    1402                 :     
    1403              16 :     if ( poDS->eRMFType == RMFT_MTW )
    1404                 :     {
    1405               1 :         CPLFree(poDS->pszUnitType);
    1406               1 :         switch ( poDS->sHeader.iElevationUnit )
    1407                 :         {
    1408                 :             case 0:
    1409               1 :                 poDS->pszUnitType = CPLStrdup( RMF_UnitsM );
    1410               1 :                 break;
    1411                 :             case 1:
    1412               0 :                 poDS->pszUnitType = CPLStrdup( RMF_UnitsCM );
    1413               0 :                 break;
    1414                 :             case 2:
    1415               0 :                 poDS->pszUnitType = CPLStrdup( RMF_UnitsDM );
    1416               0 :                 break;
    1417                 :             case 3:
    1418               0 :                 poDS->pszUnitType = CPLStrdup( RMF_UnitsMM );
    1419               0 :                 break;
    1420                 :             default:
    1421               0 :                 poDS->pszUnitType = CPLStrdup( RMF_UnitsEmpty );
    1422                 :                 break;
    1423                 :         }
    1424                 :     }
    1425                 : 
    1426                 : /* -------------------------------------------------------------------- */
    1427                 : /*  Report some other dataset related information.                      */
    1428                 : /* -------------------------------------------------------------------- */
    1429                 : 
    1430              16 :     if ( poDS->eRMFType == RMFT_MTW )
    1431                 :     {
    1432                 :         char        szTemp[256];
    1433                 : 
    1434               1 :         snprintf( szTemp, sizeof(szTemp), "%g", poDS->sHeader.adfElevMinMax[0] );
    1435               1 :         poDS->SetMetadataItem( "ELEVATION_MINIMUM", szTemp );
    1436                 : 
    1437               1 :         snprintf( szTemp, sizeof(szTemp), "%g", poDS->sHeader.adfElevMinMax[1] );
    1438               1 :         poDS->SetMetadataItem( "ELEVATION_MAXIMUM", szTemp );
    1439                 : 
    1440               1 :         poDS->SetMetadataItem( "ELEVATION_UNITS", poDS->pszUnitType );
    1441                 : 
    1442               1 :         snprintf( szTemp, sizeof(szTemp), "%d", poDS->sHeader.iElevationType );
    1443               1 :         poDS->SetMetadataItem( "ELEVATION_TYPE", szTemp );
    1444                 :     }
    1445                 : 
    1446              16 :     return( poDS );
    1447                 : }
    1448                 : 
    1449                 : /************************************************************************/
    1450                 : /*                               Create()                               */
    1451                 : /************************************************************************/
    1452                 : 
    1453              33 : GDALDataset *RMFDataset::Create( const char * pszFilename,
    1454                 :                                  int nXSize, int nYSize, int nBands,
    1455                 :                                  GDALDataType eType, char **papszParmList )
    1456                 : 
    1457                 : {
    1458              33 :     if ( nBands != 1 && nBands != 3 )
    1459                 :     {
    1460                 :         CPLError( CE_Failure, CPLE_NotSupported,
    1461                 :                   "RMF driver doesn't support %d bands. Must be 1 or 3.\n",
    1462               7 :                   nBands );
    1463                 : 
    1464               7 :         return NULL;
    1465                 :     }
    1466                 : 
    1467              26 :     if ( nBands == 1
    1468                 :          && eType != GDT_Byte
    1469                 :          && eType != GDT_Int16
    1470                 :          && eType != GDT_Int32
    1471                 :          && eType != GDT_Float64 )
    1472                 :     {
    1473                 :          CPLError( CE_Failure, CPLE_AppDefined,
    1474                 :               "Attempt to create RMF dataset with an illegal data type (%s),\n"
    1475                 :               "only Byte, Int16, Int32 and Float64 types supported "
    1476                 :               "by the format for single-band images.\n",
    1477              14 :               GDALGetDataTypeName(eType) );
    1478                 : 
    1479              14 :         return NULL;
    1480                 :     }
    1481                 : 
    1482              12 :     if ( nBands == 3 && eType != GDT_Byte )
    1483                 :     {
    1484                 :          CPLError( CE_Failure, CPLE_AppDefined,
    1485                 :               "Attempt to create RMF dataset with an illegal data type (%s),\n"
    1486                 :               "only Byte type supported by the format for three-band images.\n",
    1487               0 :               GDALGetDataTypeName(eType) );
    1488                 : 
    1489               0 :         return NULL;
    1490                 :     }
    1491                 : 
    1492                 : /* -------------------------------------------------------------------- */
    1493                 : /*  Create the dataset.                                                 */
    1494                 : /* -------------------------------------------------------------------- */
    1495                 :     RMFDataset      *poDS;
    1496                 : 
    1497              12 :     poDS = new RMFDataset();
    1498                 : 
    1499              12 :     poDS->fp = VSIFOpenL( pszFilename, "w+b" );
    1500              12 :     if( poDS->fp == NULL )
    1501                 :     {
    1502                 :         CPLError( CE_Failure, CPLE_OpenFailed, "Unable to create file %s.\n",
    1503               0 :                   pszFilename );
    1504               0 :         return NULL;
    1505                 :     }
    1506                 : 
    1507              12 :     poDS->pszFilename = pszFilename;
    1508                 : 
    1509                 : /* -------------------------------------------------------------------- */
    1510                 : /*  Fill the RMFHeader                                                  */
    1511                 : /* -------------------------------------------------------------------- */
    1512              12 :     GUInt32     nTileSize, nCurPtr = 0;
    1513                 :     GUInt32     nBlockXSize =
    1514              12 :         ( nXSize < RMF_DEFAULT_BLOCKXSIZE ) ? nXSize : RMF_DEFAULT_BLOCKXSIZE;
    1515                 :     GUInt32     nBlockYSize =
    1516              12 :         ( nYSize < RMF_DEFAULT_BLOCKYSIZE ) ? nYSize : RMF_DEFAULT_BLOCKYSIZE;
    1517                 :     const char  *pszValue;
    1518                 : 
    1519              12 :     if ( CSLFetchBoolean( papszParmList, "MTW", FALSE) )
    1520               0 :         poDS->eRMFType = RMFT_MTW;
    1521                 :     else
    1522              12 :         poDS->eRMFType = RMFT_RSW;
    1523              12 :     if ( poDS->eRMFType == RMFT_MTW )
    1524               0 :         memcpy( poDS->sHeader.bySignature, RMF_SigMTW, RMF_SIGNATURE_SIZE );
    1525                 :     else
    1526              12 :         memcpy( poDS->sHeader.bySignature, RMF_SigRSW, RMF_SIGNATURE_SIZE );
    1527              12 :     poDS->sHeader.iVersion = 0x0200;
    1528              12 :     poDS->sHeader.nOvrOffset = 0x00;
    1529              12 :     poDS->sHeader.iUserID = 0x00;
    1530              12 :     memset( poDS->sHeader.byName, 0, sizeof(poDS->sHeader.byName) );
    1531              12 :     poDS->sHeader.nBitDepth = GDALGetDataTypeSize( eType ) * nBands;
    1532              12 :     poDS->sHeader.nHeight = nYSize;
    1533              12 :     poDS->sHeader.nWidth = nXSize;
    1534                 : 
    1535              12 :     pszValue = CSLFetchNameValue(papszParmList,"BLOCKXSIZE");
    1536              12 :     if( pszValue != NULL )
    1537               0 :         nBlockXSize = atoi( pszValue );
    1538                 : 
    1539              12 :     pszValue = CSLFetchNameValue(papszParmList,"BLOCKYSIZE");
    1540              12 :     if( pszValue != NULL )
    1541               0 :         nBlockYSize = atoi( pszValue );
    1542                 : 
    1543              12 :     poDS->sHeader.nTileWidth = nBlockXSize;
    1544              12 :     poDS->sHeader.nTileHeight = nBlockYSize;
    1545                 : 
    1546                 :     poDS->nXTiles = poDS->sHeader.nXTiles =
    1547              12 :         ( nXSize + poDS->sHeader.nTileWidth - 1 ) / poDS->sHeader.nTileWidth;
    1548                 :     poDS->nYTiles = poDS->sHeader.nYTiles =
    1549              12 :         ( nYSize + poDS->sHeader.nTileHeight - 1 ) / poDS->sHeader.nTileHeight;
    1550              12 :     poDS->sHeader.nLastTileHeight = nYSize % poDS->sHeader.nTileHeight;
    1551              12 :     if ( !poDS->sHeader.nLastTileHeight )
    1552              12 :         poDS->sHeader.nLastTileHeight = poDS->sHeader.nTileHeight;
    1553              12 :     poDS->sHeader.nLastTileWidth = nXSize % poDS->sHeader.nTileWidth;
    1554              12 :     if ( !poDS->sHeader.nLastTileWidth )
    1555              12 :         poDS->sHeader.nLastTileWidth = poDS->sHeader.nTileWidth;
    1556                 :     
    1557              12 :     poDS->sHeader.nROIOffset = 0x00;
    1558              12 :     poDS->sHeader.nROISize = 0x00;
    1559                 : 
    1560              12 :     nCurPtr += RMF_HEADER_SIZE;
    1561                 : 
    1562                 :     // Extended header
    1563              12 :     poDS->sHeader.nExtHdrOffset = nCurPtr;
    1564              12 :     poDS->sHeader.nExtHdrSize = RMF_EXT_HEADER_SIZE;
    1565              12 :     nCurPtr += poDS->sHeader.nExtHdrSize;
    1566                 : 
    1567                 :     // Color table
    1568              21 :     if ( poDS->eRMFType == RMFT_RSW && nBands == 1 )
    1569                 :     {
    1570                 :         GUInt32 i;
    1571                 : 
    1572               9 :         poDS->sHeader.nClrTblOffset = nCurPtr;
    1573               9 :         poDS->nColorTableSize = 1 << poDS->sHeader.nBitDepth;
    1574               9 :         poDS->sHeader.nClrTblSize = poDS->nColorTableSize * 4;
    1575               9 :         poDS->pabyColorTable = (GByte *) CPLMalloc( poDS->sHeader.nClrTblSize );
    1576          131853 :         for ( i = 0; i < poDS->nColorTableSize; i++ )
    1577                 :         {
    1578          131844 :             poDS->pabyColorTable[i * 4] =
    1579          263688 :                 poDS->pabyColorTable[i * 4 + 1] =
    1580          263688 :                 poDS->pabyColorTable[i * 4 + 2] = (GByte) i;
    1581          131844 :                 poDS->pabyColorTable[i * 4 + 3] = 0;
    1582                 :         }
    1583               9 :         nCurPtr += poDS->sHeader.nClrTblSize;
    1584                 :     }
    1585                 :     else
    1586                 :     {
    1587               3 :         poDS->sHeader.nClrTblOffset = 0x00;
    1588               3 :         poDS->sHeader.nClrTblSize = 0x00;
    1589                 :     }
    1590                 : 
    1591                 :     // Blocks table
    1592              12 :     poDS->sHeader.nTileTblOffset = nCurPtr;
    1593                 :     poDS->sHeader.nTileTblSize =
    1594              12 :         poDS->sHeader.nXTiles * poDS->sHeader.nYTiles * 4 * 2;
    1595              12 :     poDS->paiTiles = (GUInt32 *)CPLCalloc( poDS->sHeader.nTileTblSize, 1 );
    1596              12 :     nCurPtr += poDS->sHeader.nTileTblSize;
    1597                 :     nTileSize = poDS->sHeader.nTileWidth * poDS->sHeader.nTileHeight
    1598              12 :         * GDALGetDataTypeSize( eType ) / 8;
    1599                 :     poDS->sHeader.nSize =
    1600              12 :         poDS->paiTiles[poDS->sHeader.nTileTblSize / 4 - 2] + nTileSize;
    1601                 : 
    1602                 :     // Elevation units
    1603              12 :     if ( EQUAL(poDS->pszUnitType, RMF_UnitsM) )
    1604               0 :         poDS->sHeader.iElevationUnit = 0;
    1605              12 :     else if ( EQUAL(poDS->pszUnitType, RMF_UnitsCM) )
    1606               0 :         poDS->sHeader.iElevationUnit = 1;
    1607              12 :     else if ( EQUAL(poDS->pszUnitType, RMF_UnitsDM) )
    1608               0 :         poDS->sHeader.iElevationUnit = 2;
    1609              12 :     else if ( EQUAL(poDS->pszUnitType, RMF_UnitsMM) )
    1610               0 :         poDS->sHeader.iElevationUnit = 3;
    1611                 :     else
    1612              12 :         poDS->sHeader.iElevationUnit = 0;
    1613                 : 
    1614              12 :     poDS->sHeader.iMapType = -1;
    1615              12 :     poDS->sHeader.iProjection = -1;
    1616              12 :     poDS->sHeader.dfScale = 10000.0;
    1617              12 :     poDS->sHeader.dfResolution = 100.0;
    1618              12 :     poDS->sHeader.iCompression = 0;
    1619              12 :     poDS->sHeader.iMaskType = 0;
    1620              12 :     poDS->sHeader.iMaskStep = 0;
    1621              12 :     poDS->sHeader.iFrameFlag = 0;
    1622              12 :     poDS->sHeader.nFlagsTblOffset = 0x00;
    1623              12 :     poDS->sHeader.nFlagsTblSize = 0x00;
    1624              12 :     poDS->sHeader.nFileSize0 = 0x00;
    1625              12 :     poDS->sHeader.nFileSize1 = 0x00;
    1626              12 :     poDS->sHeader.iUnknown = 0;
    1627              12 :     poDS->sHeader.iGeorefFlag = 0;
    1628              12 :     poDS->sHeader.iInverse = 0;
    1629                 :     memset( poDS->sHeader.abyInvisibleColors, 0,
    1630              12 :             sizeof(poDS->sHeader.abyInvisibleColors) );
    1631              12 :     poDS->sHeader.adfElevMinMax[0] = 0.0;
    1632              12 :     poDS->sHeader.adfElevMinMax[1] = 0.0;
    1633              12 :     poDS->sHeader.dfNoData = 0.0;
    1634              12 :     poDS->sHeader.iElevationType = 0;
    1635                 : 
    1636              12 :     poDS->nRasterXSize = nXSize;
    1637              12 :     poDS->nRasterYSize = nYSize;
    1638              12 :     poDS->eAccess = GA_Update;
    1639              12 :     poDS->nBands = nBands;
    1640                 : 
    1641              12 :     poDS->WriteHeader();
    1642                 : 
    1643                 : /* -------------------------------------------------------------------- */
    1644                 : /*      Create band information objects.                                */
    1645                 : /* -------------------------------------------------------------------- */
    1646                 :     int         iBand;
    1647                 : 
    1648              60 :     for( iBand = 1; iBand <= poDS->nBands; iBand++ )
    1649              18 :         poDS->SetBand( iBand, new RMFRasterBand( poDS, iBand, eType ) );
    1650                 : 
    1651              12 :     return (GDALDataset *) poDS;
    1652                 : }
    1653                 : 
    1654                 : /************************************************************************/
    1655                 : /*                        GDALRegister_RMF()                            */
    1656                 : /************************************************************************/
    1657                 : 
    1658             338 : void GDALRegister_RMF()
    1659                 : 
    1660                 : {
    1661                 :     GDALDriver  *poDriver;
    1662                 : 
    1663             338 :     if( GDALGetDriverByName( "RMF" ) == NULL )
    1664                 :     {
    1665             336 :         poDriver = new GDALDriver();
    1666                 : 
    1667             336 :         poDriver->SetDescription( "RMF" );
    1668                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
    1669             336 :                                    "Raster Matrix Format" );
    1670                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
    1671             336 :                                    "frmt_rmf.html" );
    1672             336 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "rsw" );
    1673             336 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, "Byte" );
    1674                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
    1675                 : "<CreationOptionList>"
    1676                 : "   <Option name='MTW' type='boolean' description='Create MTW DEM matrix'/>"
    1677                 : "   <Option name='BLOCKXSIZE' type='int' description='Tile Width'/>"
    1678                 : "   <Option name='BLOCKYSIZE' type='int' description='Tile Height'/>"
    1679             336 : "</CreationOptionList>" );
    1680                 : 
    1681             336 :         poDriver->pfnIdentify = RMFDataset::Identify;
    1682             336 :         poDriver->pfnOpen = RMFDataset::Open;
    1683             336 :         poDriver->pfnCreate = RMFDataset::Create;
    1684                 : 
    1685             336 :         GetGDALDriverManager()->RegisterDriver( poDriver );
    1686                 :     }
    1687             338 : }
    1688                 : 

Generated by: LCOV version 1.7