mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-08-25 06:12:47 -06:00
1836 lines
67 KiB
C++
1836 lines
67 KiB
C++
/******************************************************************************
|
|
* $Id: rmfdataset.cpp 27384 2014-05-24 12:28:12Z rouault $
|
|
*
|
|
* Project: Raster Matrix Format
|
|
* Purpose: Read/write raster files used in GIS "Integratsia"
|
|
* (also known as "Panorama" GIS).
|
|
* Author: Andrey Kiselev, dron@ak4719.spb.edu
|
|
*
|
|
******************************************************************************
|
|
* Copyright (c) 2005, Andrey Kiselev <dron@ak4719.spb.edu>
|
|
* Copyright (c) 2007-2012, Even Rouault <even dot rouault at mines-paris dot org>
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included
|
|
* in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* DEALINGS IN THE SOFTWARE.
|
|
****************************************************************************/
|
|
|
|
#include "ogr_spatialref.h"
|
|
#include "cpl_string.h"
|
|
|
|
#include "rmfdataset.h"
|
|
|
|
CPL_CVSID("$Id: rmfdataset.cpp 27384 2014-05-24 12:28:12Z rouault $");
|
|
|
|
CPL_C_START
|
|
void GDALRegister_RMF(void);
|
|
CPL_C_END
|
|
|
|
#define RMF_DEFAULT_BLOCKXSIZE 256
|
|
#define RMF_DEFAULT_BLOCKYSIZE 256
|
|
|
|
static const char RMF_SigRSW[] = { 'R', 'S', 'W', '\0' };
|
|
static const char RMF_SigRSW_BE[] = { '\0', 'W', 'S', 'R' };
|
|
static const char RMF_SigMTW[] = { 'M', 'T', 'W', '\0' };
|
|
|
|
static const char RMF_UnitsEmpty[] = "";
|
|
static const char RMF_UnitsM[] = "m";
|
|
static const char RMF_UnitsCM[] = "cm";
|
|
static const char RMF_UnitsDM[] = "dm";
|
|
static const char RMF_UnitsMM[] = "mm";
|
|
|
|
/************************************************************************/
|
|
/* ==================================================================== */
|
|
/* RMFRasterBand */
|
|
/* ==================================================================== */
|
|
/************************************************************************/
|
|
|
|
/************************************************************************/
|
|
/* RMFRasterBand() */
|
|
/************************************************************************/
|
|
|
|
RMFRasterBand::RMFRasterBand( RMFDataset *poDS, int nBand,
|
|
GDALDataType eType )
|
|
{
|
|
this->poDS = poDS;
|
|
this->nBand = nBand;
|
|
|
|
eDataType = eType;
|
|
nBytesPerPixel = poDS->sHeader.nBitDepth / 8;
|
|
nDataSize = GDALGetDataTypeSize( eDataType ) / 8;
|
|
nBlockXSize = poDS->sHeader.nTileWidth;
|
|
nBlockYSize = poDS->sHeader.nTileHeight;
|
|
nBlockSize = nBlockXSize * nBlockYSize;
|
|
nBlockBytes = nBlockSize * nDataSize;
|
|
nLastTileXBytes =
|
|
(poDS->GetRasterXSize() % poDS->sHeader.nTileWidth) * nDataSize;
|
|
nLastTileHeight = poDS->GetRasterYSize() % poDS->sHeader.nTileHeight;
|
|
|
|
#ifdef DEBUG
|
|
CPLDebug( "RMF",
|
|
"Band %d: tile width is %d, tile height is %d, "
|
|
" last tile width %d, last tile height %d, "
|
|
"bytes per pixel is %d, data type size is %d",
|
|
nBand, nBlockXSize, nBlockYSize,
|
|
poDS->sHeader.nLastTileWidth, poDS->sHeader.nLastTileHeight,
|
|
nBytesPerPixel, nDataSize );
|
|
#endif
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ~RMFRasterBand() */
|
|
/************************************************************************/
|
|
|
|
RMFRasterBand::~RMFRasterBand()
|
|
{
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ReadBuffer() */
|
|
/* */
|
|
/* Helper fucntion to read specified amount of bytes from the input */
|
|
/* file stream. */
|
|
/************************************************************************/
|
|
|
|
CPLErr RMFRasterBand::ReadBuffer( GByte *pabyBuf, GUInt32 nBytes ) const
|
|
{
|
|
RMFDataset *poGDS = (RMFDataset *) poDS;
|
|
|
|
CPLAssert( pabyBuf != NULL && poGDS->fp != 0 );
|
|
|
|
vsi_l_offset nOffset = VSIFTellL( poGDS->fp );
|
|
|
|
if ( VSIFReadL( pabyBuf, 1, nBytes, poGDS->fp ) < nBytes )
|
|
{
|
|
// XXX
|
|
if( poGDS->eAccess == GA_Update )
|
|
{
|
|
return CE_Failure;
|
|
}
|
|
else
|
|
{
|
|
CPLError( CE_Failure, CPLE_FileIO,
|
|
"Can't read at offset %ld from input file.\n%s\n",
|
|
(long)nOffset, VSIStrerror( errno ) );
|
|
return CE_Failure;
|
|
}
|
|
}
|
|
|
|
#ifdef CPL_MSB
|
|
if ( poGDS->eRMFType == RMFT_MTW )
|
|
{
|
|
GUInt32 i;
|
|
|
|
if ( poGDS->sHeader.nBitDepth == 16 )
|
|
{
|
|
for ( i = 0; i < nBytes; i += 2 )
|
|
CPL_SWAP16PTR( pabyBuf + i );
|
|
}
|
|
|
|
else if ( poGDS->sHeader.nBitDepth == 32 )
|
|
{
|
|
for ( i = 0; i < nBytes; i += 4 )
|
|
CPL_SWAP32PTR( pabyBuf + i );
|
|
}
|
|
|
|
else if ( poGDS->sHeader.nBitDepth == 64 )
|
|
{
|
|
for ( i = 0; i < nBytes; i += 8 )
|
|
CPL_SWAPDOUBLE( pabyBuf + i );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* IReadBlock() */
|
|
/************************************************************************/
|
|
|
|
CPLErr RMFRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
|
|
void * pImage )
|
|
{
|
|
RMFDataset *poGDS = (RMFDataset *) poDS;
|
|
GUInt32 nTile = nBlockYOff * poGDS->nXTiles + nBlockXOff;
|
|
GUInt32 nTileBytes;
|
|
GUInt32 nCurBlockYSize;
|
|
|
|
CPLAssert( poGDS != NULL
|
|
&& nBlockXOff >= 0
|
|
&& nBlockYOff >= 0
|
|
&& pImage != NULL );
|
|
|
|
memset( pImage, 0, nBlockBytes );
|
|
|
|
if (2 * nTile + 1 >= poGDS->sHeader.nTileTblSize / sizeof(GUInt32))
|
|
{
|
|
return CE_Failure;
|
|
}
|
|
|
|
nTileBytes = poGDS->paiTiles[2 * nTile + 1];
|
|
|
|
if ( poGDS->sHeader.nLastTileHeight
|
|
&& (GUInt32) nBlockYOff == poGDS->nYTiles - 1 )
|
|
nCurBlockYSize = poGDS->sHeader.nLastTileHeight;
|
|
else
|
|
nCurBlockYSize = nBlockYSize;
|
|
|
|
if ( VSIFSeekL( poGDS->fp, poGDS->paiTiles[2 * nTile], SEEK_SET ) < 0 )
|
|
{
|
|
// XXX: We will not report error here, because file just may be
|
|
// in update state and data for this block will be available later
|
|
if( poGDS->eAccess == GA_Update )
|
|
return CE_None;
|
|
else
|
|
{
|
|
CPLError( CE_Failure, CPLE_FileIO,
|
|
"Can't seek to offset %ld in input file to read data.\n%s\n",
|
|
(long) poGDS->paiTiles[2 * nTile], VSIStrerror( errno ) );
|
|
return CE_Failure;
|
|
}
|
|
}
|
|
|
|
if ( poGDS->nBands == 1 &&
|
|
( poGDS->sHeader.nBitDepth == 8
|
|
|| poGDS->sHeader.nBitDepth == 16
|
|
|| poGDS->sHeader.nBitDepth == 32
|
|
|| poGDS->sHeader.nBitDepth == 64 ) )
|
|
{
|
|
if ( nTileBytes > nBlockBytes )
|
|
nTileBytes = nBlockBytes;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Decompress buffer, if needed. */
|
|
/* -------------------------------------------------------------------- */
|
|
if ( poGDS->Decompress )
|
|
{
|
|
GUInt32 nRawBytes;
|
|
|
|
if ( nLastTileXBytes && (GUInt32)nBlockXOff == poGDS->nXTiles - 1 )
|
|
nRawBytes = nLastTileXBytes;
|
|
else
|
|
nRawBytes = poGDS->nBands * nBlockXSize * nDataSize;
|
|
|
|
if ( nLastTileHeight && (GUInt32)nBlockYOff == poGDS->nYTiles - 1 )
|
|
nRawBytes *= nLastTileHeight;
|
|
else
|
|
nRawBytes *= nBlockYSize;
|
|
|
|
if ( nRawBytes > nTileBytes )
|
|
{
|
|
GByte *pabyTile = (GByte *) VSIMalloc( nTileBytes );
|
|
|
|
if ( !pabyTile )
|
|
{
|
|
CPLError( CE_Failure, CPLE_FileIO,
|
|
"Can't allocate tile block of size %lu.\n%s\n",
|
|
(unsigned long) nTileBytes, VSIStrerror( errno ) );
|
|
return CE_Failure;
|
|
}
|
|
|
|
if ( ReadBuffer( pabyTile, nTileBytes ) == CE_Failure )
|
|
{
|
|
// XXX: Do not fail here, just return empty block
|
|
// and continue reading.
|
|
CPLFree( pabyTile );
|
|
return CE_None;
|
|
}
|
|
|
|
(*poGDS->Decompress)( pabyTile, nTileBytes,
|
|
(GByte*)pImage, nRawBytes );
|
|
CPLFree( pabyTile );
|
|
nTileBytes = nRawBytes;
|
|
}
|
|
else
|
|
{
|
|
if ( ReadBuffer( (GByte *)pImage, nTileBytes ) == CE_Failure )
|
|
{
|
|
// XXX: Do not fail here, just return empty block
|
|
// and continue reading.
|
|
return CE_None;
|
|
}
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
|
|
if ( ReadBuffer( (GByte *)pImage, nTileBytes ) == CE_Failure )
|
|
{
|
|
// XXX: Do not fail here, just return empty block
|
|
// and continue reading.
|
|
return CE_None;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( poGDS->eRMFType == RMFT_RSW )
|
|
{
|
|
GByte *pabyTile = (GByte *) VSIMalloc( nTileBytes );
|
|
|
|
if ( !pabyTile )
|
|
{
|
|
CPLError( CE_Failure, CPLE_FileIO,
|
|
"Can't allocate tile block of size %lu.\n%s\n",
|
|
(unsigned long) nTileBytes, VSIStrerror( errno ) );
|
|
return CE_Failure;
|
|
}
|
|
|
|
|
|
if ( ReadBuffer( pabyTile, nTileBytes ) == CE_Failure )
|
|
{
|
|
// XXX: Do not fail here, just return empty block
|
|
// and continue reading.
|
|
CPLFree( pabyTile );
|
|
return CE_None;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* If buffer was compressed, decompress it first. */
|
|
/* -------------------------------------------------------------------- */
|
|
if ( poGDS->Decompress )
|
|
{
|
|
GUInt32 nRawBytes;
|
|
|
|
if ( nLastTileXBytes && (GUInt32)nBlockXOff == poGDS->nXTiles - 1 )
|
|
nRawBytes = nLastTileXBytes;
|
|
else
|
|
nRawBytes = poGDS->nBands * nBlockXSize * nDataSize;
|
|
|
|
if ( nLastTileHeight && (GUInt32)nBlockYOff == poGDS->nYTiles - 1 )
|
|
nRawBytes *= nLastTileHeight;
|
|
else
|
|
nRawBytes *= nBlockYSize;
|
|
|
|
if ( nRawBytes > nTileBytes )
|
|
{
|
|
GByte *pszRawBuf = (GByte *)VSIMalloc( nRawBytes );
|
|
if (pszRawBuf == NULL)
|
|
{
|
|
CPLError( CE_Failure, CPLE_FileIO,
|
|
"Can't allocate a buffer for raw data of size %lu.\n%s\n",
|
|
(unsigned long) nRawBytes, VSIStrerror( errno ) );
|
|
|
|
VSIFree( pabyTile );
|
|
return CE_Failure;
|
|
}
|
|
|
|
(*poGDS->Decompress)( pabyTile, nTileBytes,
|
|
pszRawBuf, nRawBytes );
|
|
CPLFree( pabyTile );
|
|
pabyTile = pszRawBuf;
|
|
nTileBytes = nRawBytes;
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Deinterleave pixels from input buffer. */
|
|
/* -------------------------------------------------------------------- */
|
|
GUInt32 i;
|
|
|
|
if ( poGDS->sHeader.nBitDepth == 24 || poGDS->sHeader.nBitDepth == 32 )
|
|
{
|
|
GUInt32 nTileSize = nTileBytes / nBytesPerPixel;
|
|
|
|
if ( nTileSize > nBlockSize )
|
|
nTileSize = nBlockSize;
|
|
|
|
for ( i = 0; i < nTileSize; i++ )
|
|
{
|
|
// Colour triplets in RMF file organized in reverse order:
|
|
// blue, green, red. When we have 32-bit RMF the forth byte
|
|
// in quadriplet should be discarded as it has no meaning.
|
|
// That is why we always use 3 byte count in the following
|
|
// pabyTemp index.
|
|
((GByte *) pImage)[i] =
|
|
pabyTile[i * nBytesPerPixel + 3 - nBand];
|
|
}
|
|
}
|
|
|
|
else if ( poGDS->sHeader.nBitDepth == 16 )
|
|
{
|
|
GUInt32 nTileSize = nTileBytes / nBytesPerPixel;
|
|
|
|
if ( nTileSize > nBlockSize )
|
|
nTileSize = nBlockSize;
|
|
|
|
for ( i = 0; i < nTileSize; i++ )
|
|
{
|
|
switch ( nBand )
|
|
{
|
|
case 1:
|
|
((GByte *) pImage)[i] =
|
|
(GByte)((((GUInt16*)pabyTile)[i] & 0x7c00) >> 7);
|
|
break;
|
|
case 2:
|
|
((GByte *) pImage)[i] =
|
|
(GByte)((((GUInt16*)pabyTile)[i] & 0x03e0) >> 2);
|
|
break;
|
|
case 3:
|
|
((GByte *) pImage)[i] =
|
|
(GByte)(((GUInt16*)pabyTile)[i] & 0x1F) << 3;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
else if ( poGDS->sHeader.nBitDepth == 4 )
|
|
{
|
|
GByte *pabyTemp = pabyTile;
|
|
|
|
for ( i = 0; i < nBlockSize; i++ )
|
|
{
|
|
// Most significant part of the byte represents leftmost pixel
|
|
if ( i & 0x01 )
|
|
((GByte *) pImage)[i] = *pabyTemp++ & 0x0F;
|
|
else
|
|
((GByte *) pImage)[i] = (*pabyTemp & 0xF0) >> 4;
|
|
}
|
|
}
|
|
|
|
else if ( poGDS->sHeader.nBitDepth == 1 )
|
|
{
|
|
GByte *pabyTemp = pabyTile;
|
|
|
|
for ( i = 0; i < nBlockSize; i++ )
|
|
{
|
|
switch ( i & 0x7 )
|
|
{
|
|
case 0:
|
|
((GByte *) pImage)[i] = (*pabyTemp & 0x80) >> 7;
|
|
break;
|
|
case 1:
|
|
((GByte *) pImage)[i] = (*pabyTemp & 0x40) >> 6;
|
|
break;
|
|
case 2:
|
|
((GByte *) pImage)[i] = (*pabyTemp & 0x20) >> 5;
|
|
break;
|
|
case 3:
|
|
((GByte *) pImage)[i] = (*pabyTemp & 0x10) >> 4;
|
|
break;
|
|
case 4:
|
|
((GByte *) pImage)[i] = (*pabyTemp & 0x08) >> 3;
|
|
break;
|
|
case 5:
|
|
((GByte *) pImage)[i] = (*pabyTemp & 0x04) >> 2;
|
|
break;
|
|
case 6:
|
|
((GByte *) pImage)[i] = (*pabyTemp & 0x02) >> 1;
|
|
break;
|
|
case 7:
|
|
((GByte *) pImage)[i] = *pabyTemp++ & 0x01;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
CPLFree( pabyTile );
|
|
}
|
|
|
|
if ( nLastTileXBytes
|
|
&& (GUInt32) nBlockXOff == poGDS->nXTiles - 1 )
|
|
{
|
|
GUInt32 iRow;
|
|
|
|
for ( iRow = nCurBlockYSize - 1; iRow > 0; iRow-- )
|
|
{
|
|
memmove( (GByte *)pImage + nBlockXSize * iRow * nDataSize,
|
|
(GByte *)pImage + iRow * nLastTileXBytes,
|
|
nLastTileXBytes );
|
|
}
|
|
|
|
}
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* IWriteBlock() */
|
|
/************************************************************************/
|
|
|
|
CPLErr RMFRasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
|
|
void * pImage )
|
|
{
|
|
RMFDataset *poGDS = (RMFDataset *)poDS;
|
|
GUInt32 nTile = nBlockYOff * poGDS->nXTiles + nBlockXOff;
|
|
GUInt32 nTileBytes = nDataSize * poGDS->nBands;
|
|
GUInt32 iInPixel, iOutPixel, nCurBlockYSize;
|
|
GByte *pabyTile;
|
|
|
|
CPLAssert( poGDS != NULL
|
|
&& nBlockXOff >= 0
|
|
&& nBlockYOff >= 0
|
|
&& pImage != NULL );
|
|
|
|
if ( poGDS->paiTiles[2 * nTile] )
|
|
{
|
|
if ( VSIFSeekL( poGDS->fp, poGDS->paiTiles[2 * nTile], SEEK_SET ) < 0 )
|
|
{
|
|
CPLError( CE_Failure, CPLE_FileIO,
|
|
"Can't seek to offset %ld in output file to write data.\n%s",
|
|
(long) poGDS->paiTiles[2 * nTile],
|
|
VSIStrerror( errno ) );
|
|
return CE_Failure;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( VSIFSeekL( poGDS->fp, 0, SEEK_END ) < 0 )
|
|
{
|
|
CPLError( CE_Failure, CPLE_FileIO,
|
|
"Can't seek to offset %ld in output file to write data.\n%s",
|
|
(long) poGDS->paiTiles[2 * nTile],
|
|
VSIStrerror( errno ) );
|
|
return CE_Failure;
|
|
}
|
|
poGDS->paiTiles[2 * nTile] = (GUInt32) VSIFTellL( poGDS->fp );
|
|
|
|
poGDS->bHeaderDirty = TRUE;
|
|
}
|
|
|
|
if ( nLastTileXBytes
|
|
&& (GUInt32) nBlockXOff == poGDS->nXTiles - 1 )
|
|
nTileBytes *= poGDS->sHeader.nLastTileWidth;
|
|
else
|
|
nTileBytes *= nBlockXSize;
|
|
|
|
if ( poGDS->sHeader.nLastTileHeight
|
|
&& (GUInt32) nBlockYOff == poGDS->nYTiles - 1 )
|
|
nCurBlockYSize = poGDS->sHeader.nLastTileHeight;
|
|
else
|
|
nCurBlockYSize = nBlockYSize;
|
|
|
|
nTileBytes *= nCurBlockYSize;
|
|
|
|
pabyTile = (GByte *) VSICalloc( nTileBytes, 1 );
|
|
if ( !pabyTile )
|
|
{
|
|
CPLError( CE_Failure, CPLE_FileIO,
|
|
"Can't allocate space for the tile blocak of size %lu.\n%s",
|
|
(unsigned long) nTileBytes, VSIStrerror( errno ) );
|
|
return CE_Failure;
|
|
}
|
|
|
|
if ( nLastTileXBytes
|
|
&& (GUInt32) nBlockXOff == poGDS->nXTiles - 1 )
|
|
{
|
|
GUInt32 iRow;
|
|
|
|
if ( poGDS->nBands == 1 )
|
|
{
|
|
for ( iRow = 0; iRow < nCurBlockYSize; iRow++ )
|
|
{
|
|
memcpy( pabyTile + iRow * nLastTileXBytes,
|
|
(GByte*)pImage + nBlockXSize * iRow * nDataSize,
|
|
nLastTileXBytes );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( poGDS->paiTiles[2 * nTile + 1] )
|
|
{
|
|
VSIFReadL( pabyTile, 1, nTileBytes, poGDS->fp );
|
|
VSIFSeekL( poGDS->fp, poGDS->paiTiles[2 * nTile], SEEK_SET );
|
|
}
|
|
|
|
for ( iRow = 0; iRow < nCurBlockYSize; iRow++ )
|
|
{
|
|
for ( iInPixel = 0, iOutPixel = nBytesPerPixel - nBand;
|
|
iOutPixel < nLastTileXBytes * poGDS->nBands;
|
|
iInPixel++, iOutPixel += poGDS->nBands )
|
|
(pabyTile + iRow * nLastTileXBytes * poGDS->nBands)[iOutPixel] =
|
|
((GByte *) pImage + nBlockXSize * iRow * nDataSize)[iInPixel];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( poGDS->nBands == 1 )
|
|
memcpy( pabyTile, pImage, nTileBytes );
|
|
else
|
|
{
|
|
if ( poGDS->paiTiles[2 * nTile + 1] )
|
|
{
|
|
VSIFReadL( pabyTile, 1, nTileBytes, poGDS->fp );
|
|
VSIFSeekL( poGDS->fp, poGDS->paiTiles[2 * nTile], SEEK_SET );
|
|
}
|
|
|
|
for ( iInPixel = 0, iOutPixel = nBytesPerPixel - nBand;
|
|
iOutPixel < nTileBytes;
|
|
iInPixel++, iOutPixel += poGDS->nBands )
|
|
pabyTile[iOutPixel] = ((GByte *) pImage)[iInPixel];
|
|
|
|
}
|
|
}
|
|
|
|
#ifdef CPL_MSB
|
|
if ( poGDS->eRMFType == RMFT_MTW )
|
|
{
|
|
GUInt32 i;
|
|
|
|
if ( poGDS->sHeader.nBitDepth == 16 )
|
|
{
|
|
for ( i = 0; i < nTileBytes; i += 2 )
|
|
CPL_SWAP16PTR( pabyTile + i );
|
|
}
|
|
|
|
else if ( poGDS->sHeader.nBitDepth == 32 )
|
|
{
|
|
for ( i = 0; i < nTileBytes; i += 4 )
|
|
CPL_SWAP32PTR( pabyTile + i );
|
|
}
|
|
|
|
else if ( poGDS->sHeader.nBitDepth == 64 )
|
|
{
|
|
for ( i = 0; i < nTileBytes; i += 8 )
|
|
CPL_SWAPDOUBLE( pabyTile + i );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if ( VSIFWriteL( pabyTile, 1, nTileBytes, poGDS->fp ) < nTileBytes )
|
|
{
|
|
CPLError( CE_Failure, CPLE_FileIO,
|
|
"Can't write block with X offset %d and Y offset %d.\n%s",
|
|
nBlockXOff, nBlockYOff, VSIStrerror( errno ) );
|
|
VSIFree( pabyTile );
|
|
return CE_Failure;
|
|
}
|
|
|
|
poGDS->paiTiles[2 * nTile + 1] = nTileBytes;
|
|
VSIFree( pabyTile );
|
|
|
|
poGDS->bHeaderDirty = TRUE;
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetUnitType() */
|
|
/************************************************************************/
|
|
|
|
const char *RMFRasterBand::GetUnitType()
|
|
|
|
{
|
|
RMFDataset *poGDS = (RMFDataset *) poDS;
|
|
|
|
return (const char *)poGDS->pszUnitType;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetUnitType() */
|
|
/************************************************************************/
|
|
|
|
CPLErr RMFRasterBand::SetUnitType( const char *pszNewValue )
|
|
|
|
{
|
|
RMFDataset *poGDS = (RMFDataset *) poDS;
|
|
|
|
CPLFree(poGDS->pszUnitType);
|
|
poGDS->pszUnitType = CPLStrdup( pszNewValue );
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetColorTable() */
|
|
/************************************************************************/
|
|
|
|
GDALColorTable *RMFRasterBand::GetColorTable()
|
|
{
|
|
RMFDataset *poGDS = (RMFDataset *) poDS;
|
|
|
|
return poGDS->poColorTable;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetColorTable() */
|
|
/************************************************************************/
|
|
|
|
CPLErr RMFRasterBand::SetColorTable( GDALColorTable *poColorTable )
|
|
{
|
|
RMFDataset *poGDS = (RMFDataset *) poDS;
|
|
|
|
if ( poColorTable )
|
|
{
|
|
if ( poGDS->eRMFType == RMFT_RSW && poGDS->nBands == 1 )
|
|
{
|
|
GDALColorEntry oEntry;
|
|
GUInt32 i;
|
|
|
|
if ( !poGDS->pabyColorTable )
|
|
return CE_Failure;
|
|
|
|
for( i = 0; i < poGDS->nColorTableSize; i++ )
|
|
{
|
|
poColorTable->GetColorEntryAsRGB( i, &oEntry );
|
|
poGDS->pabyColorTable[i * 4] = (GByte) oEntry.c1; // Red
|
|
poGDS->pabyColorTable[i * 4 + 1] = (GByte) oEntry.c2; // Green
|
|
poGDS->pabyColorTable[i * 4 + 2] = (GByte) oEntry.c3; // Blue
|
|
poGDS->pabyColorTable[i * 4 + 3] = 0;
|
|
}
|
|
|
|
poGDS->bHeaderDirty = TRUE;
|
|
}
|
|
}
|
|
else
|
|
return CE_Failure;
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetColorInterpretation() */
|
|
/************************************************************************/
|
|
|
|
GDALColorInterp RMFRasterBand::GetColorInterpretation()
|
|
{
|
|
RMFDataset *poGDS = (RMFDataset *) poDS;
|
|
|
|
if( poGDS->nBands == 3 )
|
|
{
|
|
if( nBand == 1 )
|
|
return GCI_RedBand;
|
|
else if( nBand == 2 )
|
|
return GCI_GreenBand;
|
|
else if( nBand == 3 )
|
|
return GCI_BlueBand;
|
|
else
|
|
return GCI_Undefined;
|
|
}
|
|
else
|
|
{
|
|
if ( poGDS->eRMFType == RMFT_RSW )
|
|
return GCI_PaletteIndex;
|
|
else
|
|
return GCI_Undefined;
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ==================================================================== */
|
|
/* RMFDataset */
|
|
/* ==================================================================== */
|
|
/************************************************************************/
|
|
|
|
/************************************************************************/
|
|
/* RMFDataset() */
|
|
/************************************************************************/
|
|
|
|
RMFDataset::RMFDataset()
|
|
{
|
|
pszFilename = NULL;
|
|
fp = NULL;
|
|
nBands = 0;
|
|
nXTiles = 0;
|
|
nYTiles = 0;
|
|
paiTiles = NULL;
|
|
pszProjection = CPLStrdup( "" );
|
|
pszUnitType = CPLStrdup( RMF_UnitsEmpty );
|
|
adfGeoTransform[0] = 0.0;
|
|
adfGeoTransform[1] = 1.0;
|
|
adfGeoTransform[2] = 0.0;
|
|
adfGeoTransform[3] = 0.0;
|
|
adfGeoTransform[4] = 0.0;
|
|
adfGeoTransform[5] = 1.0;
|
|
pabyColorTable = NULL;
|
|
poColorTable = NULL;
|
|
eRMFType = RMFT_RSW;
|
|
memset( &sHeader, 0, sizeof(sHeader) );
|
|
memset( &sExtHeader, 0, sizeof(sExtHeader) );
|
|
|
|
Decompress = NULL;
|
|
|
|
bBigEndian = FALSE;
|
|
bHeaderDirty = FALSE;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ~RMFDataset() */
|
|
/************************************************************************/
|
|
|
|
RMFDataset::~RMFDataset()
|
|
{
|
|
FlushCache();
|
|
|
|
if ( paiTiles )
|
|
CPLFree( paiTiles );
|
|
if ( pszProjection )
|
|
CPLFree( pszProjection );
|
|
if ( pszUnitType )
|
|
CPLFree( pszUnitType );
|
|
if ( pabyColorTable )
|
|
CPLFree( pabyColorTable );
|
|
if ( poColorTable != NULL )
|
|
delete poColorTable;
|
|
if( fp != NULL )
|
|
VSIFCloseL( fp );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetGeoTransform() */
|
|
/************************************************************************/
|
|
|
|
CPLErr RMFDataset::GetGeoTransform( double * padfTransform )
|
|
{
|
|
memcpy( padfTransform, adfGeoTransform, sizeof(adfGeoTransform[0]) * 6 );
|
|
|
|
if( sHeader.iGeorefFlag )
|
|
return CE_None;
|
|
else
|
|
return CE_Failure;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetGeoTransform() */
|
|
/************************************************************************/
|
|
|
|
CPLErr RMFDataset::SetGeoTransform( double * padfTransform )
|
|
{
|
|
memcpy( adfGeoTransform, padfTransform, sizeof(double) * 6 );
|
|
sHeader.dfPixelSize = adfGeoTransform[1];
|
|
if ( sHeader.dfPixelSize != 0.0 )
|
|
sHeader.dfResolution = sHeader.dfScale / sHeader.dfPixelSize;
|
|
sHeader.dfLLX = adfGeoTransform[0];
|
|
sHeader.dfLLY = adfGeoTransform[3] - nRasterYSize * sHeader.dfPixelSize;
|
|
sHeader.iGeorefFlag = 1;
|
|
|
|
bHeaderDirty = TRUE;
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetProjectionRef() */
|
|
/************************************************************************/
|
|
|
|
const char *RMFDataset::GetProjectionRef()
|
|
{
|
|
if( pszProjection )
|
|
return pszProjection;
|
|
else
|
|
return "";
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetProjection() */
|
|
/************************************************************************/
|
|
|
|
CPLErr RMFDataset::SetProjection( const char * pszNewProjection )
|
|
|
|
{
|
|
if ( pszProjection )
|
|
CPLFree( pszProjection );
|
|
pszProjection = CPLStrdup( (pszNewProjection) ? pszNewProjection : "" );
|
|
|
|
bHeaderDirty = TRUE;
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* WriteHeader() */
|
|
/************************************************************************/
|
|
|
|
CPLErr RMFDataset::WriteHeader()
|
|
{
|
|
/* -------------------------------------------------------------------- */
|
|
/* Setup projection. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( pszProjection && !EQUAL( pszProjection, "" ) )
|
|
{
|
|
OGRSpatialReference oSRS;
|
|
long iProjection, iDatum, iEllips, iZone;
|
|
char *pszProj = pszProjection;
|
|
|
|
if ( oSRS.importFromWkt( &pszProj ) == OGRERR_NONE )
|
|
{
|
|
double adfPrjParams[7];
|
|
|
|
oSRS.exportToPanorama( &iProjection, &iDatum, &iEllips, &iZone,
|
|
adfPrjParams );
|
|
sHeader.iProjection = iProjection;
|
|
sHeader.dfStdP1 = adfPrjParams[0];
|
|
sHeader.dfStdP2 = adfPrjParams[1];
|
|
sHeader.dfCenterLat = adfPrjParams[2];
|
|
sHeader.dfCenterLong = adfPrjParams[3];
|
|
|
|
sExtHeader.nEllipsoid = iEllips;
|
|
sExtHeader.nDatum = iDatum;
|
|
sExtHeader.nZone = iZone;
|
|
}
|
|
}
|
|
|
|
#define RMF_WRITE_LONG( ptr, value, offset ) \
|
|
do { \
|
|
GInt32 iLong = CPL_LSBWORD32( value ); \
|
|
memcpy( (ptr) + (offset), &iLong, 4 ); \
|
|
} while(0);
|
|
|
|
#define RMF_WRITE_ULONG( ptr,value, offset ) \
|
|
do { \
|
|
GUInt32 iULong = CPL_LSBWORD32( value ); \
|
|
memcpy( (ptr) + (offset), &iULong, 4 ); \
|
|
} while(0);
|
|
|
|
#define RMF_WRITE_DOUBLE( ptr,value, offset ) \
|
|
do { \
|
|
double dfDouble = (value); \
|
|
CPL_LSBPTR64( &dfDouble ); \
|
|
memcpy( (ptr) + (offset), &dfDouble, 8 ); \
|
|
} while(0);
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Write out the main header. */
|
|
/* -------------------------------------------------------------------- */
|
|
{
|
|
GByte abyHeader[RMF_HEADER_SIZE];
|
|
|
|
memset( abyHeader, 0, sizeof(abyHeader) );
|
|
|
|
memcpy( abyHeader, sHeader.bySignature, RMF_SIGNATURE_SIZE );
|
|
RMF_WRITE_ULONG( abyHeader, sHeader.iVersion, 4 );
|
|
//
|
|
RMF_WRITE_ULONG( abyHeader, sHeader.nOvrOffset, 12 );
|
|
RMF_WRITE_ULONG( abyHeader, sHeader.iUserID, 16 );
|
|
memcpy( abyHeader + 20, sHeader.byName, RMF_NAME_SIZE );
|
|
RMF_WRITE_ULONG( abyHeader, sHeader.nBitDepth, 52 );
|
|
RMF_WRITE_ULONG( abyHeader, sHeader.nHeight, 56 );
|
|
RMF_WRITE_ULONG( abyHeader, sHeader.nWidth, 60 );
|
|
RMF_WRITE_ULONG( abyHeader, sHeader.nXTiles, 64 );
|
|
RMF_WRITE_ULONG( abyHeader, sHeader.nYTiles, 68 );
|
|
RMF_WRITE_ULONG( abyHeader, sHeader.nTileHeight, 72 );
|
|
RMF_WRITE_ULONG( abyHeader, sHeader.nTileWidth, 76 );
|
|
RMF_WRITE_ULONG( abyHeader, sHeader.nLastTileHeight, 80 );
|
|
RMF_WRITE_ULONG( abyHeader, sHeader.nLastTileWidth, 84 );
|
|
RMF_WRITE_ULONG( abyHeader, sHeader.nROIOffset, 88 );
|
|
RMF_WRITE_ULONG( abyHeader, sHeader.nROISize, 92 );
|
|
RMF_WRITE_ULONG( abyHeader, sHeader.nClrTblOffset, 96 );
|
|
RMF_WRITE_ULONG( abyHeader, sHeader.nClrTblSize, 100 );
|
|
RMF_WRITE_ULONG( abyHeader, sHeader.nTileTblOffset, 104 );
|
|
RMF_WRITE_ULONG( abyHeader, sHeader.nTileTblSize, 108 );
|
|
RMF_WRITE_LONG( abyHeader, sHeader.iMapType, 124 );
|
|
RMF_WRITE_LONG( abyHeader, sHeader.iProjection, 128 );
|
|
RMF_WRITE_DOUBLE( abyHeader, sHeader.dfScale, 136 );
|
|
RMF_WRITE_DOUBLE( abyHeader, sHeader.dfResolution, 144 );
|
|
RMF_WRITE_DOUBLE( abyHeader, sHeader.dfPixelSize, 152 );
|
|
RMF_WRITE_DOUBLE( abyHeader, sHeader.dfLLY, 160 );
|
|
RMF_WRITE_DOUBLE( abyHeader, sHeader.dfLLX, 168 );
|
|
RMF_WRITE_DOUBLE( abyHeader, sHeader.dfStdP1, 176 );
|
|
RMF_WRITE_DOUBLE( abyHeader, sHeader.dfStdP2, 184 );
|
|
RMF_WRITE_DOUBLE( abyHeader, sHeader.dfCenterLong, 192 );
|
|
RMF_WRITE_DOUBLE( abyHeader, sHeader.dfCenterLat, 200 );
|
|
*(abyHeader + 208) = sHeader.iCompression;
|
|
*(abyHeader + 209) = sHeader.iMaskType;
|
|
*(abyHeader + 210) = sHeader.iMaskStep;
|
|
*(abyHeader + 211) = sHeader.iFrameFlag;
|
|
RMF_WRITE_ULONG( abyHeader, sHeader.nFlagsTblOffset, 212 );
|
|
RMF_WRITE_ULONG( abyHeader, sHeader.nFlagsTblSize, 216 );
|
|
RMF_WRITE_ULONG( abyHeader, sHeader.nFileSize0, 220 );
|
|
RMF_WRITE_ULONG( abyHeader, sHeader.nFileSize1, 224 );
|
|
*(abyHeader + 228) = sHeader.iUnknown;
|
|
*(abyHeader + 244) = sHeader.iGeorefFlag;
|
|
*(abyHeader + 245) = sHeader.iInverse;
|
|
memcpy( abyHeader + 248, sHeader.abyInvisibleColors,
|
|
sizeof(sHeader.abyInvisibleColors) );
|
|
RMF_WRITE_DOUBLE( abyHeader, sHeader.adfElevMinMax[0], 280 );
|
|
RMF_WRITE_DOUBLE( abyHeader, sHeader.adfElevMinMax[1], 288 );
|
|
RMF_WRITE_DOUBLE( abyHeader, sHeader.dfNoData, 296 );
|
|
RMF_WRITE_ULONG( abyHeader, sHeader.iElevationUnit, 304 );
|
|
*(abyHeader + 308) = sHeader.iElevationType;
|
|
RMF_WRITE_ULONG( abyHeader, sHeader.nExtHdrOffset, 312 );
|
|
RMF_WRITE_ULONG( abyHeader, sHeader.nExtHdrSize, 316 );
|
|
|
|
VSIFSeekL( fp, 0, SEEK_SET );
|
|
VSIFWriteL( abyHeader, 1, sizeof(abyHeader), fp );
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Write out the extended header. */
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
if ( sHeader.nExtHdrOffset && sHeader.nExtHdrSize )
|
|
{
|
|
GByte *pabyExtHeader = (GByte *)CPLCalloc( sHeader.nExtHdrSize, 1 );
|
|
|
|
RMF_WRITE_LONG( pabyExtHeader, sExtHeader.nEllipsoid, 24 );
|
|
RMF_WRITE_LONG( pabyExtHeader, sExtHeader.nDatum, 32 );
|
|
RMF_WRITE_LONG( pabyExtHeader, sExtHeader.nZone, 36 );
|
|
|
|
VSIFSeekL( fp, sHeader.nExtHdrOffset, SEEK_SET );
|
|
VSIFWriteL( pabyExtHeader, 1, sHeader.nExtHdrSize, fp );
|
|
|
|
CPLFree( pabyExtHeader );
|
|
}
|
|
|
|
#undef RMF_WRITE_DOUBLE
|
|
#undef RMF_WRITE_ULONG
|
|
#undef RMF_WRITE_LONG
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Write out the color table. */
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
if ( sHeader.nClrTblOffset && sHeader.nClrTblSize )
|
|
{
|
|
VSIFSeekL( fp, sHeader.nClrTblOffset, SEEK_SET );
|
|
VSIFWriteL( pabyColorTable, 1, sHeader.nClrTblSize, fp );
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Write out the block table, swap if needed. */
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
VSIFSeekL( fp, sHeader.nTileTblOffset, SEEK_SET );
|
|
|
|
#ifdef CPL_MSB
|
|
GUInt32 i;
|
|
GUInt32 *paiTilesSwapped = (GUInt32 *)CPLMalloc( sHeader.nTileTblSize );
|
|
|
|
if ( !paiTilesSwapped )
|
|
return CE_Failure;
|
|
|
|
memcpy( paiTilesSwapped, paiTiles, sHeader.nTileTblSize );
|
|
for ( i = 0; i < sHeader.nTileTblSize / sizeof(GUInt32); i++ )
|
|
CPL_SWAP32PTR( paiTilesSwapped + i );
|
|
VSIFWriteL( paiTilesSwapped, 1, sHeader.nTileTblSize, fp );
|
|
|
|
CPLFree( paiTilesSwapped );
|
|
#else
|
|
VSIFWriteL( paiTiles, 1, sHeader.nTileTblSize, fp );
|
|
#endif
|
|
|
|
bHeaderDirty = FALSE;
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* FlushCache() */
|
|
/************************************************************************/
|
|
|
|
void RMFDataset::FlushCache()
|
|
|
|
{
|
|
GDALDataset::FlushCache();
|
|
|
|
if ( !bHeaderDirty )
|
|
return;
|
|
|
|
if ( eRMFType == RMFT_MTW )
|
|
{
|
|
GDALRasterBand *poBand = GetRasterBand(1);
|
|
|
|
if ( poBand )
|
|
{
|
|
poBand->ComputeRasterMinMax( FALSE, sHeader.adfElevMinMax );
|
|
bHeaderDirty = TRUE;
|
|
}
|
|
}
|
|
WriteHeader();
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Identify() */
|
|
/************************************************************************/
|
|
|
|
int RMFDataset::Identify( GDALOpenInfo *poOpenInfo )
|
|
|
|
{
|
|
if( poOpenInfo->pabyHeader == NULL)
|
|
return FALSE;
|
|
|
|
if( memcmp(poOpenInfo->pabyHeader, RMF_SigRSW, sizeof(RMF_SigRSW)) != 0
|
|
&& memcmp(poOpenInfo->pabyHeader, RMF_SigRSW_BE, sizeof(RMF_SigRSW_BE)) != 0
|
|
&& memcmp(poOpenInfo->pabyHeader, RMF_SigMTW, sizeof(RMF_SigMTW)) != 0 )
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Open() */
|
|
/************************************************************************/
|
|
|
|
GDALDataset *RMFDataset::Open( GDALOpenInfo * poOpenInfo )
|
|
{
|
|
if ( !Identify(poOpenInfo) )
|
|
return NULL;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Create a corresponding GDALDataset. */
|
|
/* -------------------------------------------------------------------- */
|
|
RMFDataset *poDS;
|
|
|
|
poDS = new RMFDataset();
|
|
|
|
if( poOpenInfo->eAccess == GA_ReadOnly )
|
|
poDS->fp = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
|
|
else
|
|
poDS->fp = VSIFOpenL( poOpenInfo->pszFilename, "r+b" );
|
|
if ( !poDS->fp )
|
|
{
|
|
delete poDS;
|
|
return NULL;
|
|
}
|
|
|
|
#define RMF_READ_ULONG(ptr, value, offset) \
|
|
do { \
|
|
if ( poDS->bBigEndian ) \
|
|
{ \
|
|
(value) = CPL_MSBWORD32(*(GUInt32*)((ptr) + (offset))); \
|
|
} \
|
|
else \
|
|
{ \
|
|
(value) = CPL_LSBWORD32(*(GUInt32*)((ptr) + (offset))); \
|
|
} \
|
|
} while(0);
|
|
|
|
#define RMF_READ_LONG(ptr, value, offset) \
|
|
do { \
|
|
if ( poDS->bBigEndian ) \
|
|
{ \
|
|
(value) = CPL_MSBWORD32(*(GInt32*)((ptr) + (offset))); \
|
|
} \
|
|
else \
|
|
{ \
|
|
(value) = CPL_LSBWORD32(*(GInt32*)((ptr) + (offset))); \
|
|
} \
|
|
} while(0);
|
|
|
|
#define RMF_READ_DOUBLE(ptr, value, offset) \
|
|
do { \
|
|
(value) = *(double*)((ptr) + (offset)); \
|
|
if ( poDS->bBigEndian ) \
|
|
{ \
|
|
CPL_MSBPTR64(&(value)); \
|
|
} \
|
|
else \
|
|
{ \
|
|
CPL_LSBPTR64(&(value)); \
|
|
} \
|
|
} while(0);
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Read the main header. */
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
{
|
|
GByte abyHeader[RMF_HEADER_SIZE];
|
|
|
|
VSIFSeekL( poDS->fp, 0, SEEK_SET );
|
|
VSIFReadL( abyHeader, 1, sizeof(abyHeader), poDS->fp );
|
|
|
|
if ( memcmp(abyHeader, RMF_SigMTW, sizeof(RMF_SigMTW)) == 0 )
|
|
poDS->eRMFType = RMFT_MTW;
|
|
else if ( memcmp(abyHeader, RMF_SigRSW_BE, sizeof(RMF_SigRSW_BE)) == 0 )
|
|
{
|
|
poDS->eRMFType = RMFT_RSW;
|
|
poDS->bBigEndian = TRUE;
|
|
}
|
|
else
|
|
poDS->eRMFType = RMFT_RSW;
|
|
|
|
memcpy( poDS->sHeader.bySignature, abyHeader, RMF_SIGNATURE_SIZE );
|
|
RMF_READ_ULONG( abyHeader, poDS->sHeader.iVersion, 4 );
|
|
RMF_READ_ULONG( abyHeader, poDS->sHeader.nSize, 8 );
|
|
RMF_READ_ULONG( abyHeader, poDS->sHeader.nOvrOffset, 12 );
|
|
RMF_READ_ULONG( abyHeader, poDS->sHeader.iUserID, 16 );
|
|
memcpy( poDS->sHeader.byName, abyHeader + 20,
|
|
sizeof(poDS->sHeader.byName) );
|
|
poDS->sHeader.byName[sizeof(poDS->sHeader.byName) - 1] = '\0';
|
|
RMF_READ_ULONG( abyHeader, poDS->sHeader.nBitDepth, 52 );
|
|
RMF_READ_ULONG( abyHeader, poDS->sHeader.nHeight, 56 );
|
|
RMF_READ_ULONG( abyHeader, poDS->sHeader.nWidth, 60 );
|
|
RMF_READ_ULONG( abyHeader, poDS->sHeader.nXTiles, 64 );
|
|
RMF_READ_ULONG( abyHeader, poDS->sHeader.nYTiles, 68 );
|
|
RMF_READ_ULONG( abyHeader, poDS->sHeader.nTileHeight, 72 );
|
|
RMF_READ_ULONG( abyHeader, poDS->sHeader.nTileWidth, 76 );
|
|
RMF_READ_ULONG( abyHeader, poDS->sHeader.nLastTileHeight, 80 );
|
|
RMF_READ_ULONG( abyHeader, poDS->sHeader.nLastTileWidth, 84 );
|
|
RMF_READ_ULONG( abyHeader, poDS->sHeader.nROIOffset, 88 );
|
|
RMF_READ_ULONG( abyHeader, poDS->sHeader.nROISize, 92 );
|
|
RMF_READ_ULONG( abyHeader, poDS->sHeader.nClrTblOffset, 96 );
|
|
RMF_READ_ULONG( abyHeader, poDS->sHeader.nClrTblSize, 100 );
|
|
RMF_READ_ULONG( abyHeader, poDS->sHeader.nTileTblOffset, 104 );
|
|
RMF_READ_ULONG( abyHeader, poDS->sHeader.nTileTblSize, 108 );
|
|
RMF_READ_LONG( abyHeader, poDS->sHeader.iMapType, 124 );
|
|
RMF_READ_LONG( abyHeader, poDS->sHeader.iProjection, 128 );
|
|
RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfScale, 136 );
|
|
RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfResolution, 144 );
|
|
RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfPixelSize, 152 );
|
|
RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfLLY, 160 );
|
|
RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfLLX, 168 );
|
|
RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfStdP1, 176 );
|
|
RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfStdP2, 184 );
|
|
RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfCenterLong, 192 );
|
|
RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfCenterLat, 200 );
|
|
poDS->sHeader.iCompression = *(abyHeader + 208);
|
|
poDS->sHeader.iMaskType = *(abyHeader + 209);
|
|
poDS->sHeader.iMaskStep = *(abyHeader + 210);
|
|
poDS->sHeader.iFrameFlag = *(abyHeader + 211);
|
|
RMF_READ_ULONG( abyHeader, poDS->sHeader.nFlagsTblOffset, 212 );
|
|
RMF_READ_ULONG( abyHeader, poDS->sHeader.nFlagsTblSize, 216 );
|
|
RMF_READ_ULONG( abyHeader, poDS->sHeader.nFileSize0, 220 );
|
|
RMF_READ_ULONG( abyHeader, poDS->sHeader.nFileSize1, 224 );
|
|
poDS->sHeader.iUnknown = *(abyHeader + 228);
|
|
poDS->sHeader.iGeorefFlag = *(abyHeader + 244);
|
|
poDS->sHeader.iInverse = *(abyHeader + 245);
|
|
memcpy( poDS->sHeader.abyInvisibleColors,
|
|
abyHeader + 248, sizeof(poDS->sHeader.abyInvisibleColors) );
|
|
RMF_READ_DOUBLE( abyHeader, poDS->sHeader.adfElevMinMax[0], 280 );
|
|
RMF_READ_DOUBLE( abyHeader, poDS->sHeader.adfElevMinMax[1], 288 );
|
|
RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfNoData, 296 );
|
|
RMF_READ_ULONG( abyHeader, poDS->sHeader.iElevationUnit, 304 );
|
|
poDS->sHeader.iElevationType = *(abyHeader + 308);
|
|
RMF_READ_ULONG( abyHeader, poDS->sHeader.nExtHdrOffset, 312 );
|
|
RMF_READ_ULONG( abyHeader, poDS->sHeader.nExtHdrSize, 316 );
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Read the extended header. */
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
if ( poDS->sHeader.nExtHdrOffset && poDS->sHeader.nExtHdrSize )
|
|
{
|
|
GByte *pabyExtHeader =
|
|
(GByte *)VSICalloc( poDS->sHeader.nExtHdrSize, 1 );
|
|
if (pabyExtHeader == NULL)
|
|
{
|
|
delete poDS;
|
|
return NULL;
|
|
}
|
|
|
|
VSIFSeekL( poDS->fp, poDS->sHeader.nExtHdrOffset, SEEK_SET );
|
|
VSIFReadL( pabyExtHeader, 1, poDS->sHeader.nExtHdrSize, poDS->fp );
|
|
|
|
RMF_READ_LONG( pabyExtHeader, poDS->sExtHeader.nEllipsoid, 24 );
|
|
RMF_READ_LONG( pabyExtHeader, poDS->sExtHeader.nDatum, 32 );
|
|
RMF_READ_LONG( pabyExtHeader, poDS->sExtHeader.nZone, 36 );
|
|
|
|
CPLFree( pabyExtHeader );
|
|
}
|
|
|
|
#undef RMF_READ_DOUBLE
|
|
#undef RMF_READ_LONG
|
|
#undef RMF_READ_ULONG
|
|
|
|
#ifdef DEBUG
|
|
|
|
CPLDebug( "RMF", "%s image has width %d, height %d, bit depth %d, "
|
|
"compression scheme %d, %s, nodata %f",
|
|
(poDS->eRMFType == RMFT_MTW) ? "MTW" : "RSW",
|
|
poDS->sHeader.nWidth, poDS->sHeader.nHeight,
|
|
poDS->sHeader.nBitDepth, poDS->sHeader.iCompression,
|
|
poDS->bBigEndian ? "big endian" : "little endian",
|
|
poDS->sHeader.dfNoData );
|
|
CPLDebug( "RMF", "Size %d, offset to overview %#lx, user ID %d, "
|
|
"ROI offset %#lx, ROI size %d",
|
|
poDS->sHeader.nSize, (unsigned long)poDS->sHeader.nOvrOffset,
|
|
poDS->sHeader.iUserID, (unsigned long)poDS->sHeader.nROIOffset,
|
|
poDS->sHeader.nROISize );
|
|
CPLDebug( "RMF", "Map type %d, projection %d, scale %f, resolution %f, ",
|
|
poDS->sHeader.iMapType, poDS->sHeader.iProjection,
|
|
poDS->sHeader.dfScale, poDS->sHeader.dfResolution );
|
|
CPLDebug( "RMF", "Georeferencing: pixel size %f, LLX %f, LLY %f",
|
|
poDS->sHeader.dfPixelSize,
|
|
poDS->sHeader.dfLLX, poDS->sHeader.dfLLY );
|
|
if ( poDS->sHeader.nROIOffset && poDS->sHeader.nROISize )
|
|
{
|
|
GUInt32 i;
|
|
GInt32 nValue;
|
|
|
|
CPLDebug( "RMF", "ROI coordinates:" );
|
|
for ( i = 0; i < poDS->sHeader.nROISize; i += sizeof(nValue) )
|
|
{
|
|
GUInt32 nValue;
|
|
|
|
VSIFSeekL( poDS->fp, poDS->sHeader.nROIOffset + i, SEEK_SET );
|
|
VSIFReadL( &nValue, 1, sizeof(nValue), poDS->fp );
|
|
|
|
CPLDebug( "RMF", "%d", nValue );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Read array of blocks offsets/sizes. */
|
|
/* -------------------------------------------------------------------- */
|
|
GUInt32 i;
|
|
|
|
if ( VSIFSeekL( poDS->fp, poDS->sHeader.nTileTblOffset, SEEK_SET ) < 0)
|
|
{
|
|
delete poDS;
|
|
return NULL;
|
|
}
|
|
|
|
poDS->paiTiles = (GUInt32 *)VSIMalloc( poDS->sHeader.nTileTblSize );
|
|
if ( !poDS->paiTiles )
|
|
{
|
|
delete poDS;
|
|
return NULL;
|
|
}
|
|
|
|
if ( VSIFReadL( poDS->paiTiles, 1, poDS->sHeader.nTileTblSize,
|
|
poDS->fp ) < poDS->sHeader.nTileTblSize )
|
|
{
|
|
CPLDebug( "RMF", "Can't read tiles offsets/sizes table." );
|
|
delete poDS;
|
|
return NULL;
|
|
}
|
|
|
|
#ifdef CPL_MSB
|
|
if ( !poDS->bBigEndian )
|
|
{
|
|
for ( i = 0; i < poDS->sHeader.nTileTblSize / sizeof(GUInt32); i++ )
|
|
CPL_SWAP32PTR( poDS->paiTiles + i );
|
|
}
|
|
#else
|
|
if ( poDS->bBigEndian )
|
|
{
|
|
for ( i = 0; i < poDS->sHeader.nTileTblSize / sizeof(GUInt32); i++ )
|
|
CPL_SWAP32PTR( poDS->paiTiles + i );
|
|
}
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
CPLDebug( "RMF", "List of block offsets/sizes:" );
|
|
|
|
for ( i = 0; i < poDS->sHeader.nTileTblSize / sizeof(GUInt32); i += 2 )
|
|
{
|
|
CPLDebug( "RMF", " %d / %d",
|
|
poDS->paiTiles[i], poDS->paiTiles[i + 1] );
|
|
}
|
|
#endif
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Set up essential image parameters. */
|
|
/* -------------------------------------------------------------------- */
|
|
GDALDataType eType = GDT_Byte;
|
|
|
|
poDS->nRasterXSize = poDS->sHeader.nWidth;
|
|
poDS->nRasterYSize = poDS->sHeader.nHeight;
|
|
|
|
if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
|
|
{
|
|
delete poDS;
|
|
return NULL;
|
|
}
|
|
|
|
if ( poDS->eRMFType == RMFT_RSW )
|
|
{
|
|
switch ( poDS->sHeader.nBitDepth )
|
|
{
|
|
case 32:
|
|
case 24:
|
|
case 16:
|
|
poDS->nBands = 3;
|
|
break;
|
|
case 1:
|
|
case 4:
|
|
case 8:
|
|
{
|
|
// Allocate memory for colour table and read it
|
|
poDS->nColorTableSize = 1 << poDS->sHeader.nBitDepth;
|
|
if ( poDS->nColorTableSize * 4 > poDS->sHeader.nClrTblSize )
|
|
{
|
|
CPLDebug( "RMF",
|
|
"Wrong color table size. Expected %d, got %d.",
|
|
poDS->nColorTableSize * 4,
|
|
poDS->sHeader.nClrTblSize );
|
|
delete poDS;
|
|
return NULL;
|
|
}
|
|
poDS->pabyColorTable =
|
|
(GByte *)VSIMalloc( poDS->sHeader.nClrTblSize );
|
|
if (poDS->pabyColorTable == NULL)
|
|
{
|
|
CPLDebug( "RMF", "Can't allocate color table." );
|
|
delete poDS;
|
|
return NULL;
|
|
}
|
|
if ( VSIFSeekL( poDS->fp, poDS->sHeader.nClrTblOffset,
|
|
SEEK_SET ) < 0 )
|
|
{
|
|
CPLDebug( "RMF", "Can't seek to color table location." );
|
|
delete poDS;
|
|
return NULL;
|
|
}
|
|
if ( VSIFReadL( poDS->pabyColorTable, 1,
|
|
poDS->sHeader.nClrTblSize, poDS->fp )
|
|
< poDS->sHeader.nClrTblSize )
|
|
{
|
|
CPLDebug( "RMF", "Can't read color table." );
|
|
delete poDS;
|
|
return NULL;
|
|
}
|
|
|
|
GDALColorEntry oEntry;
|
|
poDS->poColorTable = new GDALColorTable();
|
|
for( i = 0; i < poDS->nColorTableSize; i++ )
|
|
{
|
|
oEntry.c1 = poDS->pabyColorTable[i * 4]; // Red
|
|
oEntry.c2 = poDS->pabyColorTable[i * 4 + 1]; // Green
|
|
oEntry.c3 = poDS->pabyColorTable[i * 4 + 2]; // Blue
|
|
oEntry.c4 = 255; // Alpha
|
|
|
|
poDS->poColorTable->SetColorEntry( i, &oEntry );
|
|
}
|
|
}
|
|
poDS->nBands = 1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
eType = GDT_Byte;
|
|
}
|
|
else
|
|
{
|
|
poDS->nBands = 1;
|
|
if ( poDS->sHeader.nBitDepth == 8 )
|
|
eType = GDT_Byte;
|
|
else if ( poDS->sHeader.nBitDepth == 16 )
|
|
eType = GDT_Int16;
|
|
else if ( poDS->sHeader.nBitDepth == 32 )
|
|
eType = GDT_Int32;
|
|
else if ( poDS->sHeader.nBitDepth == 64 )
|
|
eType = GDT_Float64;
|
|
}
|
|
|
|
if (poDS->sHeader.nTileWidth == 0 ||
|
|
poDS->sHeader.nTileHeight == 0)
|
|
{
|
|
CPLDebug ("RMF", "Invalid tile dimension : %d x %d",
|
|
poDS->sHeader.nTileWidth, poDS->sHeader.nTileHeight);
|
|
delete poDS;
|
|
return NULL;
|
|
}
|
|
|
|
poDS->nXTiles = ( poDS->nRasterXSize + poDS->sHeader.nTileWidth - 1 ) /
|
|
poDS->sHeader.nTileWidth;
|
|
poDS->nYTiles = ( poDS->nRasterYSize + poDS->sHeader.nTileHeight - 1 ) /
|
|
poDS->sHeader.nTileHeight;
|
|
|
|
#ifdef DEBUG
|
|
CPLDebug( "RMF", "Image is %d tiles wide, %d tiles long",
|
|
poDS->nXTiles, poDS->nYTiles );
|
|
#endif
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Choose compression scheme. */
|
|
/* XXX: The DEM compression method seems to be only applicable */
|
|
/* to Int32 data. */
|
|
/* -------------------------------------------------------------------- */
|
|
if ( poDS->sHeader.iCompression == RMF_COMPRESSION_LZW )
|
|
poDS->Decompress = &LZWDecompress;
|
|
else if ( poDS->sHeader.iCompression == RMF_COMPRESSION_DEM
|
|
&& eType == GDT_Int32 )
|
|
poDS->Decompress = &DEMDecompress;
|
|
else // No compression
|
|
poDS->Decompress = NULL;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Create band information objects. */
|
|
/* -------------------------------------------------------------------- */
|
|
int iBand;
|
|
|
|
for( iBand = 1; iBand <= poDS->nBands; iBand++ )
|
|
poDS->SetBand( iBand, new RMFRasterBand( poDS, iBand, eType ) );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Set up projection. */
|
|
/* */
|
|
/* XXX: If projection value is not specified, but image still have */
|
|
/* georeferencing information, assume Gauss-Kruger projection. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( poDS->sHeader.iProjection > 0 ||
|
|
(poDS->sHeader.dfPixelSize != 0.0 &&
|
|
poDS->sHeader.dfLLX != 0.0 &&
|
|
poDS->sHeader.dfLLY != 0.0) )
|
|
{
|
|
OGRSpatialReference oSRS;
|
|
GInt32 nProj =
|
|
(poDS->sHeader.iProjection) ? poDS->sHeader.iProjection : 1L;
|
|
double padfPrjParams[8];
|
|
|
|
padfPrjParams[0] = poDS->sHeader.dfStdP1;
|
|
padfPrjParams[1] = poDS->sHeader.dfStdP2;
|
|
padfPrjParams[2] = poDS->sHeader.dfCenterLat;
|
|
padfPrjParams[3] = poDS->sHeader.dfCenterLong;
|
|
padfPrjParams[4] = 1.0;
|
|
padfPrjParams[5] = 0.0;
|
|
padfPrjParams[6] = 0.0;
|
|
|
|
// XXX: Compute zone number for Gauss-Kruger (Transverse Mercator)
|
|
// projection if it is not specified.
|
|
if ( nProj == 1L && poDS->sHeader.dfCenterLong == 0.0 )
|
|
{
|
|
if ( poDS->sExtHeader.nZone == 0 )
|
|
{
|
|
double centerXCoord = poDS->sHeader.dfLLX +
|
|
(poDS->nRasterXSize * poDS->sHeader.dfPixelSize / 2.0);
|
|
padfPrjParams[7] =
|
|
floor((centerXCoord - 500000.0 ) / 1000000.0);
|
|
}
|
|
else
|
|
padfPrjParams[7] = poDS->sExtHeader.nZone;
|
|
}
|
|
else
|
|
padfPrjParams[7] = 0.0;
|
|
|
|
oSRS.importFromPanorama( nProj, poDS->sExtHeader.nDatum,
|
|
poDS->sExtHeader.nEllipsoid, padfPrjParams );
|
|
if ( poDS->pszProjection )
|
|
CPLFree( poDS->pszProjection );
|
|
oSRS.exportToWkt( &poDS->pszProjection );
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Set up georeferencing. */
|
|
/* -------------------------------------------------------------------- */
|
|
if ( (poDS->eRMFType == RMFT_RSW && poDS->sHeader.iGeorefFlag) ||
|
|
(poDS->eRMFType == RMFT_MTW && poDS->sHeader.dfPixelSize != 0.0) )
|
|
{
|
|
poDS->adfGeoTransform[0] = poDS->sHeader.dfLLX;
|
|
poDS->adfGeoTransform[3] = poDS->sHeader.dfLLY
|
|
+ poDS->nRasterYSize * poDS->sHeader.dfPixelSize;
|
|
poDS->adfGeoTransform[1] = poDS->sHeader.dfPixelSize;
|
|
poDS->adfGeoTransform[5] = - poDS->sHeader.dfPixelSize;
|
|
poDS->adfGeoTransform[2] = 0.0;
|
|
poDS->adfGeoTransform[4] = 0.0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Set units. */
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
if ( poDS->eRMFType == RMFT_MTW )
|
|
{
|
|
CPLFree(poDS->pszUnitType);
|
|
switch ( poDS->sHeader.iElevationUnit )
|
|
{
|
|
case 0:
|
|
poDS->pszUnitType = CPLStrdup( RMF_UnitsM );
|
|
break;
|
|
case 1:
|
|
poDS->pszUnitType = CPLStrdup( RMF_UnitsCM );
|
|
break;
|
|
case 2:
|
|
poDS->pszUnitType = CPLStrdup( RMF_UnitsDM );
|
|
break;
|
|
case 3:
|
|
poDS->pszUnitType = CPLStrdup( RMF_UnitsMM );
|
|
break;
|
|
default:
|
|
poDS->pszUnitType = CPLStrdup( RMF_UnitsEmpty );
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Report some other dataset related information. */
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
if ( poDS->eRMFType == RMFT_MTW )
|
|
{
|
|
char szTemp[256];
|
|
|
|
snprintf( szTemp, sizeof(szTemp), "%g", poDS->sHeader.adfElevMinMax[0] );
|
|
poDS->SetMetadataItem( "ELEVATION_MINIMUM", szTemp );
|
|
|
|
snprintf( szTemp, sizeof(szTemp), "%g", poDS->sHeader.adfElevMinMax[1] );
|
|
poDS->SetMetadataItem( "ELEVATION_MAXIMUM", szTemp );
|
|
|
|
poDS->SetMetadataItem( "ELEVATION_UNITS", poDS->pszUnitType );
|
|
|
|
snprintf( szTemp, sizeof(szTemp), "%d", poDS->sHeader.iElevationType );
|
|
poDS->SetMetadataItem( "ELEVATION_TYPE", szTemp );
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Check for overviews. */
|
|
/* -------------------------------------------------------------------- */
|
|
poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
|
|
|
|
return( poDS );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Create() */
|
|
/************************************************************************/
|
|
|
|
GDALDataset *RMFDataset::Create( const char * pszFilename,
|
|
int nXSize, int nYSize, int nBands,
|
|
GDALDataType eType, char **papszParmList )
|
|
|
|
{
|
|
if ( nBands != 1 && nBands != 3 )
|
|
{
|
|
CPLError( CE_Failure, CPLE_NotSupported,
|
|
"RMF driver doesn't support %d bands. Must be 1 or 3.\n",
|
|
nBands );
|
|
|
|
return NULL;
|
|
}
|
|
|
|
if ( nBands == 1
|
|
&& eType != GDT_Byte
|
|
&& eType != GDT_Int16
|
|
&& eType != GDT_Int32
|
|
&& eType != GDT_Float64 )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Attempt to create RMF dataset with an illegal data type (%s),\n"
|
|
"only Byte, Int16, Int32 and Float64 types supported "
|
|
"by the format for single-band images.\n",
|
|
GDALGetDataTypeName(eType) );
|
|
|
|
return NULL;
|
|
}
|
|
|
|
if ( nBands == 3 && eType != GDT_Byte )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Attempt to create RMF dataset with an illegal data type (%s),\n"
|
|
"only Byte type supported by the format for three-band images.\n",
|
|
GDALGetDataTypeName(eType) );
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Create the dataset. */
|
|
/* -------------------------------------------------------------------- */
|
|
RMFDataset *poDS;
|
|
|
|
poDS = new RMFDataset();
|
|
|
|
poDS->fp = VSIFOpenL( pszFilename, "w+b" );
|
|
if( poDS->fp == NULL )
|
|
{
|
|
CPLError( CE_Failure, CPLE_OpenFailed, "Unable to create file %s.\n",
|
|
pszFilename );
|
|
delete poDS;
|
|
return NULL;
|
|
}
|
|
|
|
poDS->pszFilename = pszFilename;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Fill the RMFHeader */
|
|
/* -------------------------------------------------------------------- */
|
|
GUInt32 nTileSize, nCurPtr = 0;
|
|
GUInt32 nBlockXSize =
|
|
( nXSize < RMF_DEFAULT_BLOCKXSIZE ) ? nXSize : RMF_DEFAULT_BLOCKXSIZE;
|
|
GUInt32 nBlockYSize =
|
|
( nYSize < RMF_DEFAULT_BLOCKYSIZE ) ? nYSize : RMF_DEFAULT_BLOCKYSIZE;
|
|
const char *pszValue;
|
|
|
|
if ( CSLFetchBoolean( papszParmList, "MTW", FALSE) )
|
|
poDS->eRMFType = RMFT_MTW;
|
|
else
|
|
poDS->eRMFType = RMFT_RSW;
|
|
if ( poDS->eRMFType == RMFT_MTW )
|
|
memcpy( poDS->sHeader.bySignature, RMF_SigMTW, RMF_SIGNATURE_SIZE );
|
|
else
|
|
memcpy( poDS->sHeader.bySignature, RMF_SigRSW, RMF_SIGNATURE_SIZE );
|
|
poDS->sHeader.iVersion = 0x0200;
|
|
poDS->sHeader.nOvrOffset = 0x00;
|
|
poDS->sHeader.iUserID = 0x00;
|
|
memset( poDS->sHeader.byName, 0, sizeof(poDS->sHeader.byName) );
|
|
poDS->sHeader.nBitDepth = GDALGetDataTypeSize( eType ) * nBands;
|
|
poDS->sHeader.nHeight = nYSize;
|
|
poDS->sHeader.nWidth = nXSize;
|
|
|
|
pszValue = CSLFetchNameValue(papszParmList,"BLOCKXSIZE");
|
|
if( pszValue != NULL )
|
|
nBlockXSize = atoi( pszValue );
|
|
|
|
pszValue = CSLFetchNameValue(papszParmList,"BLOCKYSIZE");
|
|
if( pszValue != NULL )
|
|
nBlockYSize = atoi( pszValue );
|
|
|
|
poDS->sHeader.nTileWidth = nBlockXSize;
|
|
poDS->sHeader.nTileHeight = nBlockYSize;
|
|
|
|
poDS->nXTiles = poDS->sHeader.nXTiles =
|
|
( nXSize + poDS->sHeader.nTileWidth - 1 ) / poDS->sHeader.nTileWidth;
|
|
poDS->nYTiles = poDS->sHeader.nYTiles =
|
|
( nYSize + poDS->sHeader.nTileHeight - 1 ) / poDS->sHeader.nTileHeight;
|
|
poDS->sHeader.nLastTileHeight = nYSize % poDS->sHeader.nTileHeight;
|
|
if ( !poDS->sHeader.nLastTileHeight )
|
|
poDS->sHeader.nLastTileHeight = poDS->sHeader.nTileHeight;
|
|
poDS->sHeader.nLastTileWidth = nXSize % poDS->sHeader.nTileWidth;
|
|
if ( !poDS->sHeader.nLastTileWidth )
|
|
poDS->sHeader.nLastTileWidth = poDS->sHeader.nTileWidth;
|
|
|
|
poDS->sHeader.nROIOffset = 0x00;
|
|
poDS->sHeader.nROISize = 0x00;
|
|
|
|
nCurPtr += RMF_HEADER_SIZE;
|
|
|
|
// Extended header
|
|
poDS->sHeader.nExtHdrOffset = nCurPtr;
|
|
poDS->sHeader.nExtHdrSize = RMF_EXT_HEADER_SIZE;
|
|
nCurPtr += poDS->sHeader.nExtHdrSize;
|
|
|
|
// Color table
|
|
if ( poDS->eRMFType == RMFT_RSW && nBands == 1 )
|
|
{
|
|
GUInt32 i;
|
|
|
|
if ( poDS->sHeader.nBitDepth > 8 )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Cannot create color table of RSW with nBitDepth = %d. Retry with MTW ?",
|
|
poDS->sHeader.nBitDepth );
|
|
delete poDS;
|
|
return NULL;
|
|
}
|
|
|
|
poDS->sHeader.nClrTblOffset = nCurPtr;
|
|
poDS->nColorTableSize = 1 << poDS->sHeader.nBitDepth;
|
|
poDS->sHeader.nClrTblSize = poDS->nColorTableSize * 4;
|
|
poDS->pabyColorTable = (GByte *) VSIMalloc( poDS->sHeader.nClrTblSize );
|
|
if (poDS->pabyColorTable == NULL)
|
|
{
|
|
CPLError( CE_Failure, CPLE_OutOfMemory, "Out of memory");
|
|
delete poDS;
|
|
return NULL;
|
|
}
|
|
for ( i = 0; i < poDS->nColorTableSize; i++ )
|
|
{
|
|
poDS->pabyColorTable[i * 4] =
|
|
poDS->pabyColorTable[i * 4 + 1] =
|
|
poDS->pabyColorTable[i * 4 + 2] = (GByte) i;
|
|
poDS->pabyColorTable[i * 4 + 3] = 0;
|
|
}
|
|
nCurPtr += poDS->sHeader.nClrTblSize;
|
|
}
|
|
else
|
|
{
|
|
poDS->sHeader.nClrTblOffset = 0x00;
|
|
poDS->sHeader.nClrTblSize = 0x00;
|
|
}
|
|
|
|
// Blocks table
|
|
poDS->sHeader.nTileTblOffset = nCurPtr;
|
|
poDS->sHeader.nTileTblSize =
|
|
poDS->sHeader.nXTiles * poDS->sHeader.nYTiles * 4 * 2;
|
|
poDS->paiTiles = (GUInt32 *)CPLCalloc( poDS->sHeader.nTileTblSize, 1 );
|
|
nCurPtr += poDS->sHeader.nTileTblSize;
|
|
nTileSize = poDS->sHeader.nTileWidth * poDS->sHeader.nTileHeight
|
|
* GDALGetDataTypeSize( eType ) / 8;
|
|
poDS->sHeader.nSize =
|
|
poDS->paiTiles[poDS->sHeader.nTileTblSize / 4 - 2] + nTileSize;
|
|
|
|
// Elevation units
|
|
if ( EQUAL(poDS->pszUnitType, RMF_UnitsM) )
|
|
poDS->sHeader.iElevationUnit = 0;
|
|
else if ( EQUAL(poDS->pszUnitType, RMF_UnitsCM) )
|
|
poDS->sHeader.iElevationUnit = 1;
|
|
else if ( EQUAL(poDS->pszUnitType, RMF_UnitsDM) )
|
|
poDS->sHeader.iElevationUnit = 2;
|
|
else if ( EQUAL(poDS->pszUnitType, RMF_UnitsMM) )
|
|
poDS->sHeader.iElevationUnit = 3;
|
|
else
|
|
poDS->sHeader.iElevationUnit = 0;
|
|
|
|
poDS->sHeader.iMapType = -1;
|
|
poDS->sHeader.iProjection = -1;
|
|
poDS->sHeader.dfScale = 10000.0;
|
|
poDS->sHeader.dfResolution = 100.0;
|
|
poDS->sHeader.iCompression = 0;
|
|
poDS->sHeader.iMaskType = 0;
|
|
poDS->sHeader.iMaskStep = 0;
|
|
poDS->sHeader.iFrameFlag = 0;
|
|
poDS->sHeader.nFlagsTblOffset = 0x00;
|
|
poDS->sHeader.nFlagsTblSize = 0x00;
|
|
poDS->sHeader.nFileSize0 = 0x00;
|
|
poDS->sHeader.nFileSize1 = 0x00;
|
|
poDS->sHeader.iUnknown = 0;
|
|
poDS->sHeader.iGeorefFlag = 0;
|
|
poDS->sHeader.iInverse = 0;
|
|
memset( poDS->sHeader.abyInvisibleColors, 0,
|
|
sizeof(poDS->sHeader.abyInvisibleColors) );
|
|
poDS->sHeader.adfElevMinMax[0] = 0.0;
|
|
poDS->sHeader.adfElevMinMax[1] = 0.0;
|
|
poDS->sHeader.dfNoData = 0.0;
|
|
poDS->sHeader.iElevationType = 0;
|
|
|
|
poDS->nRasterXSize = nXSize;
|
|
poDS->nRasterYSize = nYSize;
|
|
poDS->eAccess = GA_Update;
|
|
poDS->nBands = nBands;
|
|
|
|
poDS->WriteHeader();
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Create band information objects. */
|
|
/* -------------------------------------------------------------------- */
|
|
int iBand;
|
|
|
|
for( iBand = 1; iBand <= poDS->nBands; iBand++ )
|
|
poDS->SetBand( iBand, new RMFRasterBand( poDS, iBand, eType ) );
|
|
|
|
return (GDALDataset *) poDS;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALRegister_RMF() */
|
|
/************************************************************************/
|
|
|
|
void GDALRegister_RMF()
|
|
|
|
{
|
|
GDALDriver *poDriver;
|
|
|
|
if( GDALGetDriverByName( "RMF" ) == NULL )
|
|
{
|
|
poDriver = new GDALDriver();
|
|
|
|
poDriver->SetDescription( "RMF" );
|
|
poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
|
|
poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
|
|
"Raster Matrix Format" );
|
|
poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
|
|
"frmt_rmf.html" );
|
|
poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "rsw" );
|
|
poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
|
|
"Byte Int16 Int32 Float64" );
|
|
poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
|
|
"<CreationOptionList>"
|
|
" <Option name='MTW' type='boolean' description='Create MTW DEM matrix'/>"
|
|
" <Option name='BLOCKXSIZE' type='int' description='Tile Width'/>"
|
|
" <Option name='BLOCKYSIZE' type='int' description='Tile Height'/>"
|
|
"</CreationOptionList>" );
|
|
poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
|
|
|
|
poDriver->pfnIdentify = RMFDataset::Identify;
|
|
poDriver->pfnOpen = RMFDataset::Open;
|
|
poDriver->pfnCreate = RMFDataset::Create;
|
|
|
|
GetGDALDriverManager()->RegisterDriver( poDriver );
|
|
}
|
|
}
|
|
|