ultimatepp/bazaar/plugin/gdal/frmts/pcidsk/pcidskdataset.cpp
cxl 23ff1e7e82 .gdal moved to bazaar
git-svn-id: svn://ultimatepp.org/upp/trunk@9273 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2015-12-07 13:36:24 +00:00

1644 lines
66 KiB
C++

/******************************************************************************
* $Id: pcidskdataset.cpp 28373 2015-01-30 00:14:24Z rouault $
*
* Project: PCIDSK Database File
* Purpose: Read/write PCIDSK Database File used by the PCI software
* Author: Andrey Kiselev, dron@ak4719.spb.edu
*
******************************************************************************
* Copyright (c) 2003, Andrey Kiselev <dron@ak4719.spb.edu>
* Copyright (c) 2009-2010, 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
* 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: pcidskdataset.cpp 28373 2015-01-30 00:14:24Z rouault $");
CPL_C_START
void GDALRegister_PCIDSK(void);
CPL_C_END
const int nSegBlocks = 64; // Number of blocks of Segment Pointers
const int nGeoSegBlocks = 8; // Number of blocks in GEO Segment
/************************************************************************/
/* PCIDSKDataset() */
/************************************************************************/
PCIDSKDataset::PCIDSKDataset()
{
pszFilename = NULL;
fp = NULL;
nFileSize = 0;
nBands = 0;
pszCreatTime = NULL;
nGeoOffset = 0;
bGeoSegmentDirty = FALSE;
nBlockMapSeg = 0;
nSegCount = 0;
panSegType = NULL;
papszSegName = NULL;
panSegOffset = NULL;
panSegSize = NULL;
pszProjection = CPLStrdup( "" );
pszGCPProjection = CPLStrdup( "" );
nGCPCount = 0;
pasGCPList = NULL;
adfGeoTransform[0] = 0.0;
adfGeoTransform[1] = 1.0;
adfGeoTransform[2] = 0.0;
adfGeoTransform[3] = 0.0;
adfGeoTransform[4] = 0.0;
adfGeoTransform[5] = 1.0;
bGeoTransformValid = FALSE;
nBandFileCount = 0;
pafpBandFiles = NULL;
}
/************************************************************************/
/* ~PCIDSKDataset() */
/************************************************************************/
PCIDSKDataset::~PCIDSKDataset()
{
int i;
FlushCache();
if ( pszProjection )
CPLFree( pszProjection );
if ( pszGCPProjection )
CPLFree( pszGCPProjection );
if( fp != NULL )
VSIFCloseL( fp );
if( pszCreatTime )
CPLFree( pszCreatTime );
if( nGCPCount > 0 )
{
GDALDeinitGCPs( nGCPCount, pasGCPList );
CPLFree( pasGCPList );
}
CPLFree( panSegOffset );
CPLFree( panSegSize );
CPLFree( panSegType );
for( i = 0; i < nSegCount; i++ )
if( papszSegName[i] != NULL )
CPLFree( papszSegName[i] );
CPLFree( papszSegName );
for( i = 0; i < nBandFileCount; i++ )
VSIFCloseL( pafpBandFiles[i] );
CPLFree( pafpBandFiles );
}
/************************************************************************/
/* GetGeoTransform() */
/************************************************************************/
CPLErr PCIDSKDataset::GetGeoTransform( double * padfTransform )
{
if( !bGeoTransformValid )
return GDALPamDataset::GetGeoTransform( padfTransform );
else
{
memcpy( padfTransform, adfGeoTransform, sizeof(adfGeoTransform[0])*6 );
return CE_None;
}
}
/************************************************************************/
/* SetGeoTransform() */
/************************************************************************/
CPLErr PCIDSKDataset::SetGeoTransform( double * padfTransform )
{
memcpy( adfGeoTransform, padfTransform, sizeof(double) * 6 );
bGeoSegmentDirty = TRUE;
bGeoTransformValid = TRUE;
return CE_None;
}
/************************************************************************/
/* GetProjectionRef() */
/************************************************************************/
const char *PCIDSKDataset::GetProjectionRef()
{
if( pszProjection )
return pszProjection;
else
return GDALPamDataset::GetProjectionRef();
}
/************************************************************************/
/* SetProjection() */
/************************************************************************/
CPLErr PCIDSKDataset::SetProjection( const char *pszNewProjection )
{
if( pszProjection )
CPLFree( pszProjection );
pszProjection = CPLStrdup( pszNewProjection );
bGeoSegmentDirty = TRUE;
return CE_None;
}
/************************************************************************/
/* GetGCPCount() */
/************************************************************************/
int PCIDSKDataset::GetGCPCount()
{
return nGCPCount;
}
/************************************************************************/
/* GetGCPProjection() */
/************************************************************************/
const char *PCIDSKDataset::GetGCPProjection()
{
if( nGCPCount > 0 )
return pszGCPProjection;
else
return GDALPamDataset::GetGCPProjection();
}
/************************************************************************/
/* GetGCPs() */
/************************************************************************/
const GDAL_GCP *PCIDSKDataset::GetGCPs()
{
return pasGCPList;
}
/************************************************************************/
/* FlushCache() */
/************************************************************************/
void PCIDSKDataset::FlushCache()
{
GDALPamDataset::FlushCache();
if( GetAccess() == GA_Update )
{
char szTemp[64];
/* -------------------------------------------------------------------- */
/* Write out pixel size. */
/* -------------------------------------------------------------------- */
CPLPrintDouble( szTemp, "%16.9E", ABS(adfGeoTransform[1]), "C" );
CPLPrintDouble( szTemp + 16, "%16.9E", ABS(adfGeoTransform[5]), "C" );
VSIFSeekL( fp, 408, SEEK_SET );
VSIFWriteL( (void *)szTemp, 1, 32, fp );
/* -------------------------------------------------------------------- */
/* Write out Georeferencing segment. */
/* -------------------------------------------------------------------- */
if ( nGeoOffset && bGeoSegmentDirty )
{
WriteGeoSegment();
bGeoSegmentDirty = FALSE;
}
}
}
/************************************************************************/
/* WriteGeoSegment() */
/************************************************************************/
void PCIDSKDataset::WriteGeoSegment( )
{
char szTemp[3072];
struct tm oUpdateTime;
time_t nTime = VSITime(NULL);
char *pszP = pszProjection;
OGRSpatialReference oSRS;
int i;
#ifdef DEBUG
CPLDebug( "PCIDSK", "Writing out georeferencing segment." );
#endif
VSILocalTime( &nTime, &oUpdateTime );
CPLPrintStringFill( szTemp, "Master Georeferencing Segment for File", 64 );
CPLPrintStringFill( szTemp + 64, "", 64 );
if ( pszCreatTime )
CPLPrintStringFill( szTemp + 128, pszCreatTime, 16 );
else
CPLPrintTime( szTemp + 128, 16, "%H:%M %d-%b-%y ", &oUpdateTime, "C" );
CPLPrintTime( szTemp + 144, 16, "%H:%M %d-%b-%y ", &oUpdateTime, "C" );
CPLPrintStringFill( szTemp + 160, "", 224 );
// Write the history line
CPLPrintStringFill( szTemp + 384,
"GDAL: Master Georeferencing Segment for File", 64 );
CPLPrintTime( szTemp + 448, 16, "%H:%M %d-%b-%y ", &oUpdateTime, "C" );
// Fill other lines with spaces
CPLPrintStringFill( szTemp + 464, "", 80 * 7 );
// More history lines may be used, if needed.
// CPLPrintStringFill( szTemp + 464, "History2", 80 );
// CPLPrintStringFill( szTemp + 544, "History3", 80 );
// CPLPrintStringFill( szTemp + 624, "History4", 80 );
// CPLPrintStringFill( szTemp + 704, "History5", 80 );
// CPLPrintStringFill( szTemp + 784, "History6", 80 );
// CPLPrintStringFill( szTemp + 864, "History7", 80 );
// CPLPrintStringFill( szTemp + 944, "History8", 80 );
VSIFSeekL( fp, nGeoOffset, SEEK_SET );
VSIFWriteL( (void *)szTemp, 1, 1024, fp );
CPLPrintStringFill( szTemp, "PROJECTION", 16 );
CPLPrintStringFill( szTemp + 16, "PIXEL", 16 );
if( pszProjection != NULL && !EQUAL( pszProjection, "" )
&& oSRS.importFromWkt( &pszP ) == OGRERR_NONE )
{
char *pszProj = NULL;
char *pszUnits = NULL;
double *padfPrjParms = NULL;
oSRS.exportToPCI( &pszProj, &pszUnits, &padfPrjParms );
CPLPrintStringFill( szTemp + 32, pszProj, 16 );
CPLPrintInt32( szTemp + 48, 3, 8 );
CPLPrintInt32( szTemp + 56, 3, 8 );
CPLPrintStringFill( szTemp + 64, pszUnits, 16 );
for ( i = 0; i < 17; i++ )
{
CPLPrintDouble( szTemp + 80 + 26 * i,
"%26.18E", padfPrjParms[i], "C" );
}
CPLPrintStringFill( szTemp + 522, "", 936 );
if ( pszProj )
CPLFree( pszProj );
if ( pszUnits )
CPLFree(pszUnits );
if ( padfPrjParms )
CPLFree( padfPrjParms );
}
else
{
if( adfGeoTransform[0] == 0.0
&& adfGeoTransform[1] == 1.0
&& adfGeoTransform[2] == 0.0
&& adfGeoTransform[3] == 0.0
&& adfGeoTransform[4] == 0.0
&& ABS(adfGeoTransform[5]) == 1.0 )
{
// no georeferencing at all.
CPLPrintStringFill( szTemp + 32, "PIXEL", 16 );
}
else
{
// georeferenced but not a known coordinate system.
CPLPrintStringFill( szTemp + 32, "METER", 16 );
}
CPLPrintInt32( szTemp + 48, 3, 8 );
CPLPrintInt32( szTemp + 56, 3, 8 );
CPLPrintStringFill( szTemp + 64, "METER", 16 );
CPLPrintStringFill( szTemp + 80, "", 1378 );
}
/* TODO: USGS format */
CPLPrintStringFill( szTemp + 1458, "", 1614 );
for ( i = 0; i < 3; i++ )
{
CPLPrintDouble( szTemp + 1980 + 26 * i,
"%26.18E", adfGeoTransform[i], "C" );
}
for ( i = 0; i < 3; i++ )
{
CPLPrintDouble( szTemp + 2526 + 26 * i,
"%26.18E", adfGeoTransform[i + 3], "C" );
}
VSIFWriteL( (void *)szTemp, 1, 3072, fp );
// Now make the segment active
szTemp[0] = 'A';
VSIFSeekL( fp, nGeoPtrOffset, SEEK_SET );
VSIFWriteL( (void *)szTemp, 1, 1, fp );
}
/************************************************************************/
/* PCIDSKTypeToGDAL() */
/************************************************************************/
GDALDataType PCIDSKDataset::PCIDSKTypeToGDAL( const char *pszType )
{
if ( EQUALN( pszType, "8U", 2 ) )
return GDT_Byte;
if ( EQUALN( pszType, "16S", 3 ) )
return GDT_Int16;
if ( EQUALN( pszType, "16U", 3 ) )
return GDT_UInt16;
if ( EQUALN( pszType, "32R", 3 ) )
return GDT_Float32;
return GDT_Unknown;
}
/************************************************************************/
/* Identify() */
/************************************************************************/
int PCIDSKDataset::Identify( GDALOpenInfo * poOpenInfo )
{
if( poOpenInfo->nHeaderBytes < 512
|| !EQUALN((const char *) poOpenInfo->pabyHeader, "PCIDSK ", 8) )
return FALSE;
else
return TRUE;
}
/************************************************************************/
/* Open() */
/************************************************************************/
GDALDataset *PCIDSKDataset::Open( GDALOpenInfo * poOpenInfo )
{
if( !Identify( poOpenInfo ) )
return NULL;
/* -------------------------------------------------------------------- */
/* Create a corresponding GDALDataset. */
/* -------------------------------------------------------------------- */
PCIDSKDataset *poDS;
poDS = new PCIDSKDataset();
if( poOpenInfo->eAccess == GA_ReadOnly )
poDS->fp = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
else
poDS->fp = VSIFOpenL( poOpenInfo->pszFilename, "r+b" );
if ( !poDS->fp )
{
CPLError( CE_Failure, CPLE_OpenFailed,
"Failed to re-open %s within PCIDSK driver.\n",
poOpenInfo->pszFilename );
delete poDS;
return NULL;
}
poDS->eAccess = poOpenInfo->eAccess;
/* ==================================================================== */
/* Read PCIDSK File Header. */
/* ==================================================================== */
char szTemp[1024];
char *pszString;
VSIFSeekL( poDS->fp, 0, SEEK_END );
poDS->nFileSize = VSIFTellL( poDS->fp );
/* -------------------------------------------------------------------- */
/* Read File Identification. */
/* -------------------------------------------------------------------- */
VSIFSeekL( poDS->fp, 0, SEEK_SET );
VSIFReadL( szTemp, 1, 512, poDS->fp );
pszString = CPLScanString( szTemp + 8, 8, TRUE, TRUE );
poDS->SetMetadataItem( "SOFTWARE", pszString );
CPLFree( pszString );
pszString = CPLScanString( szTemp + 48, 64, TRUE, TRUE );
poDS->SetMetadataItem( "FILE_ID", pszString );
CPLFree( pszString );
pszString = CPLScanString( szTemp + 112, 32, TRUE, TRUE );
poDS->SetMetadataItem( "GENERATING_FACILITY", pszString );
CPLFree( pszString );
pszString = CPLScanString( szTemp + 144, 64, TRUE, TRUE );
poDS->SetMetadataItem( "DESCRIPTION1", pszString );
CPLFree( pszString );
pszString = CPLScanString( szTemp + 208, 64, TRUE, TRUE );
poDS->SetMetadataItem( "DESCRIPTION2", pszString );
CPLFree( pszString );
pszString = CPLScanString( szTemp + 272, 16, TRUE, TRUE );
poDS->SetMetadataItem( "DATE_OF_CREATION", pszString );
CPLFree( pszString );
// Store original creation time string for later use
poDS->pszCreatTime = CPLScanString( szTemp + 272, 16, TRUE, FALSE );
pszString = CPLScanString( szTemp + 288, 16, TRUE, TRUE );
poDS->SetMetadataItem( "DATE_OF_UPDATE", pszString );
CPLFree( pszString );
/* ==================================================================== */
/* Read Segment Pointers. */
/* ==================================================================== */
vsi_l_offset nSegPointersStart; // Start block of Segment Pointers
vsi_l_offset nSegPointersOffset; // Offset in bytes to Pointers
int nSegBlocks; // Number of blocks of Segment Pointers
{
VSIFSeekL( poDS->fp, 440, SEEK_SET );
VSIFReadL( szTemp, 1, 16, poDS->fp );
szTemp[16] = '\0';
nSegPointersStart = atol( szTemp ); // XXX: should be atoll()
nSegPointersOffset = ( nSegPointersStart - 1 ) * 512;
VSIFSeekL( poDS->fp, 456, SEEK_SET );
VSIFReadL( szTemp, 1, 8, poDS->fp );
nSegBlocks = CPLScanLong( szTemp, 8 );
poDS->nSegCount = ( nSegBlocks * 512 ) / 32;
if ( poDS->nSegCount < 0 ||
nSegPointersOffset + poDS->nSegCount * 32 >= poDS->nFileSize )
{
CPLDebug("PCIDSK", "nSegCount=%d", poDS->nSegCount);
delete poDS;
return NULL;
}
/* -------------------------------------------------------------------- */
/* Allocate segment info structures. */
/* -------------------------------------------------------------------- */
poDS->panSegType =
(int *) VSICalloc( sizeof(int), poDS->nSegCount );
poDS->papszSegName =
(char **) VSICalloc( sizeof(char*), poDS->nSegCount );
poDS->panSegOffset = (vsi_l_offset *)
VSICalloc( sizeof(vsi_l_offset), poDS->nSegCount );
poDS->panSegSize = (vsi_l_offset *)
VSICalloc( sizeof(vsi_l_offset), poDS->nSegCount );
if (poDS->panSegType == NULL ||
poDS->papszSegName == NULL ||
poDS->panSegOffset == NULL ||
poDS->panSegSize == NULL)
{
CPLError( CE_Failure, CPLE_OutOfMemory,
"Not enough memory to hold segment description of %s",
poOpenInfo->pszFilename );
delete poDS;
return NULL;
}
/* -------------------------------------------------------------------- */
/* Parse each segment pointer. */
/* -------------------------------------------------------------------- */
int iSeg;
for( iSeg = 0; iSeg < poDS->nSegCount; iSeg++ )
{
int bActive, nSegStartBlock, nSegSize;
char szSegName[9];
VSIFSeekL( poDS->fp, nSegPointersOffset + iSeg * 32, SEEK_SET );
if (VSIFReadL( szTemp, 1, 32, poDS->fp ) != 32)
{
delete poDS;
return NULL;
}
szTemp[32] = '\0';
strncpy( szSegName, szTemp+4, 8 );
szSegName[8] = '\0';
if ( szTemp[0] == 'A' || szTemp[0] == 'L' )
bActive = TRUE;
else
bActive = FALSE;
if( !bActive )
continue;
poDS->panSegType[iSeg] = CPLScanLong( szTemp + 1, 3 );
nSegStartBlock = CPLScanLong( szTemp+12, 11 );
nSegSize = CPLScanLong( szTemp+23, 9 );
poDS->papszSegName[iSeg] = CPLStrdup( szSegName );
poDS->panSegOffset[iSeg] = 512 * ((vsi_l_offset) (nSegStartBlock-1));
poDS->panSegSize[iSeg] = 512 * ((vsi_l_offset) nSegSize);
CPLDebug( "PCIDSK",
"Seg=%d, Type=%d, Start=%9d, Size=%7d, Name=%s",
iSeg+1, poDS->panSegType[iSeg],
nSegStartBlock, nSegSize, szSegName );
// Some segments will be needed sooner, rather than later.
if( poDS->panSegType[iSeg] == 182 && EQUAL(szSegName,"SysBMDir"))
poDS->nBlockMapSeg = iSeg+1;
}
}
/* -------------------------------------------------------------------- */
/* Read Image Data. */
/* -------------------------------------------------------------------- */
vsi_l_offset nImageStart; // Start block of image data
vsi_l_offset nImgHdrsStart; // Start block of image headers
vsi_l_offset nImageOffset; // Offset to the first byte of the image
int nByteBands, nInt16Bands, nUInt16Bands, nFloat32Bands;
pszString = CPLScanString( szTemp + 304, 16, TRUE, FALSE );
if ( !EQUAL( pszString, "" ) )
nImageStart = atol( pszString );// XXX: should be atoll()
else
nImageStart = 1;
CPLFree( pszString );
nImageOffset = (nImageStart - 1) * 512;
pszString = CPLScanString( szTemp + 336, 16, TRUE, FALSE );
nImgHdrsStart = atol( pszString ); // XXX: should be atoll()
CPLFree( pszString );
poDS->nBands = CPLScanLong( szTemp + 376, 8 );
poDS->nRasterXSize = CPLScanLong( szTemp + 384, 8 );
poDS->nRasterYSize = CPLScanLong( szTemp + 392, 8 );
if ( poDS->nRasterXSize <= 0 || poDS->nRasterYSize <= 0 )
{
CPLError( CE_Failure, CPLE_AppDefined,
"Invalid dimensions : %d x %d",
poDS->nRasterXSize, poDS->nRasterYSize );
delete poDS;
return NULL;
}
nByteBands = CPLScanLong( szTemp + 464, 4 );
nInt16Bands = CPLScanLong( szTemp + 468, 4 );
nUInt16Bands = CPLScanLong( szTemp + 472, 4 );
nFloat32Bands = CPLScanLong( szTemp + 476, 4 );
// If these fields are blank, then it is assumed that all channels are 8-bit
if ( nByteBands == 0 && nInt16Bands == 0
&& nUInt16Bands == 0 && nFloat32Bands == 0 )
nByteBands = poDS->nBands;
/* ==================================================================== */
/* Read Image Headers and create band information objects. */
/* ==================================================================== */
int iBand;
PCIDSKInterleaving eInterleaving;
/* -------------------------------------------------------------------- */
/* Read type of interleaving and set up image parameters. */
/* -------------------------------------------------------------------- */
pszString = CPLScanString( szTemp + 360, 8, TRUE, FALSE );
if ( EQUALN( pszString, "PIXEL", 5 ) )
eInterleaving = PDI_PIXEL;
else if ( EQUALN( pszString, "BAND", 4 ) )
eInterleaving = PDI_BAND;
else if ( EQUALN( pszString, "FILE", 4 ) )
eInterleaving = PDI_FILE;
else
{
CPLDebug( "PCIDSK",
"PCIDSK interleaving type %s is not supported by GDAL",
pszString );
delete poDS;
return NULL;
}
CPLFree( pszString );
for( iBand = 0; iBand < poDS->nBands; iBand++ )
{
GDALDataType eType;
GDALRasterBand *poBand = NULL;
vsi_l_offset nImgHdrOffset = (nImgHdrsStart - 1 + iBand * 2) * 512;
vsi_l_offset nPixelOffset = 0, nLineOffset = 0, nLineSize = 0;
int bNativeOrder;
int i;
VSILFILE *fp = poDS->fp;
VSIFSeekL( poDS->fp, nImgHdrOffset, SEEK_SET );
if ( VSIFReadL( szTemp, 1, 1024, poDS->fp ) != 1024 )
{
delete poDS;
return NULL;
}
pszString = CPLScanString( szTemp + 160, 8, TRUE, FALSE );
eType = poDS->PCIDSKTypeToGDAL( pszString );
// Old files computed type based on list.
if( eType == GDT_Unknown && pszString[0] == '\0' )
{
if( iBand < nByteBands )
eType = GDT_Byte;
else if( iBand < nByteBands + nInt16Bands )
eType = GDT_Int16;
else if( iBand < nByteBands + nInt16Bands + nUInt16Bands )
eType = GDT_UInt16;
else if( iBand < nByteBands + nInt16Bands + nUInt16Bands
+ nFloat32Bands )
eType = GDT_Float32;
}
if ( eType == GDT_Unknown )
{
CPLDebug( "PCIDSK",
"PCIDSK data type %s is not supported by GDAL",
pszString );
delete poDS;
return NULL;
}
CPLFree( pszString );
switch ( eInterleaving )
{
case PDI_PIXEL:
nPixelOffset = nByteBands + 2 * (nInt16Bands + nUInt16Bands)
+ 4 * nFloat32Bands;
nLineSize = nPixelOffset * poDS->nRasterXSize;
nLineOffset = ((int)((nLineSize + 511)/512)) * 512;
break;
case PDI_BAND:
nPixelOffset = GDALGetDataTypeSize( eType ) / 8;
nLineOffset = nPixelOffset * poDS->nRasterXSize;
break;
case PDI_FILE:
{
char *pszFilename;
// Read the filename
pszFilename = CPLScanString( szTemp + 64, 64, TRUE, FALSE );
// /SIS=n is special case for internal tiled file.
if( EQUALN(pszFilename,"/SIS=",5) )
{
int nImage = atoi(pszFilename+5);
poBand = new PCIDSKTiledRasterBand( poDS, iBand+1, nImage );
if ( poBand->GetXSize() == 0 )
{
CPLFree( pszFilename );
delete poBand;
delete poDS;
return NULL;
}
}
// Non-empty filename means we have data stored in
// external raw file
else if ( !EQUAL(pszFilename, "") )
{
CPLDebug( "PCIDSK", "pszFilename=%s", pszFilename );
if( poOpenInfo->eAccess == GA_ReadOnly )
fp = VSIFOpenL( pszFilename, "rb" );
else
fp = VSIFOpenL( pszFilename, "r+b" );
if ( !fp )
{
CPLDebug( "PCIDSK",
"Cannot open external raw file %s",
pszFilename );
iBand--;
poDS->nBands--;
CPLFree( pszFilename );
continue;
}
poDS->nBandFileCount++;
poDS->pafpBandFiles = (VSILFILE **)
CPLRealloc( poDS->pafpBandFiles,
poDS->nBandFileCount * sizeof(VSILFILE*) );
poDS->pafpBandFiles[poDS->nBandFileCount-1] = fp;
}
pszString = CPLScanString( szTemp + 168, 16, TRUE, FALSE );
nImageOffset = atol( pszString ); // XXX: should be atoll()
CPLFree( pszString );
nPixelOffset = CPLScanLong( szTemp + 184, 8 );
nLineOffset = CPLScanLong( szTemp + + 192, 8 );
CPLFree( pszFilename );
}
break;
default: /* NOTREACHED */
break;
}
/* -------------------------------------------------------------------- */
/* Create raw band, only if we didn't already get a tiled band. */
/* -------------------------------------------------------------------- */
if( poBand == NULL )
{
#ifdef CPL_MSB
bNativeOrder = ( szTemp[201] == 'S')?FALSE:TRUE;
#else
bNativeOrder = ( szTemp[201] == 'S')?TRUE:FALSE;
#endif
#ifdef DEBUG
CPLDebug( "PCIDSK",
"Band %d: nImageOffset=" CPL_FRMT_GIB ", nPixelOffset=" CPL_FRMT_GIB ", "
"nLineOffset=" CPL_FRMT_GIB ", nLineSize=" CPL_FRMT_GIB,
iBand + 1, (GIntBig)nImageOffset, (GIntBig)nPixelOffset,
(GIntBig)nLineOffset, (GIntBig)nLineSize );
#endif
poBand = new PCIDSKRawRasterBand( poDS, iBand + 1, fp,
nImageOffset,
(int) nPixelOffset,
(int) nLineOffset,
eType, bNativeOrder);
switch ( eInterleaving )
{
case PDI_PIXEL:
nImageOffset += GDALGetDataTypeSize( eType ) / 8;
break;
case PDI_BAND:
nImageOffset += nLineOffset * poDS->nRasterYSize;
break;
default:
break;
}
}
poDS->SetBand( iBand + 1, poBand );
/* -------------------------------------------------------------------- */
/* Read and assign few metadata parameters to each image band. */
/* -------------------------------------------------------------------- */
pszString = CPLScanString( szTemp, 64, TRUE, TRUE );
poBand->SetDescription( pszString );
CPLFree( pszString );
pszString = CPLScanString( szTemp + 128, 16, TRUE, TRUE );
poBand->SetMetadataItem( "DATE_OF_CREATION", pszString );
CPLFree( pszString );
pszString = CPLScanString( szTemp + 144, 16, TRUE, TRUE );
poBand->SetMetadataItem( "DATE_OF_UPDATE", pszString );
CPLFree( pszString );
pszString = CPLScanString( szTemp + 202, 16, TRUE, TRUE );
if ( !EQUAL( szTemp, "" ) )
poBand->SetMetadataItem( "UNITS", pszString );
CPLFree( pszString );
for ( i = 0; i < 8; i++ )
{
pszString = CPLScanString( szTemp + 384 + i * 80, 80, TRUE, TRUE );
if ( !EQUAL( pszString, "" ) )
poBand->SetMetadataItem( CPLSPrintf("HISTORY%d", i + 1),
pszString );
CPLFree( pszString );
}
}
if (!poDS->GetRasterCount())
CPLError(CE_Warning, CPLE_None, "Dataset contain no raster bands.");
/* ==================================================================== */
/* Process some segments of interest. */
/* ==================================================================== */
int iSeg;
for( iSeg = 0; iSeg < poDS->nSegCount; iSeg++ )
{
switch( poDS->panSegType[iSeg] )
{
/* -------------------------------------------------------------------- */
/* Georeferencing segment. */
/* -------------------------------------------------------------------- */
case 150: // GEO segment
{
vsi_l_offset nGeoDataOffset;
int j, nXCoeffs, nYCoeffs;
OGRSpatialReference oSRS;
poDS->nGeoPtrOffset = nSegPointersOffset + iSeg * 32;
poDS->nGeoOffset = poDS->panSegOffset[iSeg];
nGeoDataOffset = poDS->nGeoOffset + 1024;
VSIFSeekL( poDS->fp, nGeoDataOffset, SEEK_SET );
VSIFReadL( szTemp, 1, 16, poDS->fp );
szTemp[16] = '\0';
if ( EQUALN( szTemp, "POLYNOMIAL", 10 ) )
{
char szProj[17];
// Read projection definition
VSIFSeekL( poDS->fp, nGeoDataOffset + 32, SEEK_SET );
VSIFReadL( szProj, 1, 16, poDS->fp );
szProj[16] = '\0';
if ( EQUALN( szProj, "PIXEL", 5 ) )
break;
// Read number of transform coefficients
VSIFSeekL( poDS->fp, nGeoDataOffset + 48, SEEK_SET );
VSIFReadL( szTemp, 1, 16, poDS->fp );
nXCoeffs = CPLScanLong( szTemp, 8 );
if ( nXCoeffs > 3 )
nXCoeffs = 3;
nYCoeffs = CPLScanLong( szTemp + 8, 8 );
if ( nYCoeffs > 3 )
nYCoeffs = 3;
// Read geotransform coefficients
VSIFSeekL( poDS->fp, nGeoDataOffset + 212, SEEK_SET );
VSIFReadL( szTemp, 1, nXCoeffs * 26, poDS->fp );
for ( j = 0; j < nXCoeffs; j++ )
{
poDS->adfGeoTransform[j] =
CPLScanDouble( szTemp + 26 * j, 26 );
}
VSIFSeekL( poDS->fp, nGeoDataOffset + 1642, SEEK_SET );
VSIFReadL( szTemp, 1, nYCoeffs * 26, poDS->fp );
for ( j = 0; j < nYCoeffs; j++ )
{
poDS->adfGeoTransform[j + 3] =
CPLScanDouble( szTemp + 26 * j, 26 );
}
poDS->bGeoTransformValid = TRUE;
oSRS.importFromPCI( szProj, NULL, NULL );
if ( poDS->pszProjection )
CPLFree( poDS->pszProjection );
oSRS.exportToWkt( &poDS->pszProjection );
}
else if ( EQUALN( szTemp, "PROJECTION", 10 ) )
{
char szProj[17], szUnits[17];
double adfProjParms[17];
// Read projection definition
VSIFSeekL( poDS->fp, nGeoDataOffset + 32, SEEK_SET );
VSIFReadL( szProj, 1, 16, poDS->fp );
szProj[16] = '\0';
if ( EQUALN( szProj, "PIXEL", 5 )
|| EQUALN( szProj, "METRE", 5 ) )
break;
// Read number of transform coefficients
VSIFSeekL( poDS->fp, nGeoDataOffset + 48, SEEK_SET );
VSIFReadL( szTemp, 1, 16, poDS->fp );
nXCoeffs = CPLScanLong( szTemp, 8 );
if ( nXCoeffs > 3 )
nXCoeffs = 3;
nYCoeffs = CPLScanLong( szTemp + 8, 8 );
if ( nYCoeffs > 3 )
nYCoeffs = 3;
// Read grid units definition
VSIFSeekL( poDS->fp, nGeoDataOffset + 64, SEEK_SET );
VSIFReadL( szUnits, 1, 16, poDS->fp );
szUnits[16] = '\0';
// Read 16 projection parameters
VSIFSeekL( poDS->fp, nGeoDataOffset + 80, SEEK_SET );
VSIFReadL( szTemp, 1, 26 * 16, poDS->fp );
for ( j = 0; j < 17; j++ )
{
adfProjParms[j] =
CPLScanDouble( szTemp + 26 * j, 26 );
}
// Read geotransform coefficients
VSIFSeekL( poDS->fp, nGeoDataOffset + 1980, SEEK_SET );
VSIFReadL( szTemp, 1, nXCoeffs * 26, poDS->fp );
for ( j = 0; j < nXCoeffs; j++ )
{
poDS->adfGeoTransform[j] =
CPLScanDouble( szTemp + 26 * j, 26 );;
}
VSIFSeekL( poDS->fp, nGeoDataOffset + 2526, SEEK_SET );
VSIFReadL( szTemp, 1, nYCoeffs * 26, poDS->fp );
for ( j = 0; j < nYCoeffs; j++ )
{
poDS->adfGeoTransform[j + 3] =
CPLScanDouble( szTemp + 26 * j, 26 );
}
poDS->bGeoTransformValid = TRUE;
oSRS.importFromPCI( szProj, szUnits, adfProjParms );
if ( poDS->pszProjection )
CPLFree( poDS->pszProjection );
oSRS.exportToWkt( &poDS->pszProjection );
}
}
break;
/* -------------------------------------------------------------------- */
/* GCP Segment */
/* -------------------------------------------------------------------- */
case 214: // GCP segment
{
vsi_l_offset nGcpDataOffset;
int j;
OGRSpatialReference oSRS;
poDS->nGcpPtrOffset = nSegPointersOffset + iSeg * 32;
poDS->nGcpOffset = poDS->panSegOffset[iSeg];
nGcpDataOffset = poDS->nGcpOffset + 1024;
if( !poDS->nGCPCount ) // XXX: We will read the
// first GCP segment only
{
VSIFSeekL( poDS->fp, nGcpDataOffset, SEEK_SET );
VSIFReadL( szTemp, 1, 80, poDS->fp );
poDS->nGCPCount = CPLScanLong( szTemp, 16 );
if ( poDS->nGCPCount > 0 &&
nGcpDataOffset + poDS->nGCPCount * 128 + 512 < poDS->nFileSize )
{
double dfUnitConv = 1.0;
char szProj[17];
memcpy( szProj, szTemp + 32, 16 );
szProj[16] = '\0';
oSRS.importFromPCI( szProj, NULL, NULL );
if ( poDS->pszGCPProjection )
CPLFree( poDS->pszGCPProjection );
oSRS.exportToWkt( &poDS->pszGCPProjection );
poDS->pasGCPList = (GDAL_GCP *)
CPLCalloc( poDS->nGCPCount, sizeof(GDAL_GCP) );
GDALInitGCPs( poDS->nGCPCount, poDS->pasGCPList );
if ( EQUALN( szTemp + 64, "FEET ", 9 ) )
dfUnitConv = CPLAtof(SRS_UL_FOOT_CONV);
for ( j = 0; j < poDS->nGCPCount; j++ )
{
VSIFSeekL( poDS->fp, nGcpDataOffset + j * 128 + 512,
SEEK_SET );
VSIFReadL( szTemp, 1, 128, poDS->fp );
poDS->pasGCPList[j].dfGCPPixel =
CPLScanDouble( szTemp + 6, 18 );
poDS->pasGCPList[j].dfGCPLine =
CPLScanDouble( szTemp + 24, 18 );
poDS->pasGCPList[j].dfGCPX =
CPLScanDouble( szTemp + 60, 18 );
poDS->pasGCPList[j].dfGCPY =
CPLScanDouble( szTemp + 78, 18 );
poDS->pasGCPList[j].dfGCPZ =
CPLScanDouble( szTemp + 96, 18 ) / dfUnitConv;
}
}
poDS->bGeoTransformValid = TRUE;
}
}
break;
/* -------------------------------------------------------------------- */
/* SYS Segments. Process metadata immediately. */
/* -------------------------------------------------------------------- */
case 182: // SYS segment.
{
if( EQUAL(poDS->papszSegName[iSeg],"METADATA") )
poDS->CollectPCIDSKMetadata( iSeg+1 );
}
break;
default:
break;
}
}
/* -------------------------------------------------------------------- */
/* Check for band overviews. */
/* -------------------------------------------------------------------- */
for( iBand = 0; iBand < poDS->GetRasterCount(); iBand++ )
{
GDALRasterBand *poBand = poDS->GetRasterBand( iBand+1 );
char **papszMD = poBand->GetMetadata( "PCISYS" );
int iMD;
for( iMD = 0; papszMD != NULL && papszMD[iMD] != NULL; iMD++ )
{
if( EQUALN(papszMD[iMD],"Overview_",9) )
{
int nBlockXSize, nBlockYSize;
int nImage = atoi(CPLParseNameValue( papszMD[iMD], NULL ));
PCIDSKTiledRasterBand *poOvBand;
poOvBand = new PCIDSKTiledRasterBand( poDS, 0, nImage );
if ( poOvBand->GetXSize() == 0 )
{
delete poOvBand;
delete poDS;
return NULL;
}
poBand->GetBlockSize( &nBlockXSize, &nBlockYSize );
if( nBlockYSize == 1 )
((PCIDSKRawRasterBand *) poBand)->
AttachOverview( poOvBand );
else
((PCIDSKTiledRasterBand *) poBand)->
AttachOverview( poOvBand );
}
}
}
/* -------------------------------------------------------------------- */
/* Check for worldfile if we have no other georeferencing. */
/* -------------------------------------------------------------------- */
if( !poDS->bGeoTransformValid )
poDS->bGeoTransformValid =
GDALReadWorldFile( poOpenInfo->pszFilename, "pxw",
poDS->adfGeoTransform );
/* -------------------------------------------------------------------- */
/* Initialize any PAM information. */
/* -------------------------------------------------------------------- */
poDS->SetDescription( poOpenInfo->pszFilename );
poDS->TryLoadXML();
/* -------------------------------------------------------------------- */
/* Open overviews. */
/* -------------------------------------------------------------------- */
poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
return( poDS );
}
/************************************************************************/
/* SegRead() */
/************************************************************************/
int PCIDSKDataset::SegRead( int nSegment, vsi_l_offset nOffset,
int nSize, void *pBuffer )
{
if( nSegment < 1 || nSegment > nSegCount || panSegType[nSegment-1] == 0 )
return 0;
if( nOffset + nSize > panSegSize[nSegment-1] )
{
return 0;
}
else
{
if( VSIFSeekL( fp, panSegOffset[nSegment-1]+nOffset+1024,
SEEK_SET ) != 0 )
return 0;
return VSIFReadL( pBuffer, 1, nSize, fp );
}
}
/************************************************************************/
/* CollectPCIDSKMetadata() */
/************************************************************************/
void PCIDSKDataset::CollectPCIDSKMetadata( int nSegment )
{
int nSegSize = (int) panSegSize[nSegment-1];
/* -------------------------------------------------------------------- */
/* Read all metadata in one gulp. */
/* -------------------------------------------------------------------- */
char *pszMetadataBuf = (char *) VSICalloc( 1, nSegSize + 1 );
if ( pszMetadataBuf == NULL )
return;
if( !SegRead( nSegment, 0, nSegSize, pszMetadataBuf ) )
{
CPLFree( pszMetadataBuf );
CPLError( CE_Warning, CPLE_FileIO,
"IO error reading metadata, ignoring." );
return;
}
/* ==================================================================== */
/* Parse out domain/name/value sets. */
/* ==================================================================== */
char *pszNext = pszMetadataBuf;
while( *pszNext != '\0' )
{
char *pszName, *pszValue;
pszName = pszNext;
/* -------------------------------------------------------------------- */
/* Identify the end of this line, and zero terminate it. */
/* -------------------------------------------------------------------- */
while( *pszNext != 10 && *pszNext != 12 && *pszNext != 0 )
pszNext++;
if( *pszNext != 0 )
{
*(pszNext++) = '\0';
while( *pszNext == 10 || *pszNext == 12 )
pszNext++;
}
/* -------------------------------------------------------------------- */
/* Split off the value from the name. */
/* -------------------------------------------------------------------- */
pszValue = pszName;
while( *pszValue != 0 && *pszValue != ':' )
pszValue++;
if( *pszValue != 0 )
*(pszValue++) = '\0';
while( *pszValue == ' ' )
pszValue++;
/* -------------------------------------------------------------------- */
/* Handle METADATA_IMG values by assigning to the appropriate */
/* band object. */
/* -------------------------------------------------------------------- */
if( EQUALN(pszName,"METADATA_IMG_",13) )
{
int nBand = atoi(pszName+13);
pszName += 13;
while( *pszName && *pszName != '_' )
pszName++;
if( *pszName == '_' )
pszName++;
if( nBand > 0 && nBand <= GetRasterCount() )
{
GDALRasterBand *poBand = GetRasterBand( nBand );
if( *pszName == '_' )
poBand->SetMetadataItem( pszName+1, pszValue, "PCISYS" );
else
poBand->SetMetadataItem( pszName, pszValue );
}
}
else if( EQUALN(pszName,"METADATA_FIL",13) )
{
pszName += 13;
if( *pszName == '_' )
pszName++;
if( *pszName == '_' )
SetMetadataItem( pszName+1, pszValue, "PCISYS" );
else
SetMetadataItem( pszName, pszValue );
}
}
/* -------------------------------------------------------------------- */
/* Cleanup */
/* -------------------------------------------------------------------- */
CPLFree( pszMetadataBuf );
}
/************************************************************************/
/* Create() */
/************************************************************************/
GDALDataset *PCIDSKDataset::Create( const char * pszFilename,
int nXSize, int nYSize, int nBands,
GDALDataType eType, char **papszOptions )
{
if ( eType != GDT_Byte
&& eType != GDT_Int16
&& eType != GDT_UInt16
&& eType != GDT_Float32 )
{
CPLError( CE_Failure, CPLE_AppDefined,
"Attempt to create PCIDSK dataset with an illegal data type (%s),\n"
"only Byte, Int16, UInt16 and Float32 supported by the format.\n",
GDALGetDataTypeName(eType) );
return NULL;
}
/* -------------------------------------------------------------------- */
/* Try to create the file. */
/* -------------------------------------------------------------------- */
VSILFILE *fp = VSIFOpenL( pszFilename, "wb" );
if( fp == NULL )
{
CPLError( CE_Failure, CPLE_OpenFailed,
"Unable to create file %s.\n", pszFilename );
return NULL;
}
/* -------------------------------------------------------------------- */
/* Get current time to fill appropriate fields. */
/* -------------------------------------------------------------------- */
struct tm oUpdateTime;
time_t nTime = VSITime(NULL);
VSILocalTime( &nTime, &oUpdateTime );
/* ==================================================================== */
/* Fill the PCIDSK File Header. */
/* ==================================================================== */
const char *pszDesc;
char szTemp[1024];
vsi_l_offset nImageStart; // Start block of image data
vsi_l_offset nSegPointersStart; // Start block of Segment Pointers
vsi_l_offset nImageBlocks; // Number of blocks of image data
int nImgHdrBlocks; // Number of blocks of image header data
/* -------------------------------------------------------------------- */
/* Calculate offsets. */
/* -------------------------------------------------------------------- */
nImgHdrBlocks = nBands * 2;
nSegPointersStart = 2 + nImgHdrBlocks;
nImageStart = nSegPointersStart + nSegBlocks;
nImageBlocks =
(nXSize * ((vsi_l_offset)nYSize) * nBands * (GDALGetDataTypeSize(eType)/8) + 512) / 512;
/* -------------------------------------------------------------------- */
/* Fill the File Identification. */
/* -------------------------------------------------------------------- */
CPLPrintStringFill( szTemp, "PCIDSK ", 8 );
CPLPrintStringFill( szTemp + 8, "GDAL", 4 );
CPLPrintStringFill( szTemp + 12, GDALVersionInfo( "VERSION_NUM" ), 4 );
CPLPrintUIntBig( szTemp + 16,
nImageStart + nImageBlocks + nGeoSegBlocks - 1, 16 );
CPLPrintStringFill( szTemp + 32, "", 16 );
CPLPrintStringFill( szTemp + 48, CPLGetFilename(pszFilename), 64 );
CPLPrintStringFill( szTemp + 112, "Created with GDAL", 32 );
pszDesc = CSLFetchNameValue( papszOptions, "FILEDESC1" );
if ( !pszDesc )
pszDesc = "";
CPLPrintStringFill( szTemp + 144, pszDesc, 64 );
pszDesc = CSLFetchNameValue( papszOptions, "FILEDESC2" );
if ( !pszDesc )
pszDesc = "";
CPLPrintStringFill( szTemp + 208, pszDesc, 64 );
CPLPrintTime( szTemp + 272, 16, "%H:%M %d-%b-%y ", &oUpdateTime, "C" );
CPLPrintTime( szTemp + 288, 16, "%H:%M %d-%b-%y ", &oUpdateTime, "C" );
/* -------------------------------------------------------------------- */
/* Fill the Image Data and Segment Pointers. */
/* -------------------------------------------------------------------- */
CPLPrintUIntBig( szTemp + 304, nImageStart, 16 );
CPLPrintUIntBig( szTemp + 320, nImageBlocks, 16 );
sprintf( szTemp + 336, "%16d", 2 );
sprintf( szTemp + 352, "%8d", nImgHdrBlocks );
CPLPrintStringFill( szTemp + 360, "BAND", 8 );
CPLPrintStringFill( szTemp + 368, "", 8 );
sprintf( szTemp + 376, "%8d", nBands );
sprintf( szTemp + 384, "%8d", nXSize );
sprintf( szTemp + 392, "%8d", nYSize );
CPLPrintStringFill( szTemp + 400, "METRE", 8 );
// Two following parameters will be filled with real values in FlushCache()
CPLPrintStringFill( szTemp + 408, "", 16 ); // X size of pixel
CPLPrintStringFill( szTemp + 424, "", 16 ); // Y size of pixel
CPLPrintUIntBig( szTemp + 440, nSegPointersStart, 16 );
sprintf( szTemp + 456, "%8d", nSegBlocks );
if ( eType == GDT_Byte )
sprintf( szTemp + 464, "%4d", nBands );
else
CPLPrintStringFill( szTemp + 464, " 0", 4 );
if ( eType == GDT_Int16 )
sprintf( szTemp + 468, "%4d", nBands );
else
CPLPrintStringFill( szTemp + 468, " 0", 4 );
if ( eType == GDT_UInt16 )
sprintf( szTemp + 472, "%4d", nBands );
else
CPLPrintStringFill( szTemp + 472, " 0", 4 );
if ( eType == GDT_Float32 )
sprintf( szTemp + 476, "%4d", nBands );
else
CPLPrintStringFill( szTemp + 476, " 0", 4 );
CPLPrintStringFill( szTemp + 480, "", 32 );
VSIFSeekL( fp, 0, SEEK_SET );
VSIFWriteL( (void *)szTemp, 1, 512, fp );
/* ==================================================================== */
/* Fill the Image Headers. */
/* ==================================================================== */
int i;
for ( i = 0; i < nBands; i++ )
{
pszDesc =
CSLFetchNameValue( papszOptions, CPLSPrintf("BANDDESC%d", i + 1) );
if ( !pszDesc )
pszDesc = CPLSPrintf( "Image band %d", i + 1 );
CPLPrintStringFill( szTemp, pszDesc, 64 );
CPLPrintStringFill( szTemp + 64, "", 64 );
CPLPrintTime( szTemp + 128, 16, "%H:%M %d-%b-%y ", &oUpdateTime, "C" );
CPLPrintTime( szTemp + 144, 16, "%H:%M %d-%b-%y ", &oUpdateTime, "C" );
switch ( eType )
{
case GDT_Byte:
CPLPrintStringFill( szTemp + 160, "8U", 8 );
break;
case GDT_Int16:
CPLPrintStringFill( szTemp + 160, "16S", 8 );
break;
case GDT_UInt16:
CPLPrintStringFill( szTemp + 160, "16U", 8 );
break;
case GDT_Float32:
CPLPrintStringFill( szTemp + 160, "32R", 8 );
break;
default:
break;
}
CPLPrintStringFill( szTemp + 168, "", 16 );
CPLPrintStringFill( szTemp + 184, "", 8 );
CPLPrintStringFill( szTemp + 192, "", 8 );
CPLPrintStringFill( szTemp + 200, " ", 1 );
CPLPrintStringFill( szTemp + 201, "N", 1 ); // only N is supported!
CPLPrintStringFill( szTemp + 202, "", 48 );
CPLPrintStringFill( szTemp + 250, "", 32 );
CPLPrintStringFill( szTemp + 282, "", 8 );
CPLPrintStringFill( szTemp + 290, "", 94 );
// Write the history line
CPLPrintStringFill( szTemp + 384,
"GDAL: Image band created with GDAL", 64 );
CPLPrintTime( szTemp + 448, 16, "%H:%M %d-%b-%y ", &oUpdateTime, "C" );
// Fill other lines with spaces
CPLPrintStringFill( szTemp + 464, "", 80 * 7 );
// More history lines may be used if needed.
// CPLPrintStringFill( szTemp + 464, "HistoryLine2", 80 );
// CPLPrintStringFill( szTemp + 544, "HistoryLine3", 80 );
// CPLPrintStringFill( szTemp + 624, "HistoryLine4", 80 );
// CPLPrintStringFill( szTemp + 704, "HistoryLine5", 80 );
// CPLPrintStringFill( szTemp + 784, "HistoryLine6", 80 );
// CPLPrintStringFill( szTemp + 864, "HistoryLine7", 80 );
// CPLPrintStringFill( szTemp + 944, "HistoryLine8", 80 );
VSIFWriteL( (void *)szTemp, 1, 1024, fp );
}
/* ==================================================================== */
/* Fill the Segment Pointers. */
/* ==================================================================== */
int nSegments = ( nSegBlocks * 512 ) / 32;
/* -------------------------------------------------------------------- */
/* Write out pointer to the Georeferencing segment. */
/* -------------------------------------------------------------------- */
CPLPrintStringFill( szTemp, "A150GEOref", 12 );
CPLPrintUIntBig( szTemp + 12, nImageStart + nImageBlocks, 11 );
sprintf( szTemp + 23, "%9d", nGeoSegBlocks );
VSIFWriteL( (void *)szTemp, 1, 32, fp );
/* -------------------------------------------------------------------- */
/* Blank all other segment pointers */
/* -------------------------------------------------------------------- */
CPLPrintStringFill( szTemp, "", 32 );
for ( i = 1; i < nSegments; i++ )
VSIFWriteL( (void *)szTemp, 1, 32, fp );
/* -------------------------------------------------------------------- */
/* Write out default georef segment. */
/* -------------------------------------------------------------------- */
static const char *apszGeoref[] = {
"Master Georeferencing Segment for File 17:27 11Nov2003 17:27 11Nov2003 "," POLYNOMIAL PIXEL PIXEL 3 3 0.000000000000000000D+00 1.000000000000000000D+00 0.000000000000000000D+00 "," 0.000000000000000000D+00 0.000000000000000000D+00 1.000000000000000000D+00 "," "," ", NULL};
for( i = 0; apszGeoref[i] != NULL; i++ )
VSIFWriteL( (void *) apszGeoref[i], 1, strlen(apszGeoref[i]), fp );
VSIFCloseL( fp );
return (GDALDataset *) GDALOpen( pszFilename, GA_Update );
}
/************************************************************************/
/* CreateCopy() */
/************************************************************************/
GDALDataset *
PCIDSKDataset::CreateCopy( const char * pszFilename,
GDALDataset *poSrcDS,
CPL_UNUSED int bStrict,
char ** papszOptions,
GDALProgressFunc pfnProgress,
void * pProgressData )
{
PCIDSKDataset *poDS;
GDALDataType eType;
int iBand;
int nBands = poSrcDS->GetRasterCount();
if (nBands == 0)
{
CPLError( CE_Failure, CPLE_NotSupported,
"PCIDSK driver does not support source dataset with zero band.\n");
return NULL;
}
if( !pfnProgress( 0.0, NULL, pProgressData ) )
return NULL;
eType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
/* check that other bands match type- sets type */
/* to unknown if they differ. */
for( iBand = 1; iBand < nBands; iBand++ )
{
GDALRasterBand *poBand = poSrcDS->GetRasterBand( iBand+1 );
eType = GDALDataTypeUnion( eType, poBand->GetRasterDataType() );
}
poDS = (PCIDSKDataset *) Create( pszFilename,
poSrcDS->GetRasterXSize(),
poSrcDS->GetRasterYSize(),
poSrcDS->GetRasterCount(),
eType, papszOptions );
/* Check that Create worked- return Null if it didn't */
if (poDS == NULL)
return NULL;
/* -------------------------------------------------------------------- */
/* Copy the image data. */
/* -------------------------------------------------------------------- */
int nXSize = poDS->GetRasterXSize();
int nYSize = poDS->GetRasterYSize();
int nBlockXSize, nBlockYSize, nBlockTotal, nBlocksDone;
poDS->GetRasterBand(1)->GetBlockSize( &nBlockXSize, &nBlockYSize );
nBlockTotal = ((nXSize + nBlockXSize - 1) / nBlockXSize)
* ((nYSize + nBlockYSize - 1) / nBlockYSize)
* poSrcDS->GetRasterCount();
nBlocksDone = 0;
for( iBand = 0; iBand < poSrcDS->GetRasterCount(); iBand++ )
{
GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( iBand+1 );
GDALRasterBand *poDstBand = poDS->GetRasterBand( iBand+1 );
int iYOffset, iXOffset;
void *pData;
CPLErr eErr;
pData = CPLMalloc(nBlockXSize * nBlockYSize
* GDALGetDataTypeSize(eType) / 8);
for( iYOffset = 0; iYOffset < nYSize; iYOffset += nBlockYSize )
{
for( iXOffset = 0; iXOffset < nXSize; iXOffset += nBlockXSize )
{
int nTBXSize, nTBYSize;
if( !pfnProgress( (nBlocksDone++) / (float) nBlockTotal,
NULL, pProgressData ) )
{
CPLError( CE_Failure, CPLE_UserInterrupt,
"User terminated" );
delete poDS;
GDALDriver *poPCIDSKDriver =
(GDALDriver *) GDALGetDriverByName( "PCIDSK" );
poPCIDSKDriver->Delete( pszFilename );
return NULL;
}
nTBXSize = MIN(nBlockXSize,nXSize-iXOffset);
nTBYSize = MIN(nBlockYSize,nYSize-iYOffset);
eErr = poSrcBand->RasterIO( GF_Read,
iXOffset, iYOffset,
nTBXSize, nTBYSize,
pData, nTBXSize, nTBYSize,
eType, 0, 0, NULL );
if( eErr != CE_None )
{
return NULL;
}
eErr = poDstBand->RasterIO( GF_Write,
iXOffset, iYOffset,
nTBXSize, nTBYSize,
pData, nTBXSize, nTBYSize,
eType, 0, 0, NULL );
if( eErr != CE_None )
{
return NULL;
}
}
}
CPLFree( pData );
}
/* -------------------------------------------------------------------- */
/* Copy georeferencing information, if enough is available. */
/* -------------------------------------------------------------------- */
double *tempGeoTransform=NULL;
tempGeoTransform = (double *) CPLMalloc(6*sizeof(double));
if (( poSrcDS->GetGeoTransform( tempGeoTransform ) == CE_None)
&& (tempGeoTransform[0] != 0.0 || tempGeoTransform[1] != 1.0
|| tempGeoTransform[2] != 0.0 || tempGeoTransform[3] != 0.0
|| tempGeoTransform[4] != 0.0 || ABS(tempGeoTransform[5]) != 1.0 ))
{
poDS->SetProjection(poSrcDS->GetProjectionRef());
poDS->SetGeoTransform(tempGeoTransform);
}
CPLFree(tempGeoTransform);
poDS->FlushCache();
if( !pfnProgress( 1.0, NULL, pProgressData ) )
{
CPLError( CE_Failure, CPLE_UserInterrupt,
"User terminated" );
delete poDS;
GDALDriver *poPCIDSKDriver =
(GDALDriver *) GDALGetDriverByName( "PCIDSK" );
poPCIDSKDriver->Delete( pszFilename );
return NULL;
}
poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
return poDS;
}
/************************************************************************/
/* GDALRegister_PCIDSK() */
/************************************************************************/
void GDALRegister_PCIDSK()
{
GDALDriver *poDriver;
if( GDALGetDriverByName( "PCIDSK" ) == NULL )
{
poDriver = new GDALDriver();
poDriver->SetDescription( "PCIDSK" );
poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
"PCIDSK Database File" );
poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
"frmt_pcidsk.html" );
poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "pix" );
poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, "Byte UInt16 Int16 Float32" );
poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
"<CreationOptionList>"
" <Option name='FILEDESC1' type='string' description='The first line of descriptive text'/>"
" <Option name='FILEDESC2' type='string' description='The second line of descriptive text'/>"
" <Option name='BANDDESCn' type='string' description='Text describing contents of the specified band'/>"
"</CreationOptionList>" );
poDriver->pfnIdentify = PCIDSKDataset::Identify;
poDriver->pfnOpen = PCIDSKDataset::Open;
poDriver->pfnCreate = PCIDSKDataset::Create;
poDriver->pfnCreateCopy = PCIDSKDataset::CreateCopy;
GetGDALDriverManager()->RegisterDriver( poDriver );
}
}