mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-06-19 22:03:51 -06:00
1100 lines
37 KiB
C++
1100 lines
37 KiB
C++
/******************************************************************************
|
|
* $Id: aigdataset.cpp 27384 2014-05-24 12:28:12Z rouault $
|
|
*
|
|
* Project: Arc/Info Binary Grid Driver
|
|
* Purpose: Implements GDAL interface to underlying library.
|
|
* Author: Frank Warmerdam, warmerdam@pobox.com
|
|
*
|
|
******************************************************************************
|
|
* Copyright (c) 1999, Frank Warmerdam
|
|
* Copyright (c) 2008-2013, 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_pam.h"
|
|
#include "cpl_string.h"
|
|
#include "ogr_spatialref.h"
|
|
#include "gdal_rat.h"
|
|
#include "aigrid.h"
|
|
#include "avc.h"
|
|
#include <vector>
|
|
|
|
CPL_CVSID("$Id: aigdataset.cpp 27384 2014-05-24 12:28:12Z rouault $");
|
|
|
|
CPL_C_START
|
|
void GDALRegister_AIGrid(void);
|
|
CPL_C_END
|
|
|
|
static CPLString OSR_GDS( char **papszNV, const char * pszField,
|
|
const char *pszDefaultValue );
|
|
|
|
|
|
/************************************************************************/
|
|
/* ==================================================================== */
|
|
/* AIGDataset */
|
|
/* ==================================================================== */
|
|
/************************************************************************/
|
|
|
|
class AIGRasterBand;
|
|
|
|
class CPL_DLL AIGDataset : public GDALPamDataset
|
|
{
|
|
friend class AIGRasterBand;
|
|
|
|
AIGInfo_t *psInfo;
|
|
|
|
char **papszPrj;
|
|
char *pszProjection;
|
|
|
|
GDALColorTable *poCT;
|
|
int bHasReadRat;
|
|
|
|
void TranslateColorTable( const char * );
|
|
|
|
void ReadRAT();
|
|
GDALRasterAttributeTable *poRAT;
|
|
|
|
public:
|
|
AIGDataset();
|
|
~AIGDataset();
|
|
|
|
static GDALDataset *Open( GDALOpenInfo * );
|
|
|
|
virtual CPLErr GetGeoTransform( double * );
|
|
virtual const char *GetProjectionRef(void);
|
|
virtual char **GetFileList(void);
|
|
};
|
|
|
|
/************************************************************************/
|
|
/* ==================================================================== */
|
|
/* AIGRasterBand */
|
|
/* ==================================================================== */
|
|
/************************************************************************/
|
|
|
|
class AIGRasterBand : public GDALPamRasterBand
|
|
|
|
{
|
|
friend class AIGDataset;
|
|
|
|
public:
|
|
|
|
AIGRasterBand( AIGDataset *, int );
|
|
|
|
virtual CPLErr IReadBlock( int, int, void * );
|
|
virtual double GetMinimum( int *pbSuccess );
|
|
virtual double GetMaximum( int *pbSuccess );
|
|
virtual double GetNoDataValue( int *pbSuccess );
|
|
|
|
virtual GDALColorInterp GetColorInterpretation();
|
|
virtual GDALColorTable *GetColorTable();
|
|
virtual GDALRasterAttributeTable *GetDefaultRAT();
|
|
};
|
|
|
|
/************************************************************************/
|
|
/* AIGRasterBand() */
|
|
/************************************************************************/
|
|
|
|
AIGRasterBand::AIGRasterBand( AIGDataset *poDS, int nBand )
|
|
|
|
{
|
|
this->poDS = poDS;
|
|
this->nBand = nBand;
|
|
|
|
nBlockXSize = poDS->psInfo->nBlockXSize;
|
|
nBlockYSize = poDS->psInfo->nBlockYSize;
|
|
|
|
if( poDS->psInfo->nCellType == AIG_CELLTYPE_INT
|
|
&& poDS->psInfo->dfMin >= 0.0 && poDS->psInfo->dfMax <= 254.0 )
|
|
{
|
|
eDataType = GDT_Byte;
|
|
}
|
|
else if( poDS->psInfo->nCellType == AIG_CELLTYPE_INT
|
|
&& poDS->psInfo->dfMin >= -32767 && poDS->psInfo->dfMax <= 32767 )
|
|
{
|
|
eDataType = GDT_Int16;
|
|
}
|
|
else if( poDS->psInfo->nCellType == AIG_CELLTYPE_INT )
|
|
{
|
|
eDataType = GDT_Int32;
|
|
}
|
|
else
|
|
{
|
|
eDataType = GDT_Float32;
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* IReadBlock() */
|
|
/************************************************************************/
|
|
|
|
CPLErr AIGRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
|
|
void * pImage )
|
|
|
|
{
|
|
AIGDataset *poODS = (AIGDataset *) poDS;
|
|
GInt32 *panGridRaster;
|
|
int i;
|
|
|
|
if( poODS->psInfo->nCellType == AIG_CELLTYPE_INT )
|
|
{
|
|
panGridRaster = (GInt32 *) VSIMalloc3(4,nBlockXSize,nBlockYSize);
|
|
if( panGridRaster == NULL ||
|
|
AIGReadTile( poODS->psInfo, nBlockXOff, nBlockYOff, panGridRaster )
|
|
!= CE_None )
|
|
{
|
|
CPLFree( panGridRaster );
|
|
return CE_Failure;
|
|
}
|
|
|
|
if( eDataType == GDT_Byte )
|
|
{
|
|
for( i = 0; i < nBlockXSize * nBlockYSize; i++ )
|
|
{
|
|
if( panGridRaster[i] == ESRI_GRID_NO_DATA )
|
|
((GByte *) pImage)[i] = 255;
|
|
else
|
|
((GByte *) pImage)[i] = (GByte) panGridRaster[i];
|
|
}
|
|
}
|
|
else if( eDataType == GDT_Int16 )
|
|
{
|
|
for( i = 0; i < nBlockXSize * nBlockYSize; i++ )
|
|
{
|
|
if( panGridRaster[i] == ESRI_GRID_NO_DATA )
|
|
((GInt16 *) pImage)[i] = -32768;
|
|
else
|
|
((GInt16 *) pImage)[i] = (GInt16) panGridRaster[i];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for( i = 0; i < nBlockXSize * nBlockYSize; i++ )
|
|
((GInt32 *) pImage)[i] = panGridRaster[i];
|
|
}
|
|
|
|
CPLFree( panGridRaster );
|
|
|
|
return CE_None;
|
|
}
|
|
else
|
|
{
|
|
return AIGReadFloatTile( poODS->psInfo, nBlockXOff, nBlockYOff,
|
|
(float *) pImage );
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetDefaultRAT() */
|
|
/************************************************************************/
|
|
|
|
GDALRasterAttributeTable *AIGRasterBand::GetDefaultRAT()
|
|
|
|
{
|
|
AIGDataset *poODS = (AIGDataset *) poDS;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Read info raster attribute table, if present. */
|
|
/* -------------------------------------------------------------------- */
|
|
if (!poODS->bHasReadRat)
|
|
{
|
|
poODS->ReadRAT();
|
|
poODS->bHasReadRat = TRUE;
|
|
}
|
|
|
|
if( poODS->poRAT )
|
|
return poODS->poRAT;
|
|
else
|
|
return GDALPamRasterBand::GetDefaultRAT();
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetMinimum() */
|
|
/************************************************************************/
|
|
|
|
double AIGRasterBand::GetMinimum( int *pbSuccess )
|
|
|
|
{
|
|
AIGDataset *poODS = (AIGDataset *) poDS;
|
|
|
|
if( pbSuccess != NULL )
|
|
*pbSuccess = TRUE;
|
|
|
|
return poODS->psInfo->dfMin;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetMaximum() */
|
|
/************************************************************************/
|
|
|
|
double AIGRasterBand::GetMaximum( int *pbSuccess )
|
|
|
|
{
|
|
AIGDataset *poODS = (AIGDataset *) poDS;
|
|
|
|
if( pbSuccess != NULL )
|
|
*pbSuccess = TRUE;
|
|
|
|
return poODS->psInfo->dfMax;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetNoDataValue() */
|
|
/************************************************************************/
|
|
|
|
double AIGRasterBand::GetNoDataValue( int *pbSuccess )
|
|
|
|
{
|
|
if( pbSuccess != NULL )
|
|
*pbSuccess = TRUE;
|
|
|
|
if( eDataType == GDT_Float32 )
|
|
return ESRI_GRID_FLOAT_NO_DATA;
|
|
else if( eDataType == GDT_Int16 )
|
|
return -32768;
|
|
else if( eDataType == GDT_Byte )
|
|
return 255;
|
|
else
|
|
return ESRI_GRID_NO_DATA;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetColorInterpretation() */
|
|
/************************************************************************/
|
|
|
|
GDALColorInterp AIGRasterBand::GetColorInterpretation()
|
|
|
|
{
|
|
AIGDataset *poODS = (AIGDataset *) poDS;
|
|
|
|
if( poODS->poCT != NULL )
|
|
return GCI_PaletteIndex;
|
|
else
|
|
return GDALPamRasterBand::GetColorInterpretation();
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetColorTable() */
|
|
/************************************************************************/
|
|
|
|
GDALColorTable *AIGRasterBand::GetColorTable()
|
|
|
|
{
|
|
AIGDataset *poODS = (AIGDataset *) poDS;
|
|
|
|
if( poODS->poCT != NULL )
|
|
return poODS->poCT;
|
|
else
|
|
return GDALPamRasterBand::GetColorTable();
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ==================================================================== */
|
|
/* AIGDataset */
|
|
/* ==================================================================== */
|
|
/************************************************************************/
|
|
|
|
|
|
/************************************************************************/
|
|
/* AIGDataset() */
|
|
/************************************************************************/
|
|
|
|
AIGDataset::AIGDataset()
|
|
|
|
{
|
|
psInfo = NULL;
|
|
papszPrj = NULL;
|
|
pszProjection = CPLStrdup("");
|
|
poCT = NULL;
|
|
poRAT = NULL;
|
|
bHasReadRat = FALSE;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ~AIGDataset() */
|
|
/************************************************************************/
|
|
|
|
AIGDataset::~AIGDataset()
|
|
|
|
{
|
|
FlushCache();
|
|
CPLFree( pszProjection );
|
|
CSLDestroy( papszPrj );
|
|
if( psInfo != NULL )
|
|
AIGClose( psInfo );
|
|
|
|
if( poCT != NULL )
|
|
delete poCT;
|
|
|
|
if( poRAT != NULL )
|
|
delete poRAT;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetFileList() */
|
|
/************************************************************************/
|
|
|
|
char **AIGDataset::GetFileList()
|
|
|
|
{
|
|
char **papszFileList = GDALPamDataset::GetFileList();
|
|
|
|
// Add in all files in the cover directory.
|
|
char **papszCoverFiles = VSIReadDir( GetDescription() );
|
|
int i;
|
|
|
|
for( i = 0; papszCoverFiles != NULL && papszCoverFiles[i] != NULL; i++ )
|
|
{
|
|
if( EQUAL(papszCoverFiles[i],".")
|
|
|| EQUAL(papszCoverFiles[i],"..") )
|
|
continue;
|
|
|
|
papszFileList =
|
|
CSLAddString( papszFileList,
|
|
CPLFormFilename( GetDescription(),
|
|
papszCoverFiles[i],
|
|
NULL ) );
|
|
}
|
|
CSLDestroy(papszCoverFiles);
|
|
|
|
return papszFileList;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* AIGErrorHandlerVATOpen() */
|
|
/************************************************************************/
|
|
|
|
class AIGErrorDescription
|
|
{
|
|
public:
|
|
CPLErr eErr;
|
|
int no;
|
|
CPLString osMsg;
|
|
};
|
|
|
|
static void CPL_STDCALL AIGErrorHandlerVATOpen(CPLErr eErr, int no, const char* msg)
|
|
{
|
|
std::vector<AIGErrorDescription>* paoErrors =
|
|
(std::vector<AIGErrorDescription>* )CPLGetErrorHandlerUserData();
|
|
if( EQUALN(msg, "EOF encountered in", strlen("EOF encountered in")) &&
|
|
strstr(msg, "../info/arc.dir") != NULL )
|
|
return;
|
|
if( EQUALN(msg, "Failed to open table ", strlen("Failed to open table ")) )
|
|
return;
|
|
AIGErrorDescription oError;
|
|
oError.eErr = eErr;
|
|
oError.no = no;
|
|
oError.osMsg = msg;
|
|
paoErrors->push_back(oError);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ReadRAT() */
|
|
/************************************************************************/
|
|
|
|
void AIGDataset::ReadRAT()
|
|
|
|
{
|
|
#ifndef OGR_ENABLED
|
|
#else
|
|
/* -------------------------------------------------------------------- */
|
|
/* Check if we have an associated info directory. If not */
|
|
/* return quietly. */
|
|
/* -------------------------------------------------------------------- */
|
|
CPLString osInfoPath, osTableName;
|
|
VSIStatBufL sStatBuf;
|
|
|
|
osInfoPath = psInfo->pszCoverName;
|
|
osInfoPath += "/../info";
|
|
|
|
if( VSIStatL( osInfoPath, &sStatBuf ) != 0 )
|
|
{
|
|
CPLDebug( "AIG", "No associated info directory at: %s, skip RAT.",
|
|
osInfoPath.c_str() );
|
|
return;
|
|
}
|
|
|
|
osInfoPath += "/";
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Attempt to open the VAT table associated with this coverage. */
|
|
/* -------------------------------------------------------------------- */
|
|
osTableName = CPLGetFilename(psInfo->pszCoverName);
|
|
osTableName += ".VAT";
|
|
|
|
/* Turn off errors that can be triggered if the info has no VAT */
|
|
/* table related with this coverage */
|
|
std::vector<AIGErrorDescription> aoErrors;
|
|
CPLPushErrorHandlerEx(AIGErrorHandlerVATOpen, &aoErrors );
|
|
|
|
AVCBinFile *psFile =
|
|
AVCBinReadOpen( osInfoPath, osTableName,
|
|
AVCCoverTypeUnknown, AVCFileTABLE, NULL );
|
|
CPLPopErrorHandler();
|
|
|
|
/* Emit other errors */
|
|
std::vector<AIGErrorDescription>::const_iterator oIter;
|
|
for( oIter = aoErrors.begin(); oIter != aoErrors.end(); ++oIter )
|
|
{
|
|
const AIGErrorDescription& oError = *oIter;
|
|
CPLError( oError.eErr, oError.no, "%s", oError.osMsg.c_str() );
|
|
}
|
|
|
|
CPLErrorReset();
|
|
if( psFile == NULL )
|
|
return;
|
|
|
|
AVCTableDef *psTableDef = psFile->hdr.psTableDef;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Setup columns in corresponding RAT. */
|
|
/* -------------------------------------------------------------------- */
|
|
int iField;
|
|
|
|
poRAT = new GDALDefaultRasterAttributeTable();
|
|
|
|
for( iField = 0; iField < psTableDef->numFields; iField++ )
|
|
{
|
|
AVCFieldInfo *psFDef = psTableDef->pasFieldDef + iField;
|
|
GDALRATFieldUsage eFUsage = GFU_Generic;
|
|
GDALRATFieldType eFType = GFT_String;
|
|
|
|
CPLString osFName = psFDef->szName;
|
|
osFName.Trim();
|
|
|
|
if( EQUAL(osFName,"VALUE") )
|
|
eFUsage = GFU_MinMax;
|
|
else if( EQUAL(osFName,"COUNT") )
|
|
eFUsage = GFU_PixelCount;
|
|
|
|
if( psFDef->nType1 * 10 == AVC_FT_BININT )
|
|
eFType = GFT_Integer;
|
|
else if( psFDef->nType1 * 10 == AVC_FT_BINFLOAT )
|
|
eFType = GFT_Real;
|
|
|
|
poRAT->CreateColumn( osFName, eFType, eFUsage );
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Process all records into RAT. */
|
|
/* -------------------------------------------------------------------- */
|
|
AVCField *pasFields;
|
|
int iRecord = 0;
|
|
|
|
while( (pasFields = AVCBinReadNextTableRec(psFile)) != NULL )
|
|
{
|
|
iRecord++;
|
|
|
|
for( iField = 0; iField < psTableDef->numFields; iField++ )
|
|
{
|
|
switch( psTableDef->pasFieldDef[iField].nType1 * 10 )
|
|
{
|
|
case AVC_FT_DATE:
|
|
case AVC_FT_FIXINT:
|
|
case AVC_FT_CHAR:
|
|
case AVC_FT_FIXNUM:
|
|
{
|
|
// XXX - I bet mloskot would like to see const_cast + static_cast :-)
|
|
const char* pszTmp = (const char*)(pasFields[iField].pszStr);
|
|
CPLString osStrValue( pszTmp );
|
|
poRAT->SetValue( iRecord-1, iField, osStrValue.Trim() );
|
|
}
|
|
break;
|
|
|
|
case AVC_FT_BININT:
|
|
if( psTableDef->pasFieldDef[iField].nSize == 4 )
|
|
poRAT->SetValue( iRecord-1, iField,
|
|
pasFields[iField].nInt32 );
|
|
else
|
|
poRAT->SetValue( iRecord-1, iField,
|
|
pasFields[iField].nInt16 );
|
|
break;
|
|
|
|
case AVC_FT_BINFLOAT:
|
|
if( psTableDef->pasFieldDef[iField].nSize == 4 )
|
|
poRAT->SetValue( iRecord-1, iField,
|
|
pasFields[iField].fFloat );
|
|
else
|
|
poRAT->SetValue( iRecord-1, iField,
|
|
pasFields[iField].dDouble );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Cleanup */
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
AVCBinReadClose( psFile );
|
|
|
|
/* Workaround against #2447 and #3031, to avoid binding languages */
|
|
/* not being able to open the dataset */
|
|
CPLErrorReset();
|
|
|
|
#endif /* OGR_ENABLED */
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Open() */
|
|
/************************************************************************/
|
|
|
|
GDALDataset *AIGDataset::Open( GDALOpenInfo * poOpenInfo )
|
|
|
|
{
|
|
AIGInfo_t *psInfo;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* If the pass name ends in .adf assume a file within the */
|
|
/* coverage has been selected, and strip that off the coverage */
|
|
/* name. */
|
|
/* -------------------------------------------------------------------- */
|
|
CPLString osCoverName;
|
|
|
|
osCoverName = poOpenInfo->pszFilename;
|
|
if( osCoverName.size() > 4
|
|
&& EQUAL(osCoverName.c_str()+osCoverName.size()-4,".adf") )
|
|
{
|
|
osCoverName = CPLGetDirname( poOpenInfo->pszFilename );
|
|
if( osCoverName == "" )
|
|
osCoverName = ".";
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Otherwise verify we were already given a directory. */
|
|
/* -------------------------------------------------------------------- */
|
|
else if( !poOpenInfo->bIsDirectory )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Verify that a few of the "standard" files are available. */
|
|
/* -------------------------------------------------------------------- */
|
|
VSIStatBufL sStatBuf;
|
|
CPLString osTestName;
|
|
|
|
osTestName.Printf( "%s/hdr.adf", osCoverName.c_str() );
|
|
if( VSIStatL( osTestName, &sStatBuf ) != 0 )
|
|
|
|
{
|
|
osTestName.Printf( "%s/HDR.ADF", osCoverName.c_str() );
|
|
if( VSIStatL( osTestName, &sStatBuf ) != 0 )
|
|
return NULL;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Confirm we have at least one raster data file. These can be */
|
|
/* sparse so we don't require particular ones to exists but if */
|
|
/* there are none this is likely not a grid. */
|
|
/* -------------------------------------------------------------------- */
|
|
char **papszFileList = VSIReadDir( osCoverName );
|
|
int iFile;
|
|
int bGotOne = FALSE;
|
|
|
|
if (papszFileList == NULL)
|
|
{
|
|
/* Useful when reading from /vsicurl/ on servers that don't */
|
|
/* return a file list */
|
|
/* such as /vsicurl/http://eros.usgs.gov/archive/nslrsda/GeoTowns/NLCD/89110458 */
|
|
do
|
|
{
|
|
osTestName.Printf( "%s/W001001.ADF", osCoverName.c_str() );
|
|
if( VSIStatL( osTestName, &sStatBuf ) == 0 )
|
|
{
|
|
bGotOne = TRUE;
|
|
break;
|
|
}
|
|
|
|
osTestName.Printf( "%s/w001001.adf", osCoverName.c_str() );
|
|
if( VSIStatL( osTestName, &sStatBuf ) == 0 )
|
|
{
|
|
bGotOne = TRUE;
|
|
break;
|
|
}
|
|
} while(0);
|
|
}
|
|
|
|
for( iFile = 0;
|
|
papszFileList != NULL && papszFileList[iFile] != NULL && !bGotOne;
|
|
iFile++ )
|
|
{
|
|
if( strlen(papszFileList[iFile]) != 11 )
|
|
continue;
|
|
|
|
// looking for something like w001001.adf or z001013.adf
|
|
if( papszFileList[iFile][0] != 'w'
|
|
&& papszFileList[iFile][0] != 'W'
|
|
&& papszFileList[iFile][0] != 'z'
|
|
&& papszFileList[iFile][0] != 'Z' )
|
|
continue;
|
|
|
|
if( strncmp(papszFileList[iFile] + 1, "0010", 4) != 0 )
|
|
continue;
|
|
|
|
if( !EQUAL(papszFileList[iFile] + 7, ".adf") )
|
|
continue;
|
|
|
|
bGotOne = TRUE;
|
|
}
|
|
CSLDestroy( papszFileList );
|
|
|
|
if( !bGotOne )
|
|
return NULL;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Open the file. */
|
|
/* -------------------------------------------------------------------- */
|
|
psInfo = AIGOpen( osCoverName.c_str(), "r" );
|
|
|
|
if( psInfo == NULL )
|
|
{
|
|
CPLErrorReset();
|
|
return NULL;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Confirm the requested access is supported. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( poOpenInfo->eAccess == GA_Update )
|
|
{
|
|
AIGClose(psInfo);
|
|
CPLError( CE_Failure, CPLE_NotSupported,
|
|
"The AIG driver does not support update access to existing"
|
|
" datasets.\n" );
|
|
return NULL;
|
|
}
|
|
/* -------------------------------------------------------------------- */
|
|
/* Create a corresponding GDALDataset. */
|
|
/* -------------------------------------------------------------------- */
|
|
AIGDataset *poDS;
|
|
|
|
poDS = new AIGDataset();
|
|
|
|
poDS->psInfo = psInfo;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Try to read a color table (.clr). It seems it is legal to */
|
|
/* have more than one so we just use the first one found. */
|
|
/* -------------------------------------------------------------------- */
|
|
char **papszFiles = CPLReadDir( psInfo->pszCoverName );
|
|
CPLString osClrFilename;
|
|
CPLString osCleanPath = CPLCleanTrailingSlash( psInfo->pszCoverName );
|
|
|
|
// first check for any .clr in coverage dir.
|
|
for( iFile = 0; papszFiles != NULL && papszFiles[iFile] != NULL; iFile++ )
|
|
{
|
|
if( !EQUAL(CPLGetExtension(papszFiles[iFile]),"clr") && !EQUAL(CPLGetExtension(papszFiles[iFile]),"CLR"))
|
|
continue;
|
|
|
|
osClrFilename = CPLFormFilename( psInfo->pszCoverName,
|
|
papszFiles[iFile], NULL );
|
|
break;
|
|
}
|
|
|
|
CSLDestroy( papszFiles );
|
|
|
|
// Look in parent if we don't find a .clr in the coverage dir.
|
|
if( strlen(osClrFilename) == 0 )
|
|
{
|
|
osTestName.Printf( "%s/../%s.clr",
|
|
psInfo->pszCoverName,
|
|
CPLGetFilename( osCleanPath ) );
|
|
|
|
if( VSIStatL( osTestName, &sStatBuf ) != 0 )
|
|
|
|
{
|
|
osTestName.Printf( "%s/../%s.CLR",
|
|
psInfo->pszCoverName,
|
|
CPLGetFilename( osCleanPath ) );
|
|
|
|
if( !VSIStatL( osTestName, &sStatBuf ) )
|
|
osClrFilename = osTestName;
|
|
}
|
|
else
|
|
osClrFilename = osTestName;
|
|
}
|
|
|
|
|
|
if( strlen(osClrFilename) > 0 )
|
|
poDS->TranslateColorTable( osClrFilename );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Establish raster info. */
|
|
/* -------------------------------------------------------------------- */
|
|
poDS->nRasterXSize = psInfo->nPixels;
|
|
poDS->nRasterYSize = psInfo->nLines;
|
|
poDS->nBands = 1;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Create band information objects. */
|
|
/* -------------------------------------------------------------------- */
|
|
poDS->SetBand( 1, new AIGRasterBand( poDS, 1 ) );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Try to read projection file. */
|
|
/* -------------------------------------------------------------------- */
|
|
const char *pszPrjFilename;
|
|
|
|
pszPrjFilename = CPLFormCIFilename( psInfo->pszCoverName, "prj", "adf" );
|
|
if( VSIStatL( pszPrjFilename, &sStatBuf ) == 0 )
|
|
{
|
|
OGRSpatialReference oSRS;
|
|
|
|
poDS->papszPrj = CSLLoad( pszPrjFilename );
|
|
|
|
if( oSRS.importFromESRI( poDS->papszPrj ) == OGRERR_NONE )
|
|
{
|
|
// If geographic values are in seconds, we must transform.
|
|
// Is there a code for minutes too?
|
|
if( oSRS.IsGeographic()
|
|
&& EQUAL(OSR_GDS( poDS->papszPrj, "Units", ""), "DS") )
|
|
{
|
|
psInfo->dfLLX /= 3600.0;
|
|
psInfo->dfURY /= 3600.0;
|
|
psInfo->dfCellSizeX /= 3600.0;
|
|
psInfo->dfCellSizeY /= 3600.0;
|
|
}
|
|
|
|
CPLFree( poDS->pszProjection );
|
|
oSRS.exportToWkt( &(poDS->pszProjection) );
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Initialize any PAM information. */
|
|
/* -------------------------------------------------------------------- */
|
|
poDS->SetDescription( psInfo->pszCoverName );
|
|
poDS->TryLoadXML();
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Open overviews. */
|
|
/* -------------------------------------------------------------------- */
|
|
poDS->oOvManager.Initialize( poDS, psInfo->pszCoverName );
|
|
|
|
return( poDS );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetGeoTransform() */
|
|
/************************************************************************/
|
|
|
|
CPLErr AIGDataset::GetGeoTransform( double * padfTransform )
|
|
|
|
{
|
|
padfTransform[0] = psInfo->dfLLX;
|
|
padfTransform[1] = psInfo->dfCellSizeX;
|
|
padfTransform[2] = 0;
|
|
|
|
padfTransform[3] = psInfo->dfURY;
|
|
padfTransform[4] = 0;
|
|
padfTransform[5] = -psInfo->dfCellSizeY;
|
|
|
|
return( CE_None );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetProjectionRef() */
|
|
/************************************************************************/
|
|
|
|
const char *AIGDataset::GetProjectionRef()
|
|
|
|
{
|
|
return pszProjection;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* TranslateColorTable() */
|
|
/************************************************************************/
|
|
|
|
void AIGDataset::TranslateColorTable( const char *pszClrFilename )
|
|
|
|
{
|
|
int iLine;
|
|
char **papszClrLines;
|
|
|
|
papszClrLines = CSLLoad( pszClrFilename );
|
|
if( papszClrLines == NULL )
|
|
return;
|
|
|
|
poCT = new GDALColorTable();
|
|
|
|
for( iLine = 0; papszClrLines[iLine] != NULL; iLine++ )
|
|
{
|
|
char **papszTokens = CSLTokenizeString( papszClrLines[iLine] );
|
|
|
|
if( CSLCount(papszTokens) >= 4 && papszTokens[0][0] != '#' )
|
|
{
|
|
int nIndex;
|
|
GDALColorEntry sEntry;
|
|
|
|
nIndex = atoi(papszTokens[0]);
|
|
sEntry.c1 = (short) atoi(papszTokens[1]);
|
|
sEntry.c2 = (short) atoi(papszTokens[2]);
|
|
sEntry.c3 = (short) atoi(papszTokens[3]);
|
|
sEntry.c4 = 255;
|
|
|
|
if( (nIndex < 0 || nIndex > 33000)
|
|
|| (sEntry.c1 < 0 || sEntry.c1 > 255)
|
|
|| (sEntry.c2 < 0 || sEntry.c2 > 255)
|
|
|| (sEntry.c3 < 0 || sEntry.c3 > 255) )
|
|
{
|
|
CSLDestroy( papszTokens );
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Color table entry appears to be corrupt, skipping the rest. " );
|
|
break;
|
|
}
|
|
|
|
poCT->SetColorEntry( nIndex, &sEntry );
|
|
}
|
|
|
|
CSLDestroy( papszTokens );
|
|
}
|
|
|
|
CSLDestroy( papszClrLines );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* OSR_GDS() */
|
|
/************************************************************************/
|
|
|
|
static CPLString OSR_GDS( char **papszNV, const char * pszField,
|
|
const char *pszDefaultValue )
|
|
|
|
{
|
|
int iLine;
|
|
|
|
if( papszNV == NULL || papszNV[0] == NULL )
|
|
return pszDefaultValue;
|
|
|
|
for( iLine = 0;
|
|
papszNV[iLine] != NULL &&
|
|
!EQUALN(papszNV[iLine],pszField,strlen(pszField));
|
|
iLine++ ) {}
|
|
|
|
if( papszNV[iLine] == NULL )
|
|
return pszDefaultValue;
|
|
else
|
|
{
|
|
CPLString osResult;
|
|
char **papszTokens;
|
|
|
|
papszTokens = CSLTokenizeString(papszNV[iLine]);
|
|
|
|
if( CSLCount(papszTokens) > 1 )
|
|
osResult = papszTokens[1];
|
|
else
|
|
osResult = pszDefaultValue;
|
|
|
|
CSLDestroy( papszTokens );
|
|
return osResult;
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* AIGRename() */
|
|
/* */
|
|
/* Custom renamer for AIG dataset. */
|
|
/************************************************************************/
|
|
|
|
static CPLErr AIGRename( const char *pszNewName, const char *pszOldName )
|
|
|
|
{
|
|
/* -------------------------------------------------------------------- */
|
|
/* Make sure we are talking about paths to the coverage */
|
|
/* directory. */
|
|
/* -------------------------------------------------------------------- */
|
|
CPLString osOldPath, osNewPath;
|
|
|
|
if( strlen(CPLGetExtension(pszNewName)) > 0 )
|
|
osNewPath = CPLGetPath(pszNewName);
|
|
else
|
|
osNewPath = pszNewName;
|
|
|
|
if( strlen(CPLGetExtension(pszOldName)) > 0 )
|
|
osOldPath = CPLGetPath(pszOldName);
|
|
else
|
|
osOldPath = pszOldName;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Get file list. */
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
GDALDatasetH hDS = GDALOpen( osOldPath, GA_ReadOnly );
|
|
if( hDS == NULL )
|
|
return CE_Failure;
|
|
|
|
char **papszFileList = GDALGetFileList( hDS );
|
|
GDALClose( hDS );
|
|
|
|
if( papszFileList == NULL )
|
|
return CE_Failure;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Work out the corresponding new names. */
|
|
/* -------------------------------------------------------------------- */
|
|
char **papszNewFileList = NULL;
|
|
int i;
|
|
|
|
for( i = 0; papszFileList[i] != NULL; i++ )
|
|
{
|
|
CPLString osNewFilename;
|
|
|
|
if( !EQUALN(papszFileList[i],osOldPath,strlen(osOldPath)) )
|
|
{
|
|
CPLAssert( FALSE );
|
|
return CE_Failure;
|
|
}
|
|
|
|
osNewFilename = osNewPath + (papszFileList[i] + strlen(osOldPath));
|
|
|
|
papszNewFileList = CSLAddString( papszNewFileList, osNewFilename );
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Try renaming the directory. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( VSIRename( osNewPath, osOldPath ) != 0 )
|
|
{
|
|
if( VSIMkdir( osNewPath, 0777 ) != 0 )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Unable to create directory %s:\n%s",
|
|
osNewPath.c_str(),
|
|
VSIStrerror(errno) );
|
|
return CE_Failure;
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Copy/rename any remaining files. */
|
|
/* -------------------------------------------------------------------- */
|
|
VSIStatBufL sStatBuf;
|
|
|
|
for( i = 0; papszFileList[i] != NULL; i++ )
|
|
{
|
|
if( VSIStatL( papszFileList[i], &sStatBuf ) == 0
|
|
&& VSI_ISREG( sStatBuf.st_mode ) )
|
|
{
|
|
if( CPLMoveFile( papszNewFileList[i], papszFileList[i] ) != 0 )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Unable to move %s to %s:\n%s",
|
|
papszFileList[i],
|
|
papszNewFileList[i],
|
|
VSIStrerror(errno) );
|
|
return CE_Failure;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( VSIStatL( osOldPath, &sStatBuf ) == 0 )
|
|
CPLUnlinkTree( osOldPath );
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* AIGDelete() */
|
|
/* */
|
|
/* Custom dataset deleter for AIG dataset. */
|
|
/************************************************************************/
|
|
|
|
static CPLErr AIGDelete( const char *pszDatasetname )
|
|
|
|
{
|
|
/* -------------------------------------------------------------------- */
|
|
/* Get file list. */
|
|
/* -------------------------------------------------------------------- */
|
|
GDALDatasetH hDS = GDALOpen( pszDatasetname, GA_ReadOnly );
|
|
if( hDS == NULL )
|
|
return CE_Failure;
|
|
|
|
char **papszFileList = GDALGetFileList( hDS );
|
|
GDALClose( hDS );
|
|
|
|
if( papszFileList == NULL )
|
|
return CE_Failure;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Delete all regular files. */
|
|
/* -------------------------------------------------------------------- */
|
|
int i;
|
|
for( i = 0; papszFileList[i] != NULL; i++ )
|
|
{
|
|
VSIStatBufL sStatBuf;
|
|
if( VSIStatL( papszFileList[i], &sStatBuf ) == 0
|
|
&& VSI_ISREG( sStatBuf.st_mode ) )
|
|
{
|
|
if( VSIUnlink( papszFileList[i] ) != 0 )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Unable to delete '%s':\n%s",
|
|
papszFileList[i], VSIStrerror( errno ) );
|
|
return CE_Failure;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Delete directories. */
|
|
/* -------------------------------------------------------------------- */
|
|
for( i = 0; papszFileList[i] != NULL; i++ )
|
|
{
|
|
VSIStatBufL sStatBuf;
|
|
if( VSIStatL( papszFileList[i], &sStatBuf ) == 0
|
|
&& VSI_ISDIR( sStatBuf.st_mode ) )
|
|
{
|
|
if( CPLUnlinkTree( papszFileList[i] ) != 0 )
|
|
return CE_Failure;
|
|
}
|
|
}
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALRegister_AIG() */
|
|
/************************************************************************/
|
|
|
|
void GDALRegister_AIGrid()
|
|
|
|
{
|
|
GDALDriver *poDriver;
|
|
|
|
if( GDALGetDriverByName( "AIG" ) == NULL )
|
|
{
|
|
poDriver = new GDALDriver();
|
|
|
|
poDriver->SetDescription( "AIG" );
|
|
poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
|
|
poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
|
|
"Arc/Info Binary Grid" );
|
|
poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
|
|
"frmt_various.html#AIG" );
|
|
poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
|
|
|
|
poDriver->pfnOpen = AIGDataset::Open;
|
|
|
|
poDriver->pfnRename = AIGRename;
|
|
poDriver->pfnDelete = AIGDelete;
|
|
|
|
GetGDALDriverManager()->RegisterDriver( poDriver );
|
|
}
|
|
}
|