From cdc20de9ff63bb1c2566c317865058d9dbc83db3 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Thu, 17 Oct 2019 19:05:06 +0200 Subject: [PATCH] VICAR: support reading more data types and pixel organization (refs #1855) - Support FORMAT=HALF, DOUB and COMP - Support big-endian order for integer & floating point values - Support BIP and BIL organizations - Ignore binary label records (NBL), and properly skip binary prefixes (NBB) - Add tests --- autotest/cpp/test_gdal.cpp | 2 +- autotest/gdrivers/data/vicar_byte.vic | Bin 0 -> 492 bytes autotest/gdrivers/data/vicar_cfloat32.vic | Bin 0 -> 608 bytes autotest/gdrivers/data/vicar_float32_bil.vic | Bin 0 -> 592 bytes autotest/gdrivers/data/vicar_float32_bip.vic | Bin 0 -> 584 bytes autotest/gdrivers/data/vicar_float32_bsq.vic | Bin 0 -> 592 bytes autotest/gdrivers/data/vicar_float64.vic | Bin 0 -> 576 bytes autotest/gdrivers/data/vicar_int16.vic | Bin 0 -> 512 bytes autotest/gdrivers/data/vicar_int32.vic | Bin 0 -> 544 bytes autotest/gdrivers/vicar.py | 22 +- gdal/frmts/pds/vicardataset.cpp | 345 +++++++++---------- gdal/frmts/pds/vicardataset.h | 81 +++++ gdal/frmts/pds/vicarkeywordhandler.cpp | 16 +- gdal/frmts/pds/vicarkeywordhandler.h | 6 + 14 files changed, 268 insertions(+), 204 deletions(-) create mode 100644 autotest/gdrivers/data/vicar_byte.vic create mode 100644 autotest/gdrivers/data/vicar_cfloat32.vic create mode 100644 autotest/gdrivers/data/vicar_float32_bil.vic create mode 100644 autotest/gdrivers/data/vicar_float32_bip.vic create mode 100644 autotest/gdrivers/data/vicar_float32_bsq.vic create mode 100644 autotest/gdrivers/data/vicar_float64.vic create mode 100644 autotest/gdrivers/data/vicar_int16.vic create mode 100644 autotest/gdrivers/data/vicar_int32.vic create mode 100644 gdal/frmts/pds/vicardataset.h diff --git a/autotest/cpp/test_gdal.cpp b/autotest/cpp/test_gdal.cpp index 8daebe9e66cf..e46f0a4cd8a0 100644 --- a/autotest/cpp/test_gdal.cpp +++ b/autotest/cpp/test_gdal.cpp @@ -1278,7 +1278,7 @@ namespace tut ensure_equals( static_cast(sLayout.eInterleaving), static_cast(GDALDataset::RawBinaryLayout::Interleaving::UNKNOWN) ); ensure_equals( sLayout.eDataType, GDT_Byte ); - ensure( !sLayout.bLittleEndianOrder ); + ensure( sLayout.bLittleEndianOrder ); ensure_equals( sLayout.nImageOffset, 9680U ); ensure_equals( sLayout.nPixelOffset, 1 ); ensure_equals( sLayout.nLineOffset, 400 ); diff --git a/autotest/gdrivers/data/vicar_byte.vic b/autotest/gdrivers/data/vicar_byte.vic new file mode 100644 index 0000000000000000000000000000000000000000..d6e41cd544315a6898f4685ca6562e1cc4711e14 GIT binary patch literal 492 zcma)2xlY6|6y)kSI*#&nu7ctu3Ja18J8^=AkHvPvE)4|@9RLN^j>*X}ddi=y`mJI8YMbzQDbH0=)s+-Zi)z ls7iW^Z>gE%sIM_iP`2A3oDHHfk@(*&XP$1;l%e*h@SXA=Mb literal 0 HcmV?d00001 diff --git a/autotest/gdrivers/data/vicar_cfloat32.vic b/autotest/gdrivers/data/vicar_cfloat32.vic new file mode 100644 index 0000000000000000000000000000000000000000..eefd992b98600b29e780a2f035c210d775acfbe6 GIT binary patch literal 608 zcmZvZJx{|h5Qg(pZgY{^%1%QGNEUTcw^;Q@vC~pmKw@EI;A7^eFfuYS^3%9WBGd}3 zMDKf#?=BbHRyLU%Ehl9G`)d)RQ;lSGaBBw8T(7lc#;K*osM;*BNanmKIl$aFIRVhY zN&ygc-8IYsLR?B#rAsXFmU4WO_!(bOq8F{tTRv$?A+epWs#a_(7a`#kyK*|379(r? z4tp8jEF4lBt}u#P**1(u>vp=XW~+9itxGiSVL|mPOE%d;Zn)Z`Ajh?eACQ<^J`8*(xgsV$6qp%#Q$) i@pTs?!x)d6V%!{d01xpX!G-z8205UNt_48$cl`k4V|qRS literal 0 HcmV?d00001 diff --git a/autotest/gdrivers/data/vicar_float32_bil.vic b/autotest/gdrivers/data/vicar_float32_bil.vic new file mode 100644 index 0000000000000000000000000000000000000000..8fcb7278adb34c8aeb036330a01c060369c52f4a GIT binary patch literal 592 zcma)(xlY6|5QhCI)1_JzCn1EDEQqt-T?@xXaduf~C}`*?IBFh;f`Wnvpyqf5j#uF5 z`E3rd9hN@(_l##W<1x~By{AN8R`hp`UDwvVNIF%Ugs9)$RwB`DJyE#H*%(10ON%Nc z8tGQ#M9LY#i8|H9guEnj-9#i(hXmGyH`a>+yA&CA9(5LV9=(M?IxA&7OgyH}ql!gU z4$5L+v|S*Vw*9z;)wmtpLWS|#X{BOyUorD~F_^bLl)D@teK-S77pRMH=wk~=sdzDB$p=GCw$ tC`) sqiMpov4dV#_`*I4y|%ST`U6Vw=C$BS2;v=s8STc67seqa-hw5*0n6chYybcN literal 0 HcmV?d00001 diff --git a/autotest/gdrivers/data/vicar_float32_bsq.vic b/autotest/gdrivers/data/vicar_float32_bsq.vic new file mode 100644 index 0000000000000000000000000000000000000000..129228c7a78b66b6b7c8c29827a7727076a5d22b GIT binary patch literal 592 zcma)(J5Izf5Qcq}=~69| zk#0p!q?{3)s8dZ$$V(#EO++I7HbSfkKGur@yA&CA9(5M&d9)M)>8zCTF!9)M9#zb% za!?inqwO5IwC%?&tj6u&7AlO_PAe6wTg1%j`C!)iQ10IV`4a(`@N5>{K{l@4>Xi2) zvCf8E$~BsYa)QW$=xe_zl8Lf-oqE-Y61b0?*(Dyn;9I4nCy$nkUcx&T~}v`#lDg^oOV94o--#5HE*$HOx!O sQof27^sL4Rm(Zlwwh`&lG7-MK5j+h>d}EMNw{A2w4lb}0p_%XX36NZTuK)l5 literal 0 HcmV?d00001 diff --git a/autotest/gdrivers/data/vicar_float64.vic b/autotest/gdrivers/data/vicar_float64.vic new file mode 100644 index 0000000000000000000000000000000000000000..b8bc10855bac3dbc70a460a64182f2800e6725a0 GIT binary patch literal 576 zcmZXR%}&EG499om$Rqef5Mrq9O4lJpENQb6k<2V{qZXg&PMxo|{L&Nh7ogtJ2SQ zZ0BD`apmQ+po_MKL)%!VS)io1BPRgiX)7p^nhgRYK5npyRz=+w0KL?70U)fRC4dv% zG_V4&ZlHww2W&Aa))-Im8pC6uDU)BN{32y)isKCD2`b^vdQ`D*n|V{ul{9;tB~939 z%qshckrPa%&`BYZx~XT!_VbxB1|7;EAzVLMqyInk-2 z6PUlJWDo{VM=u;D-|rvj_bj{w+yn`4UtnK9pBhP!;70YvhjMj;?UZ?AU&8 zbG)8-l6jhWmU*6ek$IVUo!MkAGuySw@4IRaUl+hj(@j!vspu6^6)q|#we3e`Y0Can HJ3Fvnp<`?! literal 0 HcmV?d00001 diff --git a/autotest/gdrivers/data/vicar_int16.vic b/autotest/gdrivers/data/vicar_int16.vic new file mode 100644 index 0000000000000000000000000000000000000000..47bd795b802213cec3ae3625dfbfc6bc549823e5 GIT binary patch literal 512 zcma)3xl+S05EVzq(Q%aORE4n|j|t3dAvtoQK}V2e6KE)C=qNb8pOuoygpM7L_4aAs z>S<-9iTXvsw4KrY=zXvv0b2^wGfLC*N&(YWEEHyP=urf9)yyhN=i0)QQsoVBN`vZ3 zLu}{60+@`CsBk8ixCjmYWv+9);JWbB!Zd*0oRnoTWm)=&Cf2id(l!&L-5PsomwJn= z@lTiqg${EXv{J>~Ml*`_WVA86{VR|=1(xJ(v$-6?&f8T`F#>bm@sPcki}adsz%0Fg wQ~&lw`7Pz`eS=>^>x$pu*?JT>`WqBR?Ya%ZSs|)2iTB@<*3Spyp|D%azj*^@{Qv*} literal 0 HcmV?d00001 diff --git a/autotest/gdrivers/data/vicar_int32.vic b/autotest/gdrivers/data/vicar_int32.vic new file mode 100644 index 0000000000000000000000000000000000000000..f9067b0c361ca303b39b1353d7f54153c3cec81f GIT binary patch literal 544 zcma)3xl+S05asGPI*xKXRbed0V*)cOEL#p5bOgx`frf&Hj)LR+c~UYAp+e(ly?xr< zdD0qbqJC0hTF>bB>V2@yAXq;d!-$5*g%V8LX08y)u}6_8i)vO7b=rz4k@7}xqM+K` zkk>>$%mtJ29wpAC92Z4}zf6gaXI^G~nw3hRos%+eCU3Vs!o_M(#2B4r{& z6Ym6@D~HoDsvy|c+dKHq|JE+j_JDoh05}AWfMehUI0eptbKn9noB8l^dp=z=JP&wy zHoSh4fB7JOMZCVL@Ksb6{2G?@vcX6$VLEEpt{I*XtVklBWg}YOjmC?t{<+CFK#^xm literal 0 HcmV?d00001 diff --git a/autotest/gdrivers/vicar.py b/autotest/gdrivers/vicar.py index 637f6ed45900..3bbafe4926bf 100755 --- a/autotest/gdrivers/vicar.py +++ b/autotest/gdrivers/vicar.py @@ -73,6 +73,26 @@ def test_vicar_1(): for key in expected_md: assert md[key] == expected_md[key] - +read_datatypes_lists = [ + ('vicar_byte', gdal.GDT_Byte, 129), + ('vicar_int16', gdal.GDT_Int16, 129), + ('vicar_int32', gdal.GDT_Int32, 129), + ('vicar_float32_bsq', gdal.GDT_Float32, 123), + ('vicar_float32_bil', gdal.GDT_Float32, 123), + ('vicar_float32_bip', gdal.GDT_Float32, 123), + ('vicar_float64', gdal.GDT_Float64, 129), + ('vicar_cfloat32', gdal.GDT_CFloat32, 148), +] +@pytest.mark.parametrize( + 'filename,dt,checksum', + read_datatypes_lists, + ids=[tup[0] for tup in read_datatypes_lists], +) +def test_vicar_read_datatypes(filename, dt, checksum): + + ds = gdal.Open('data/%s.vic' % filename) + b = ds.GetRasterBand(1) + assert b.DataType == dt + assert b.Checksum() == checksum diff --git a/gdal/frmts/pds/vicardataset.cpp b/gdal/frmts/pds/vicardataset.cpp index ab9c3a51a447..a89e17082df2 100644 --- a/gdal/frmts/pds/vicardataset.cpp +++ b/gdal/frmts/pds/vicardataset.cpp @@ -32,77 +32,15 @@ constexpr int NULL1 = 0; constexpr int NULL2 = -32768; constexpr double NULL3 = -32768.0; -#include "cpl_string.h" -#include "gdal_frmts.h" -#include "ogr_spatialref.h" -#include "rawdataset.h" +#include "cpl_port.h" +#include "cpl_safemaths.hpp" +#include "vicardataset.h" #include "vicarkeywordhandler.h" #include CPL_CVSID("$Id$") -/************************************************************************/ -/* ==================================================================== */ -/* VICARDataset */ -/* ==================================================================== */ -/************************************************************************/ - -class VICARDataset final: public RawDataset -{ - VSILFILE *fpImage; - - GByte abyHeader[10000]; - CPLString osExternalCube; - - VICARKeywordHandler oKeywords; - - int bGotTransform; - double adfGeoTransform[6]; - - CPLString osProjection; - - const char *GetKeyword( const char *pszPath, - const char *pszDefault = ""); - -public: - VICARDataset(); - virtual ~VICARDataset(); - - virtual CPLErr GetGeoTransform( double * padfTransform ) override; - virtual const char *_GetProjectionRef(void) override; - const OGRSpatialReference* GetSpatialRef() const override { - return GetSpatialRefFromOldGetProjectionRef(); - } - - virtual char **GetFileList() override; - - bool GetRawBinaryLayout(GDALDataset::RawBinaryLayout&) override; - - static int Identify( GDALOpenInfo * ); - static GDALDataset *Open( GDALOpenInfo * ); - static GDALDataset *Create( const char * pszFilename, - int nXSize, int nYSize, int nBands, - GDALDataType eType, char ** papszParmList ); -}; - -/************************************************************************/ -/* VICARDataset() */ -/************************************************************************/ - -VICARDataset::VICARDataset() : - fpImage(nullptr), - bGotTransform(FALSE) -{ - adfGeoTransform[0] = 0.0; - adfGeoTransform[1] = 1.0; - adfGeoTransform[2] = 0.0; - adfGeoTransform[3] = 0.0; - adfGeoTransform[4] = 0.0; - adfGeoTransform[5] = 1.0; - memset( abyHeader, 0, sizeof(abyHeader) ); -} - /************************************************************************/ /* ~VICARDataset() */ /************************************************************************/ @@ -115,21 +53,6 @@ VICARDataset::~VICARDataset() VSIFCloseL( fpImage ); } -/************************************************************************/ -/* GetFileList() */ -/************************************************************************/ - -char **VICARDataset::GetFileList() - -{ - char **papszFileList = GDALPamDataset::GetFileList(); - - if( !osExternalCube.empty() ) - papszFileList = CSLAddString( papszFileList, osExternalCube ); - - return papszFileList; -} - /************************************************************************/ /* GetProjectionRef() */ /************************************************************************/ @@ -152,7 +75,7 @@ CPLErr VICARDataset::GetGeoTransform( double * padfTransform ) { if( bGotTransform ) { - memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 ); + memcpy( padfTransform, &adfGeoTransform[0], sizeof(double) * 6 ); return CE_None; } @@ -202,45 +125,18 @@ GDALDataset *VICARDataset::Open( GDALOpenInfo * poOpenInfo ) if( !Identify( poOpenInfo ) || poOpenInfo->fpL == nullptr ) return nullptr; - VSILFILE *fpQube = poOpenInfo->fpL; - poOpenInfo->fpL = nullptr; - VICARDataset *poDS = new VICARDataset(); - if( ! poDS->oKeywords.Ingest( fpQube, poOpenInfo->pabyHeader ) ) { - VSIFCloseL( fpQube ); - delete poDS; - return nullptr; - } - - VSIFCloseL( fpQube ); - - /***** CHECK ENDIANNESS **************/ - - const char *value = poDS->GetKeyword( "INTFMT" ); - if (!EQUAL(value,"LOW") ) { - CPLError( CE_Failure, CPLE_OpenFailed, - "%s layout not supported. Abort\n\n", value); - delete poDS; - return nullptr; - } - value = poDS->GetKeyword( "REALFMT" ); - if (!EQUAL(value,"RIEEE") ) { - CPLError( CE_Failure, CPLE_OpenFailed, - "%s layout not supported. Abort\n\n", value); + poDS->fpImage = poOpenInfo->fpL; + poOpenInfo->fpL = nullptr; + if( ! poDS->oKeywords.Ingest( poDS->fpImage, poOpenInfo->pabyHeader ) ) { delete poDS; return nullptr; } - char chByteOrder = 'M'; - value = poDS->GetKeyword( "BREALFMT" ); - if (EQUAL(value,"VAX") ) { - chByteOrder = 'I'; - } - /************ CHECK INSTRUMENT/DATA *****************/ bool bIsDTM = false; - value = poDS->GetKeyword( "DTM.DTM_OFFSET" ); + const char* value = poDS->GetKeyword( "DTM.DTM_OFFSET" ); if (!EQUAL(value,"") ) { bIsDTM = true; } @@ -253,61 +149,81 @@ GDALDataset *VICARDataset::Open( GDALOpenInfo * poOpenInfo ) else if ( EQUAL(poDS->GetKeyword("INSTRUMENT_ID"),"FC2") ) bInstKnown = true; - /*********** Grab layout type (BSQ, BIP, BIL) ************/ + /************ Grab dimensions *****************/ - char szLayout[10] = "BSQ"; //default to band seq. - value = poDS->GetKeyword( "ORG" ); - if (!EQUAL(value,"BSQ") ) + const int nCols = atoi(poDS->GetKeyword("NS")); + const int nRows = atoi(poDS->GetKeyword("NL")); + const int nBands = atoi(poDS->GetKeyword("NB")); + + if( !GDALCheckDatasetDimensions(nCols, nRows) || + !GDALCheckBandCount(nBands, false) ) { - CPLError( CE_Failure, CPLE_OpenFailed, - "%s layout not supported. Abort\n\n", value); + CPLError( CE_Failure, CPLE_AppDefined, + "File %s appears to be a VICAR file, but failed to find some " + "required keywords.", + poDS->GetDescription() ); delete poDS; return nullptr; } - strcpy(szLayout,"BSQ"); - const int nCols = atoi(poDS->GetKeyword("NS")); - const int nRows = atoi(poDS->GetKeyword("NL")); - const int nBands = atoi(poDS->GetKeyword("NB")); - - /*********** Grab record bytes **********/ - GDALDataType eDataType = GDT_Byte; + const GDALDataType eDataType = GetDataTypeFromFormat(poDS->GetKeyword( "FORMAT" )); + if( eDataType == GDT_Unknown ) + { + CPLError( CE_Failure, CPLE_AppDefined, + "Could not find known VICAR label entries!\n"); + delete poDS; + return nullptr; + } double dfNoData = 0.0; - if (EQUAL( poDS->GetKeyword( "FORMAT" ), "BYTE" )) { - eDataType = GDT_Byte; + if (eDataType == GDT_Byte) { dfNoData = NULL1; } - else if (EQUAL( poDS->GetKeyword( "FORMAT" ), "HALF" )) { - eDataType = GDT_Int16; + else if (eDataType == GDT_Int16) { dfNoData = NULL2; - chByteOrder = 'I'; - } - else if (EQUAL( poDS->GetKeyword( "FORMAT" ), "FULL" )) { - eDataType = GDT_UInt32; - dfNoData = 0; } - else if (EQUAL( poDS->GetKeyword( "FORMAT" ), "REAL" )) { - eDataType = GDT_Float32; + else if (eDataType == GDT_Float32) { dfNoData = NULL3; - chByteOrder = 'I'; - } - else { - CPLError( CE_Failure, CPLE_AppDefined, - "Could not find known VICAR label entries!\n"); - delete poDS; - return nullptr; } - if( !GDALCheckDatasetDimensions(nCols, nRows) || - !GDALCheckBandCount(nBands, false) ) + /***** CHECK ENDIANNESS **************/ + + bool bIsLSB = true; + if( GDALDataTypeIsInteger(eDataType) ) { - CPLError( CE_Failure, CPLE_AppDefined, - "File %s appears to be a VICAR file, but failed to find some " - "required keywords.", - poDS->GetDescription() ); - delete poDS; - return nullptr; + value = poDS->GetKeyword( "INTFMT", "LOW" ); + if (EQUAL(value,"LOW") ) { + bIsLSB = true; + } + else if( EQUAL(value, "HIGH") ) { + bIsLSB = false; + } + else + { + CPLError( CE_Failure, CPLE_NotSupported, + "INTFMT=%s layout not supported.", value); + delete poDS; + return nullptr; + } } + else + { + value = poDS->GetKeyword( "REALFMT", "VAX" ); + if (EQUAL(value,"RIEEE") ) { + bIsLSB = true; + } + else if (EQUAL(value,"IEEE") ) { + bIsLSB = false; + } + else + { + // TODO: add support for VAX + CPLError( CE_Failure, CPLE_NotSupported, + "REALFMT=%s layout not supported.", value); + delete poDS; + return nullptr; + } + } + /* -------------------------------------------------------------------- */ /* Capture some information from the file that is of interest. */ /* -------------------------------------------------------------------- */ @@ -563,54 +479,74 @@ GDALDataset *VICARDataset::Open( GDALOpenInfo * poOpenInfo ) poDS->adfGeoTransform[5] = dfYDim; } - const CPLString osQubeFile = poOpenInfo->pszFilename; if( !poDS->bGotTransform ) - poDS->bGotTransform = - GDALReadWorldFile( osQubeFile, "psw", - poDS->adfGeoTransform ); + poDS->bGotTransform = CPL_TO_BOOL( + GDALReadWorldFile( poOpenInfo->pszFilename, "wld", + &poDS->adfGeoTransform[0] )); - if( !poDS->bGotTransform ) - poDS->bGotTransform = - GDALReadWorldFile( osQubeFile, "wld", - poDS->adfGeoTransform ); + poDS->eAccess = poOpenInfo->eAccess; /* -------------------------------------------------------------------- */ -/* Open target binary file. */ +/* Compute the line offsets. */ /* -------------------------------------------------------------------- */ - if( poOpenInfo->eAccess == GA_ReadOnly ) - poDS->fpImage = VSIFOpenL( osQubeFile, "r" ); - else - poDS->fpImage = VSIFOpenL( osQubeFile, "r+" ); - if( poDS->fpImage == nullptr ) + const GUInt64 nItemSize = GDALGetDataTypeSizeBytes(eDataType); + value = poDS->GetKeyword( "ORG", "BSQ" ); + // number of bytes of binary prefix before each record + const GUInt64 nNBB = atoi(poDS->GetKeyword("NBB")); + GUInt64 nPixelOffset; + GUInt64 nLineOffset; + GUInt64 nBandOffset; + const GUInt64 nCols64 = nCols; + const GUInt64 nRows64 = nRows; + const GUInt64 nBands64 = nBands; + try + { + if (EQUAL(value,"BIP") ) + { + nPixelOffset = (CPLSM(nItemSize) * CPLSM(nBands64)).v(); + nBandOffset = nItemSize; + nLineOffset = (CPLSM(nNBB) + CPLSM(nPixelOffset) * CPLSM(nCols64)).v(); + } + else if (EQUAL(value,"BIL") ) + { + nPixelOffset = nItemSize; + nBandOffset = (CPLSM(nItemSize) * CPLSM(nCols64)).v(); + nLineOffset = (CPLSM(nNBB) + CPLSM(nBandOffset) * CPLSM(nBands64)).v(); + } + else if (EQUAL(value,"BSQ") ) + { + nPixelOffset = nItemSize; + nLineOffset = (CPLSM(nNBB) + CPLSM(nPixelOffset) * CPLSM(nCols64)).v(); + nBandOffset = (CPLSM(nLineOffset) * CPLSM(nRows64)).v(); + } + else + { + CPLError( CE_Failure, CPLE_NotSupported, + "ORG=%s layout not supported.", value); + delete poDS; + return nullptr; + } + } + catch( const CPLSafeIntOverflow& ) { - CPLError( CE_Failure, CPLE_OpenFailed, - "Failed to open %s with write permission.\n%s", - osQubeFile.c_str(), - VSIStrerror( errno ) ); delete poDS; return nullptr; } - poDS->eAccess = poOpenInfo->eAccess; - -/* -------------------------------------------------------------------- */ -/* Compute the line offsets. */ -/* -------------------------------------------------------------------- */ - - const int nItemSize = GDALGetDataTypeSizeBytes(eDataType); - const int nPixelOffset = nItemSize; - const int nNBB = atoi(poDS->GetKeyword("NBB")); - if( nPixelOffset > INT_MAX / nCols || nNBB < 0 || - nPixelOffset * nCols > INT_MAX - nNBB ) + const GUInt64 nLabelSize = atoi(poDS->GetKeyword("LBLSIZE")); + const GUInt64 nRecordSize = atoi(poDS->GetKeyword("RECSIZE")); + const GUInt64 nNLB = atoi(poDS->GetKeyword("NLB")); + GUInt64 nSkipBytes; + try + { + nSkipBytes = (CPLSM(nLabelSize) + CPLSM(nRecordSize) * CPLSM(nNLB) + CPLSM(nNBB)).v(); + } + catch( const CPLSafeIntOverflow& ) { delete poDS; return nullptr; } - const int nLineOffset = nPixelOffset * nCols + nNBB; - const vsi_l_offset nBandOffset = static_cast(nLineOffset) * nRows; - - int nSkipBytes = atoi(poDS->GetKeyword("LBLSIZE")); /* -------------------------------------------------------------------- */ /* Create band information objects. */ @@ -618,14 +554,18 @@ GDALDataset *VICARDataset::Open( GDALOpenInfo * poOpenInfo ) for( int i = 0; i < nBands; i++ ) { GDALRasterBand *poBand - = new RawRasterBand( poDS, i+1, poDS->fpImage, nSkipBytes + nBandOffset * i, - nPixelOffset, nLineOffset, eDataType, + = new RawRasterBand( poDS, i+1, poDS->fpImage, + static_cast( + nSkipBytes + nBandOffset * i), + static_cast(nPixelOffset), + static_cast(nLineOffset), + eDataType, #ifdef CPL_LSB - chByteOrder == 'I' || chByteOrder == 'L', + bIsLSB, #else - chByteOrder == 'M', + !bIsLSB, #endif - RawRasterBand::OwnFP::NO ); + RawRasterBand::OwnFP::NO ); poDS->SetBand( i+1, poBand ); //only set NoData if instrument is supported @@ -802,6 +742,33 @@ const char *VICARDataset::GetKeyword( const char *pszPath, return oKeywords.GetKeyword( pszPath, pszDefault ); } +/************************************************************************/ +/* GetDataTypeFromFormat() */ +/************************************************************************/ + +GDALDataType VICARDataset::GetDataTypeFromFormat(const char* pszFormat) +{ + if (EQUAL( pszFormat, "BYTE" )) + return GDT_Byte; + + if (EQUAL( pszFormat, "HALF" ) || EQUAL( pszFormat, "WORD") ) + return GDT_Int16; + + if (EQUAL( pszFormat, "FULL" ) || EQUAL( pszFormat, "LONG") ) + return GDT_Int32; + + if (EQUAL( pszFormat, "REAL" )) + return GDT_Float32; + + if (EQUAL( pszFormat, "DOUB" )) + return GDT_Float64; + + if (EQUAL( pszFormat, "COMP" ) || EQUAL( pszFormat, "COMPLEX" )) + return GDT_CFloat32; + + return GDT_Unknown; +} + /************************************************************************/ /* GDALRegister_VICAR() */ /************************************************************************/ diff --git a/gdal/frmts/pds/vicardataset.h b/gdal/frmts/pds/vicardataset.h new file mode 100644 index 000000000000..977948c011a4 --- /dev/null +++ b/gdal/frmts/pds/vicardataset.h @@ -0,0 +1,81 @@ +/****************************************************************************** + * + * Project: VICAR Driver; JPL/MIPL VICAR Format + * Purpose: Implementation of VICARDataset + * Author: Even Rouault, + * + ****************************************************************************** + * Copyright (c) 2014, Sebastian Walter + * Copyright (c) 2019, Even Rouault, + * + * 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. + ****************************************************************************/ + +#ifndef VICARDATASET_H +#define VICARDATASET_H + +#include "cpl_string.h" +#include "gdal_frmts.h" +#include "ogr_spatialref.h" +#include "rawdataset.h" +#include "vicarkeywordhandler.h" +#include + +/************************************************************************/ +/* ==================================================================== */ +/* VICARDataset */ +/* ==================================================================== */ +/************************************************************************/ + +class VICARDataset final: public RawDataset +{ + VSILFILE *fpImage = nullptr; + + VICARKeywordHandler oKeywords; + + bool bGotTransform = false; + std::array adfGeoTransform = {{0.0,1.0,0,0.0,0.0,1.0}}; + + CPLString osProjection; + + const char *GetKeyword( const char *pszPath, + const char *pszDefault = ""); + +public: + VICARDataset() = default; + virtual ~VICARDataset(); + + virtual CPLErr GetGeoTransform( double * padfTransform ) override; + virtual const char *_GetProjectionRef(void) override; + const OGRSpatialReference* GetSpatialRef() const override { + return GetSpatialRefFromOldGetProjectionRef(); + } + + bool GetRawBinaryLayout(GDALDataset::RawBinaryLayout&) override; + + static int Identify( GDALOpenInfo * ); + static GDALDataset *Open( GDALOpenInfo * ); + static GDALDataset *Create( const char * pszFilename, + int nXSize, int nYSize, int nBands, + GDALDataType eType, char ** papszParmList ); + + static GDALDataType GetDataTypeFromFormat(const char* pszFormat); +}; + +#endif // VICARDATASET_H diff --git a/gdal/frmts/pds/vicarkeywordhandler.cpp b/gdal/frmts/pds/vicarkeywordhandler.cpp index 4d97be4352df..9c0bf50f4275 100644 --- a/gdal/frmts/pds/vicarkeywordhandler.cpp +++ b/gdal/frmts/pds/vicarkeywordhandler.cpp @@ -31,6 +31,7 @@ #include "cpl_string.h" #include "vicarkeywordhandler.h" +#include "vicardataset.h" #include @@ -131,20 +132,9 @@ int VICARKeywordHandler::Ingest( VSILFILE *fp, GByte *pabyHeader ) /* There is a EOL! e.G. h4231_0000.nd4.06 */ /* -------------------------------------------------------------------- */ - vsi_l_offset nPixelOffset=0; const char* pszFormat = CSLFetchNameValueDef(papszKeywordList,"FORMAT",""); - if (EQUAL( pszFormat, "BYTE" )) { - nPixelOffset = 1; - } - else if (EQUAL( pszFormat, "HALF" )) { - nPixelOffset = 2; - } - else if (EQUAL( pszFormat, "FULL" )) { - nPixelOffset = 4; - } - else if (EQUAL( pszFormat, "REAL" )) { - nPixelOffset = 4; - } + vsi_l_offset nPixelOffset= GDALGetDataTypeSizeBytes( + VICARDataset::GetDataTypeFromFormat(pszFormat)); if( nPixelOffset == 0 ) return FALSE; diff --git a/gdal/frmts/pds/vicarkeywordhandler.h b/gdal/frmts/pds/vicarkeywordhandler.h index c5ef7fc4943b..aa310bdc719a 100644 --- a/gdal/frmts/pds/vicarkeywordhandler.h +++ b/gdal/frmts/pds/vicarkeywordhandler.h @@ -28,6 +28,10 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ****************************************************************************/ + +#ifndef VICARKEYWORDHANDLER_H +#define VICARKEYWORDHANDLER_H + class VICARKeywordHandler { char **papszKeywordList; @@ -51,3 +55,5 @@ class VICARKeywordHandler const char *GetKeyword( const char *pszPath, const char *pszDefault ); char **GetKeywordList(); }; + +#endif // VICARKEYWORDHANDLER_H