mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-08-25 06:12:47 -06:00
365 lines
12 KiB
C++
365 lines
12 KiB
C++
/******************************************************************************
|
|
* $Id: pcidsktiledrasterband.cpp 17688 2009-09-25 16:01:19Z dron $
|
|
*
|
|
* Project: PCIDSK Database File
|
|
* Purpose: Implementation of PCIDSKTiledRasterBand
|
|
* Author: Frank Warmerdam <warmerdam@pobox.com>
|
|
*
|
|
******************************************************************************
|
|
* Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com>
|
|
*
|
|
* 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
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
****************************************************************************/
|
|
|
|
#include "gdal_pcidsk.h"
|
|
|
|
CPL_CVSID("$Id: pcidsktiledrasterband.cpp 17688 2009-09-25 16:01:19Z dron $");
|
|
|
|
/************************************************************************/
|
|
/* PCIDSKRasterBand() */
|
|
/************************************************************************/
|
|
|
|
PCIDSKTiledRasterBand::PCIDSKTiledRasterBand( PCIDSKDataset *poDS,
|
|
int nBand, int nImage )
|
|
|
|
{
|
|
poPDS = poDS;
|
|
this->poDS = poDS;
|
|
|
|
this->nBand = nBand;
|
|
this->nImage = nImage;
|
|
|
|
nOverviewCount = 0;
|
|
papoOverviews = NULL;
|
|
|
|
nBlocks = 0;
|
|
panBlockOffset = NULL;
|
|
|
|
if( !BuildBlockMap() )
|
|
return;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Load and parse image header. This is the image header */
|
|
/* within the tiled image data. */
|
|
/* -------------------------------------------------------------------- */
|
|
char achBData[128];
|
|
|
|
SysRead( 0, 128, achBData );
|
|
|
|
nRasterXSize = (int) CPLScanLong(achBData + 0, 8);
|
|
nRasterYSize = (int) CPLScanLong(achBData + 8, 8);
|
|
nBlockXSize = (int) CPLScanLong(achBData + 16, 8);
|
|
nBlockYSize = (int) CPLScanLong(achBData + 24, 8);
|
|
|
|
int nBPR = (nBlockXSize) ? (nRasterXSize + nBlockXSize - 1) / nBlockXSize : 0;
|
|
int nBPC = (nBlockYSize) ? (nRasterYSize + nBlockYSize - 1) / nBlockYSize : 0;
|
|
|
|
/* nBPR * nBPC * 20 must fit on an int. See BuildTileMap() */
|
|
if ( nRasterXSize <= 0 || nRasterYSize <= 0 || nBlockXSize <= 0 || nBlockYSize <= 0
|
|
|| nRasterXSize > INT_MAX - (nBlockXSize - 1)
|
|
|| nRasterYSize > INT_MAX - (nBlockYSize - 1)
|
|
|| (double)nBPR * (double)nBPC * 20 > INT_MAX )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined, "Invalid raster or block dimensions" );
|
|
nRasterXSize = 0;
|
|
nRasterYSize = 0;
|
|
nBlockXSize = 0;
|
|
nBlockYSize = 0;
|
|
}
|
|
|
|
eDataType = poPDS->PCIDSKTypeToGDAL( achBData + 32 );
|
|
|
|
szCompression[8] = '\0';
|
|
memcpy( szCompression, achBData+54, 8 );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ~PCIDSKTiledRasterBand() */
|
|
/************************************************************************/
|
|
|
|
PCIDSKTiledRasterBand::~PCIDSKTiledRasterBand()
|
|
{
|
|
FlushCache();
|
|
|
|
int i;
|
|
|
|
for( i = 0; i < nOverviewCount; i++ )
|
|
delete papoOverviews[i];
|
|
CPLFree( papoOverviews );
|
|
|
|
CPLFree( panBlockOffset );
|
|
CPLFree( panTileOffset );
|
|
CPLFree( panTileSize );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* BuildBlockMap() */
|
|
/************************************************************************/
|
|
|
|
int PCIDSKTiledRasterBand::BuildBlockMap()
|
|
|
|
{
|
|
nBlocks = 0;
|
|
panBlockOffset = NULL;
|
|
|
|
nTileCount = 0;
|
|
panTileOffset = NULL;
|
|
panTileSize = NULL;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Read the whole block map segment. */
|
|
/* -------------------------------------------------------------------- */
|
|
int nBMapSize;
|
|
char *pachBMap;
|
|
|
|
if( poPDS->nBlockMapSeg < 1 )
|
|
return FALSE;
|
|
|
|
nBMapSize = (int) poPDS->panSegSize[poPDS->nBlockMapSeg-1];
|
|
pachBMap = (char *) CPLCalloc(nBMapSize+1,1);
|
|
|
|
if( !poPDS->SegRead( poPDS->nBlockMapSeg, 0, nBMapSize, pachBMap ) )
|
|
return FALSE;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Parse the header. */
|
|
/* -------------------------------------------------------------------- */
|
|
int nMaxBlocks = (int) CPLScanLong(pachBMap + 18,8);
|
|
|
|
if( !EQUALN(pachBMap,"VERSION",7) )
|
|
return FALSE;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Build a "back link" map for this image's blocks. We need */
|
|
/* this to positively identify the first block in the chain. */
|
|
/* -------------------------------------------------------------------- */
|
|
int *panBackLink;
|
|
int i, nLastBlock = -1;
|
|
|
|
panBackLink = (int *) VSICalloc( sizeof(int), nMaxBlocks );
|
|
if ( panBackLink == NULL )
|
|
{
|
|
VSIFree( pachBMap );
|
|
VSIFree( panBackLink );
|
|
return FALSE;
|
|
}
|
|
for( i = 0; i < nMaxBlocks; i++ )
|
|
panBackLink[i] = -1;
|
|
|
|
for( i = 0; i < nMaxBlocks; i++ )
|
|
{
|
|
char *pachEntry = pachBMap + i * 28 + 512;
|
|
int nThisImage = (int) CPLScanLong(pachEntry + 12,8);
|
|
int nNextBlock = (int) CPLScanLong(pachEntry + 20,8);
|
|
|
|
if ( nThisImage != nImage || nNextBlock >= nMaxBlocks )
|
|
continue;
|
|
|
|
if( nNextBlock == -1 )
|
|
nLastBlock = i;
|
|
else
|
|
panBackLink[nNextBlock] = i;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Track back through chain to identify the first entry (while */
|
|
/* counting). */
|
|
/* -------------------------------------------------------------------- */
|
|
int iBlock = nLastBlock;
|
|
|
|
nBlocks = 1;
|
|
while( panBackLink[iBlock] != -1 )
|
|
{
|
|
nBlocks++;
|
|
iBlock = panBackLink[iBlock];
|
|
}
|
|
|
|
CPLFree( panBackLink );
|
|
panBlockOffset = (vsi_l_offset *) VSIMalloc(sizeof(vsi_l_offset)*nBlocks);
|
|
if ( panBlockOffset == NULL )
|
|
{
|
|
CPLFree( pachBMap );
|
|
return FALSE;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Process blocks, transforming to absolute offsets in the */
|
|
/* PCIDSK file. */
|
|
/* -------------------------------------------------------------------- */
|
|
for( i = 0; i < nBlocks; i++ )
|
|
{
|
|
char *pachEntry = pachBMap + iBlock * 28 + 512;
|
|
int nBDataSeg = CPLScanLong( pachEntry + 0, 4 );
|
|
int nBDataBlock = CPLScanLong( pachEntry + 4, 8 );
|
|
|
|
if ( nBDataSeg <= 0 || nBDataSeg > poPDS->nSegCount
|
|
|| poPDS->panSegType[nBDataSeg-1] != 182)
|
|
{
|
|
CPLFree( pachBMap );
|
|
return FALSE;
|
|
}
|
|
|
|
panBlockOffset[i] =
|
|
((vsi_l_offset) nBDataBlock) * 8192
|
|
+ poPDS->panSegOffset[nBDataSeg-1] + 1024;
|
|
|
|
iBlock = (int) CPLScanLong( pachEntry + 20, 8 );
|
|
}
|
|
|
|
CPLFree( pachBMap );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* BuildTileMap() */
|
|
/************************************************************************/
|
|
|
|
int PCIDSKTiledRasterBand::BuildTileMap()
|
|
|
|
{
|
|
if ( nTileCount < 0 )
|
|
return FALSE;
|
|
if( nTileCount > 0)
|
|
return TRUE;
|
|
|
|
int nBPR = (nRasterXSize + nBlockXSize - 1) / nBlockXSize;
|
|
int nBPC = (nRasterYSize + nBlockYSize - 1) / nBlockYSize;
|
|
|
|
nTileCount = nBPR * nBPC;
|
|
panTileOffset = (vsi_l_offset *)
|
|
VSICalloc( sizeof(vsi_l_offset), nTileCount );
|
|
panTileSize = (int *) VSICalloc( sizeof(int), nTileCount );
|
|
|
|
char *pachTileInfo = (char *) VSIMalloc( 20 * nTileCount );
|
|
if ( panTileOffset == NULL || panTileSize == NULL || pachTileInfo == NULL )
|
|
{
|
|
CPLError( CE_Failure, CPLE_OutOfMemory, "Out of memory" );
|
|
nTileCount = -1;
|
|
CPLFree( pachTileInfo );
|
|
return FALSE;
|
|
}
|
|
|
|
if( !SysRead( 128, 20 * nTileCount, pachTileInfo ) )
|
|
{
|
|
nTileCount = -1;
|
|
CPLFree( pachTileInfo );
|
|
return FALSE;
|
|
}
|
|
|
|
for( int iTile = 0; iTile < nTileCount; iTile++ )
|
|
{
|
|
panTileOffset[iTile] = (vsi_l_offset)
|
|
CPLScanUIntBig( pachTileInfo+12*iTile, 12 );
|
|
panTileSize[iTile] = (int)
|
|
CPLScanLong( pachTileInfo+12*nTileCount+8*iTile, 8 );
|
|
}
|
|
|
|
CPLFree( pachTileInfo );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* IReadBlock() */
|
|
/************************************************************************/
|
|
|
|
CPLErr PCIDSKTiledRasterBand::IReadBlock( int nBlockX, int nBlockY,
|
|
void *pData )
|
|
|
|
{
|
|
int iTile;
|
|
|
|
if( !EQUALN(szCompression,"NONE",4) )
|
|
{
|
|
CPLError( CE_Failure, CPLE_NotSupported,
|
|
"Compression '%s' not supported by GDAL.",
|
|
szCompression );
|
|
return CE_Failure;
|
|
}
|
|
|
|
if( !BuildTileMap() )
|
|
return CE_Failure;
|
|
|
|
int nBPR = (nRasterXSize + nBlockXSize - 1) / nBlockXSize;
|
|
|
|
iTile = nBlockX + nBlockY * nBPR;
|
|
|
|
if( panTileOffset[iTile] == (vsi_l_offset) -1 )
|
|
{
|
|
int nWordSize = GDALGetDataTypeSize( eDataType ) / 8;
|
|
memset( pData, 0, nBlockXSize*nBlockYSize*nWordSize );
|
|
}
|
|
else
|
|
{
|
|
if( !SysRead( panTileOffset[iTile], panTileSize[iTile], pData ) )
|
|
return CE_Failure;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* PCIDSK multibyte data is always big endian. Swap if needed. */
|
|
/* -------------------------------------------------------------------- */
|
|
#ifdef CPL_LSB
|
|
int nWordSize = GDALGetDataTypeSize( eDataType ) / 8;
|
|
GDALSwapWords( pData, nWordSize, nBlockXSize * nBlockYSize, nWordSize );
|
|
#endif
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SysRead() */
|
|
/************************************************************************/
|
|
|
|
int PCIDSKTiledRasterBand::SysRead( vsi_l_offset nOffset,
|
|
int nSize,
|
|
void *pData )
|
|
|
|
{
|
|
int iReadSoFar = 0;
|
|
|
|
while( iReadSoFar < nSize )
|
|
{
|
|
int iBlock;
|
|
vsi_l_offset nNextOffset = nOffset + iReadSoFar;
|
|
vsi_l_offset nRealOffset;
|
|
int nOffsetInBlock, nThisReadBytes;
|
|
|
|
iBlock = (int) (nNextOffset >> 13);
|
|
nOffsetInBlock = (int) (nNextOffset & 0x1fff);
|
|
|
|
if ( iBlock >= nBlocks )
|
|
return 0;
|
|
|
|
nRealOffset = panBlockOffset[iBlock] + nOffsetInBlock;
|
|
|
|
nThisReadBytes = MIN(nSize - iReadSoFar,8192 - nOffsetInBlock);
|
|
|
|
if( VSIFSeekL( poPDS->fp, nRealOffset, SEEK_SET ) != 0 )
|
|
return 0;
|
|
|
|
if( VSIFReadL( ((char *) pData) + iReadSoFar, 1, nThisReadBytes,
|
|
poPDS->fp ) != (size_t) nThisReadBytes )
|
|
return 0;
|
|
|
|
iReadSoFar += nThisReadBytes;
|
|
}
|
|
|
|
return nSize;
|
|
}
|