1
1
/******************************************************************************
2
* $Id: ehdrdataset.cpp 20135 2010-07-26 15:30:40Z mloskot $
2
* $Id: ehdrdataset.cpp 21783 2011-02-21 22:32:11Z rouault $
4
4
* Project: ESRI .hdr Driver
5
5
* Purpose: Implementation of EHdrDataset
31
31
#include "ogr_spatialref.h"
32
32
#include "cpl_string.h"
34
CPL_CVSID("$Id: ehdrdataset.cpp 20135 2010-07-26 15:30:40Z mloskot $");
34
CPL_CVSID("$Id: ehdrdataset.cpp 21783 2011-02-21 22:32:11Z rouault $");
37
37
void GDALRegister_EHdr(void);
40
#define HAS_MIN_FLAG 0x1
41
#define HAS_MAX_FLAG 0x2
42
#define HAS_MEAN_FLAG 0x4
43
#define HAS_STDDEV_FLAG 0x8
44
#define HAS_ALL_FLAGS (HAS_MIN_FLAG | HAS_MAX_FLAG | HAS_MEAN_FLAG | HAS_STDDEV_FLAG)
40
46
/************************************************************************/
41
47
/* ==================================================================== */
120
EHdrRasterBand( GDALDataset *poDS, int nBand, FILE * fpRaw,
128
EHdrRasterBand( GDALDataset *poDS, int nBand, VSILFILE * fpRaw,
121
129
vsi_l_offset nImgOffset, int nPixelOffset,
123
131
GDALDataType eDataType, int bNativeOrder,
142
150
/************************************************************************/
144
152
EHdrRasterBand::EHdrRasterBand( GDALDataset *poDS,
145
int nBand, FILE * fpRaw,
153
int nBand, VSILFILE * fpRaw,
146
154
vsi_l_offset nImgOffset, int nPixelOffset,
148
156
GDALDataType eDataType, int bNativeOrder,
216
224
/* -------------------------------------------------------------------- */
217
225
pabyBuffer = (GByte *) CPLCalloc(nLineBytes,1);
219
if( VSIFSeekL( GetFP(), nLineStart, SEEK_SET ) != 0
220
|| VSIFReadL( pabyBuffer, 1, nLineBytes, GetFP() ) != nLineBytes )
227
if( VSIFSeekL( GetFPL(), nLineStart, SEEK_SET ) != 0
228
|| VSIFReadL( pabyBuffer, 1, nLineBytes, GetFPL() ) != nLineBytes )
222
230
CPLError( CE_Failure, CPLE_FileIO,
223
231
"Failed to read %u bytes at offset %lu.\n%s",
281
289
/* -------------------------------------------------------------------- */
282
290
pabyBuffer = (GByte *) CPLCalloc(nLineBytes,1);
284
if( VSIFSeekL( GetFP(), nLineStart, SEEK_SET ) != 0 )
292
if( VSIFSeekL( GetFPL(), nLineStart, SEEK_SET ) != 0 )
286
294
CPLError( CE_Failure, CPLE_FileIO,
287
295
"Failed to read %u bytes at offset %lu.\n%s",
290
298
return CE_Failure;
293
VSIFReadL( pabyBuffer, 1, nLineBytes, GetFP() );
301
VSIFReadL( pabyBuffer, 1, nLineBytes, GetFPL() );
295
303
/* -------------------------------------------------------------------- */
296
304
/* Copy data, promoting to 8bit. */
318
326
/* -------------------------------------------------------------------- */
319
327
/* Write the data back out. */
320
328
/* -------------------------------------------------------------------- */
321
if( VSIFSeekL( GetFP(), nLineStart, SEEK_SET ) != 0
322
|| VSIFWriteL( pabyBuffer, 1, nLineBytes, GetFP() ) != nLineBytes )
329
if( VSIFSeekL( GetFPL(), nLineStart, SEEK_SET ) != 0
330
|| VSIFWriteL( pabyBuffer, 1, nLineBytes, GetFPL() ) != nLineBytes )
324
332
CPLError( CE_Failure, CPLE_FileIO,
325
333
"Failed to write %u bytes at offset %lu.\n%s",
535
544
CPLString osCLRFilename = CPLResetExtension( GetDescription(), "clr" );
538
FILE *fp = VSIFOpenL( osCLRFilename, "wt" );
547
VSILFILE *fp = VSIFOpenL( osCLRFilename, "wt" );
541
550
for( int iColor = 0; iColor < poTable->GetColorEntryCount(); iColor++ )
705
714
CPLString osPath = CPLGetPath( GetDescription() );
706
715
CPLString osName = CPLGetBasename( GetDescription() );
707
CPLString osHDRFilename = CPLFormCIFilename( osPath, osName, "hdr" );
716
CPLString osHDRFilename = CPLFormCIFilename( osPath, osName, osHeaderExt );
709
718
/* -------------------------------------------------------------------- */
710
719
/* Write .hdr file. */
711
720
/* -------------------------------------------------------------------- */
715
724
fp = VSIFOpenL( osHDRFilename, "wt" );
762
771
EHdrRasterBand* poBand = (EHdrRasterBand*)papoBands[i];
763
772
VSIFPrintfL( fp, "%d %.10f %.10f ", i+1, poBand->dfMin, poBand->dfMax );
764
if ( poBand->minmaxmeanstddev & 0x4 )
773
if ( poBand->minmaxmeanstddev & HAS_MEAN_FLAG )
765
774
VSIFPrintfL( fp, "%.10f ", poBand->dfMean);
767
776
VSIFPrintfL( fp, "# ");
769
if ( poBand->minmaxmeanstddev & 0x8 )
778
if ( poBand->minmaxmeanstddev & HAS_STDDEV_FLAG )
770
779
VSIFPrintfL( fp, "%.10f\n", poBand->dfStdDev);
772
781
VSIFPrintfL( fp, "#\n");
790
799
/* -------------------------------------------------------------------- */
791
800
/* Read .stx file. */
792
801
/* -------------------------------------------------------------------- */
794
if ((fp = VSIFOpenL( osSTXFilename, "rt" )))
803
if ((fp = VSIFOpenL( osSTXFilename, "rt" )) != NULL)
796
805
const char * pszLine;
797
while( (pszLine = CPLReadLineL( fp )) )
806
while( (pszLine = CPLReadLineL( fp )) != NULL )
799
808
char **papszTokens;
800
809
papszTokens = CSLTokenizeStringComplex( pszLine, " \t", TRUE, FALSE );
807
816
EHdrRasterBand* poBand = (EHdrRasterBand*)papoBands[i-1];
808
817
poBand->dfMin = atof(papszTokens[1]);
809
818
poBand->dfMax = atof(papszTokens[2]);
810
poBand->minmaxmeanstddev = 0x3;
820
int bNoDataSet = FALSE;
821
double dfNoData = poBand->GetNoDataValue(&bNoDataSet);
822
if (bNoDataSet && dfNoData == poBand->dfMin)
824
/* Triggered by /vsicurl/http://eros.usgs.gov/archive/nslrsda/GeoTowns/HongKong/srtm/n22e113.zip/n22e113.bil */
825
CPLDebug("EHDr", "Ignoring .stx file where min == nodata. "
826
"The nodata value shouldn't be taken into account "
827
"in minimum value computation.");
828
CSLDestroy( papszTokens );
833
poBand->minmaxmeanstddev = HAS_MIN_FLAG | HAS_MAX_FLAG;
811
834
// reads optional mean and stddev
812
835
if ( !EQUAL(papszTokens[3], "#") )
814
837
poBand->dfMean = atof(papszTokens[3]);
815
poBand->minmaxmeanstddev |= 0x4;
838
poBand->minmaxmeanstddev |= HAS_MEAN_FLAG;
817
840
if ( !EQUAL(papszTokens[4], "#") )
819
842
poBand->dfStdDev = atof(papszTokens[4]);
820
poBand->minmaxmeanstddev |= 0x8;
843
poBand->minmaxmeanstddev |= HAS_STDDEV_FLAG;
823
846
if( nTokens >= 6 && !EQUAL(papszTokens[5], "#") )
857
880
CPLString osName = CPLGetBasename( pszFilename );
858
881
CPLString osREPFilename =
859
882
CPLFormCIFilename( osPath, osName, "rep" );
860
if( VSIStatL( (const char*)osREPFilename, &sStatBuf ) == 0 )
883
if( VSIStatExL( osREPFilename.c_str(), &sStatBuf, VSI_STAT_EXISTS_FLAG ) == 0 )
861
884
return osREPFilename;
863
886
if (EQUAL(CPLGetFilename(pszFilename), "imspatio.bil") ||
864
887
EQUAL(CPLGetFilename(pszFilename), "haspatio.bil"))
866
CPLString pszImageRepFilename(CPLFormCIFilename( osPath, "image", "rep" ));
867
if( VSIStatL( (const char*)pszImageRepFilename, &sStatBuf ) == 0 )
868
return pszImageRepFilename;
889
CPLString osImageRepFilename(CPLFormCIFilename( osPath, "image", "rep" ));
890
if( VSIStatExL( osImageRepFilename.c_str(), &sStatBuf, VSI_STAT_EXISTS_FLAG ) == 0 )
891
return osImageRepFilename;
870
893
/* Try in the upper directories if not found in the BIL image directory */
871
894
CPLString dirName(CPLGetDirname(osPath));
872
if (CPLIsFilenameRelative((const char*)osPath))
895
if (CPLIsFilenameRelative(osPath.c_str()))
874
897
char* cwd = CPLGetCurrentDir();
877
dirName = CPLFormFilename(cwd, (const char*)dirName, NULL);
900
dirName = CPLFormFilename(cwd, dirName.c_str(), NULL);
881
904
while (dirName[0] != 0 && EQUAL(dirName, ".") == FALSE && EQUAL(dirName, "/") == FALSE)
883
pszImageRepFilename = CPLFormCIFilename( (const char*)dirName, "image", "rep" );
884
if( VSIStatL( (const char*)pszImageRepFilename, &sStatBuf ) == 0 )
885
return pszImageRepFilename;
906
osImageRepFilename = CPLFormCIFilename( dirName.c_str(), "image", "rep" );
907
if( VSIStatExL( osImageRepFilename.c_str(), &sStatBuf, VSI_STAT_EXISTS_FLAG ) == 0 )
908
return osImageRepFilename;
887
910
/* Don't try to recurse above the 'image' subdirectory */
888
911
if (EQUAL(dirName, "image"))
911
934
papszFileList = GDALPamDataset::GetFileList();
914
CPLString osFilename = CPLFormCIFilename( osPath, osName, "hdr" );
937
CPLString osFilename = CPLFormCIFilename( osPath, osName, osHeaderExt );
915
938
papszFileList = CSLAddString( papszFileList, osFilename );
917
940
// Statistics file
918
941
osFilename = CPLFormCIFilename( osPath, osName, "stx" );
919
if( VSIStatL( osFilename, &sStatBuf ) == 0 )
942
if( VSIStatExL( osFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG ) == 0 )
920
943
papszFileList = CSLAddString( papszFileList, osFilename );
922
945
// color table file.
923
946
osFilename = CPLFormCIFilename( osPath, osName, "clr" );
924
if( VSIStatL( osFilename, &sStatBuf ) == 0 )
947
if( VSIStatExL( osFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG ) == 0 )
925
948
papszFileList = CSLAddString( papszFileList, osFilename );
927
950
// projections file.
928
951
osFilename = CPLFormCIFilename( osPath, osName, "prj" );
929
if( VSIStatL( osFilename, &sStatBuf ) == 0 )
952
if( VSIStatExL( osFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG ) == 0 )
930
953
papszFileList = CSLAddString( papszFileList, osFilename );
932
955
CPLString imageRepFilename = GetImageRepFilename( GetDescription() );
933
956
if (!imageRepFilename.empty())
934
papszFileList = CSLAddString( papszFileList, (const char*)imageRepFilename );
957
papszFileList = CSLAddString( papszFileList, imageRepFilename.c_str() );
936
959
return papszFileList;
959
982
CPLString osName = CPLGetBasename( poOpenInfo->pszFilename );
960
983
CPLString osHDRFilename;
985
const char* pszHeaderExt = "hdr";
986
if( EQUAL( CPLGetExtension( poOpenInfo->pszFilename ), "SRC" ) &&
987
osName.size() == 7 &&
988
(osName[0] == 'e' || osName[0] == 'E' || osName[0] == 'w' || osName[0] == 'W') &&
989
(osName[4] == 'n' || osName[4] == 'N' || osName[4] == 's' || osName[4] == 'S') )
991
/* It is a GTOPO30 or SRTM30 source file, whose header extension is .sch */
992
/* see http://dds.cr.usgs.gov/srtm/version1/SRTM30/GTOPO30_Documentation */
993
pszHeaderExt = "sch";
962
996
if( poOpenInfo->papszSiblingFiles )
964
998
int iFile = CSLFindString(poOpenInfo->papszSiblingFiles,
965
CPLFormFilename( NULL, osName, "hdr" ) );
999
CPLFormFilename( NULL, osName, pszHeaderExt ) );
966
1000
if( iFile < 0 ) // return if there is no corresponding .hdr file
975
osHDRFilename = CPLFormCIFilename( osPath, osName, "hdr" );
1009
osHDRFilename = CPLFormCIFilename( osPath, osName, pszHeaderExt );
978
1012
bSelectedHDR = EQUAL( osHDRFilename, poOpenInfo->pszFilename );
1006
1040
char chPixelType = 'N'; // not defined
1007
1041
char szLayout[10] = "BIL";
1008
1042
char **papszHDR = NULL;
1043
int bHasInternalProjection = FALSE;
1044
int bHasMin = FALSE;
1045
int bHasMax = FALSE;
1046
double dfMin = 0, dfMax = 0;
1010
while( (pszLine = CPLReadLineL( fp )) )
1048
while( (pszLine = CPLReadLineL( fp )) != NULL )
1012
1050
char **papszTokens;
1090
1128
else if( EQUAL(papszTokens[0],"PIXELTYPE") )
1092
chPixelType = toupper(papszTokens[1][0]);
1130
chPixelType = (char) toupper(papszTokens[1][0]);
1094
1132
else if( EQUAL(papszTokens[0],"byteorder") )
1096
chByteOrder = toupper(papszTokens[1][0]);
1134
chByteOrder = (char) toupper(papszTokens[1][0]);
1137
/* http://www.worldclim.org/futdown.htm have the projection extensions */
1138
else if( EQUAL(papszTokens[0],"Projection") )
1140
bHasInternalProjection = TRUE;
1142
else if( EQUAL(papszTokens[0],"MinValue") ||
1143
EQUAL(papszTokens[0],"MIN_VALUE") )
1145
dfMin = atof(papszTokens[1]);
1148
else if( EQUAL(papszTokens[0],"MaxValue") ||
1149
EQUAL(papszTokens[0],"MAX_VALUE") )
1151
dfMax = atof(papszTokens[1]);
1099
1155
CSLDestroy( papszTokens );
1194
/* -------------------------------------------------------------------- */
1195
/* If we aren't sure of the file type, check the data file */
1196
/* size. If it is 4 bytes or more per pixel then we assume it */
1197
/* is floating point data. */
1198
/* -------------------------------------------------------------------- */
1138
1199
if( nBits == -1 && chPixelType == 'N' )
1140
1201
VSIStatBufL sStatBuf;
1141
1202
if( VSIStatL( poOpenInfo->pszFilename, &sStatBuf ) == 0 )
1143
size_t nBytes = sStatBuf.st_size/nCols/nRows/nBands;
1204
size_t nBytes = (size_t) (sStatBuf.st_size/nCols/nRows/nBands);
1144
1205
if( nBytes > 0 && nBytes != 3 )
1145
1206
nBits = nBytes*8;
1152
1213
/* -------------------------------------------------------------------- */
1214
/* If the extension is FLT it is likely a floating point file. */
1215
/* -------------------------------------------------------------------- */
1216
if( chPixelType == 'N' )
1218
if( EQUAL( CPLGetExtension( poOpenInfo->pszFilename ), "FLT" ) )
1222
/* -------------------------------------------------------------------- */
1223
/* If we have a negative nodata value, let's assume that the */
1224
/* pixel type is signed. This is necessary for datasets from */
1225
/* http://www.worldclim.org/futdown.htm */
1226
/* -------------------------------------------------------------------- */
1227
if( bNoDataSet && dfNoData < 0 && chPixelType == 'N' )
1232
/* -------------------------------------------------------------------- */
1153
1233
/* Create a corresponding GDALDataset. */
1154
1234
/* -------------------------------------------------------------------- */
1155
1235
EHdrDataset *poDS;
1157
1237
poDS = new EHdrDataset();
1239
poDS->osHeaderExt = pszHeaderExt;
1159
1241
/* -------------------------------------------------------------------- */
1160
1242
/* Capture some information from the file that is of interest. */
1161
1243
/* -------------------------------------------------------------------- */
1183
1265
poDS->eAccess = poOpenInfo->eAccess;
1185
if( chPixelType == 'N' )
1187
if( EQUAL( CPLGetExtension( poOpenInfo->pszFilename ), "FLT" ) )
1191
1267
/* -------------------------------------------------------------------- */
1192
1268
/* Figure out the data type. */
1193
1269
/* -------------------------------------------------------------------- */
1341
1424
const char *pszPrjFilename = CPLFormCIFilename( osPath, osName, "prj" );
1343
1426
fp = VSIFOpenL( pszPrjFilename, "r" );
1428
/* .hdr files from http://www.worldclim.org/futdown.htm have the projection */
1429
/* info in the .hdr file itself ! */
1430
if (fp == NULL && bHasInternalProjection)
1432
pszPrjFilename = osHDRFilename;
1433
fp = VSIFOpenL( pszPrjFilename, "r" );
1344
1436
if( fp != NULL )
1346
1438
char **papszLines;
1381
1473
/* For the specification of SPDF (in French), */
1382
1474
/* see http://eden.ign.fr/download/pub/doc/emabgi/spdf10.pdf/download */
1383
1475
/* -------------------------------------------------------------------- */
1384
CPLString pszImageRepFilename = GetImageRepFilename(poOpenInfo->pszFilename );
1385
if (!pszImageRepFilename.empty())
1476
CPLString szImageRepFilename = GetImageRepFilename(poOpenInfo->pszFilename );
1477
if (!szImageRepFilename.empty())
1387
fp = VSIFOpenL( (const char*)pszImageRepFilename, "r" );
1479
fp = VSIFOpenL( szImageRepFilename.c_str(), "r" );
1389
1481
if (fp != NULL)
1539
1631
int nIndex = atoi( papszValues[0] ); // Index
1540
1632
if (nIndex >= 0 && nIndex < 65536)
1542
oEntry.c1 = atoi( papszValues[1] ); // Red
1543
oEntry.c2 = atoi( papszValues[2] ); // Green
1544
oEntry.c3 = atoi( papszValues[3] ); // Blue
1634
oEntry.c1 = (short) atoi( papszValues[1] ); // Red
1635
oEntry.c2 = (short) atoi( papszValues[2] ); // Green
1636
oEntry.c3 = (short) atoi( papszValues[3] ); // Blue
1545
1637
oEntry.c4 = 255;
1547
1639
oColorTable.SetColorEntry( nIndex, &oEntry );
1780
1872
double EHdrRasterBand::GetMinimum( int *pbSuccess )
1782
1874
if( pbSuccess != NULL )
1783
*pbSuccess = (minmaxmeanstddev & 0x1) != 0;
1875
*pbSuccess = (minmaxmeanstddev & HAS_MIN_FLAG) != 0;
1785
if( minmaxmeanstddev & 0x1 )
1877
if( minmaxmeanstddev & HAS_MIN_FLAG )
1788
1880
return RawRasterBand::GetMinimum( pbSuccess );
1795
1887
double EHdrRasterBand::GetMaximum( int *pbSuccess )
1797
1889
if( pbSuccess != NULL )
1798
*pbSuccess = (minmaxmeanstddev & 0x2) != 0;
1890
*pbSuccess = (minmaxmeanstddev & HAS_MAX_FLAG) != 0;
1800
if( minmaxmeanstddev & 0x2 )
1892
if( minmaxmeanstddev & HAS_MAX_FLAG )
1803
1895
return RawRasterBand::GetMaximum( pbSuccess );
1810
1902
CPLErr EHdrRasterBand::GetStatistics( int bApproxOK, int bForce, double *pdfMin, double *pdfMax, double *pdfMean, double *pdfStdDev )
1812
if( (minmaxmeanstddev & 0xf) == 0xf)
1904
if( (minmaxmeanstddev & HAS_ALL_FLAGS) == HAS_ALL_FLAGS)
1814
1906
if ( pdfMin ) *pdfMin = dfMin;
1815
1907
if ( pdfMax ) *pdfMax = dfMax;
1827
1919
EHdrDataset* poEDS = (EHdrDataset *) poDS;
1829
minmaxmeanstddev = 0xf;
1921
minmaxmeanstddev = HAS_ALL_FLAGS;
1831
1923
if( poEDS->RewriteSTX() != CE_None )
1832
1924
RawRasterBand::SetStatistics( dfMin, dfMax, dfMean, dfStdDev );