LCOV - code coverage report
Current view: top level - frmts/til - tildataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 141 170 82.9 %
Date: 2024-05-07 17:03:27 Functions: 12 13 92.3 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  EarthWatch .TIL Driver
       4             :  * Purpose:  Implementation of the TILDataset class.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2009, Frank Warmerdam
       9             :  * Copyright (c) 2009-2011, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * Permission is hereby granted, free of charge, to any person obtaining a
      12             :  * copy of this software and associated documentation files (the "Software"),
      13             :  * to deal in the Software without restriction, including without limitation
      14             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15             :  * and/or sell copies of the Software, and to permit persons to whom the
      16             :  * Software is furnished to do so, subject to the following conditions:
      17             :  *
      18             :  * The above copyright notice and this permission notice shall be included
      19             :  * in all copies or substantial portions of the Software.
      20             :  *
      21             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27             :  * DEALINGS IN THE SOFTWARE.
      28             :  ****************************************************************************/
      29             : 
      30             : #include "cpl_multiproc.h"
      31             : #include "cpl_string.h"
      32             : #include "cplkeywordparser.h"
      33             : #include "gdal_mdreader.h"
      34             : #include "gdal_frmts.h"
      35             : #include "gdal_pam.h"
      36             : #include "ogr_spatialref.h"
      37             : #include "vrtdataset.h"
      38             : 
      39             : /************************************************************************/
      40             : /* ==================================================================== */
      41             : /*                              TILDataset                              */
      42             : /* ==================================================================== */
      43             : /************************************************************************/
      44             : 
      45             : class TILDataset final : public GDALPamDataset
      46             : {
      47             :     VRTDataset *poVRTDS;
      48             :     std::vector<std::string> m_aosFilenames;
      49             : 
      50             :     char **papszMetadataFiles;
      51             : 
      52             :   protected:
      53             :     virtual int CloseDependentDatasets() override;
      54             : 
      55             :   public:
      56             :     TILDataset();
      57             :     virtual ~TILDataset();
      58             : 
      59             :     virtual char **GetFileList(void) override;
      60             : 
      61             :     static GDALDataset *Open(GDALOpenInfo *);
      62             :     static int Identify(GDALOpenInfo *poOpenInfo);
      63             : };
      64             : 
      65             : /************************************************************************/
      66             : /* ==================================================================== */
      67             : /*                            TILRasterBand                             */
      68             : /* ==================================================================== */
      69             : /************************************************************************/
      70             : 
      71             : class TILRasterBand final : public GDALPamRasterBand
      72             : {
      73             :     friend class TILDataset;
      74             : 
      75             :     VRTSourcedRasterBand *poVRTBand;
      76             : 
      77             :   public:
      78             :     TILRasterBand(TILDataset *, int, VRTSourcedRasterBand *);
      79             : 
      80          10 :     virtual ~TILRasterBand()
      81           5 :     {
      82          10 :     }
      83             : 
      84             :     virtual CPLErr IReadBlock(int, int, void *) override;
      85             :     virtual CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
      86             :                              GDALDataType, GSpacing nPixelSpace,
      87             :                              GSpacing nLineSpace,
      88             :                              GDALRasterIOExtraArg *psExtraArg) override;
      89             : };
      90             : 
      91             : /************************************************************************/
      92             : /*                           TILRasterBand()                            */
      93             : /************************************************************************/
      94             : 
      95           5 : TILRasterBand::TILRasterBand(TILDataset *poTILDS, int nBandIn,
      96           5 :                              VRTSourcedRasterBand *poVRTBandIn)
      97             : 
      98             : {
      99           5 :     poDS = poTILDS;
     100           5 :     poVRTBand = poVRTBandIn;
     101           5 :     nBand = nBandIn;
     102           5 :     eDataType = poVRTBandIn->GetRasterDataType();
     103             : 
     104           5 :     poVRTBandIn->GetBlockSize(&nBlockXSize, &nBlockYSize);
     105           5 : }
     106             : 
     107             : /************************************************************************/
     108             : /*                             IReadBlock()                             */
     109             : /************************************************************************/
     110             : 
     111           0 : CPLErr TILRasterBand::IReadBlock(int iBlockX, int iBlockY, void *pBuffer)
     112             : 
     113             : {
     114           0 :     return poVRTBand->ReadBlock(iBlockX, iBlockY, pBuffer);
     115             : }
     116             : 
     117             : /************************************************************************/
     118             : /*                             IRasterIO()                              */
     119             : /************************************************************************/
     120             : 
     121           2 : CPLErr TILRasterBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
     122             :                                 int nXSize, int nYSize, void *pData,
     123             :                                 int nBufXSize, int nBufYSize,
     124             :                                 GDALDataType eBufType, GSpacing nPixelSpace,
     125             :                                 GSpacing nLineSpace,
     126             :                                 GDALRasterIOExtraArg *psExtraArg)
     127             : 
     128             : {
     129           2 :     if (GetOverviewCount() > 0)
     130             :     {
     131           0 :         return GDALPamRasterBand::IRasterIO(
     132             :             eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
     133           0 :             eBufType, nPixelSpace, nLineSpace, psExtraArg);
     134             :     }
     135             : 
     136             :     // If not exist TIL overviews, try to use band source overviews.
     137           2 :     return poVRTBand->IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
     138             :                                 nBufXSize, nBufYSize, eBufType, nPixelSpace,
     139           2 :                                 nLineSpace, psExtraArg);
     140             : }
     141             : 
     142             : /************************************************************************/
     143             : /* ==================================================================== */
     144             : /*                             TILDataset                               */
     145             : /* ==================================================================== */
     146             : /************************************************************************/
     147             : 
     148             : /************************************************************************/
     149             : /*                             TILDataset()                             */
     150             : /************************************************************************/
     151             : 
     152           5 : TILDataset::TILDataset() : poVRTDS(nullptr), papszMetadataFiles(nullptr)
     153             : {
     154           5 : }
     155             : 
     156             : /************************************************************************/
     157             : /*                            ~TILDataset()                             */
     158             : /************************************************************************/
     159             : 
     160          10 : TILDataset::~TILDataset()
     161             : 
     162             : {
     163           5 :     TILDataset::CloseDependentDatasets();
     164           5 :     CSLDestroy(papszMetadataFiles);
     165          10 : }
     166             : 
     167             : /************************************************************************/
     168             : /*                        CloseDependentDatasets()                      */
     169             : /************************************************************************/
     170             : 
     171           9 : int TILDataset::CloseDependentDatasets()
     172             : {
     173           9 :     int bHasDroppedRef = GDALPamDataset::CloseDependentDatasets();
     174             : 
     175           9 :     if (poVRTDS)
     176             :     {
     177           5 :         bHasDroppedRef = TRUE;
     178           5 :         delete poVRTDS;
     179           5 :         poVRTDS = nullptr;
     180             :     }
     181             : 
     182           9 :     return bHasDroppedRef;
     183             : }
     184             : 
     185             : /************************************************************************/
     186             : /*                              Identify()                              */
     187             : /************************************************************************/
     188             : 
     189       51094 : int TILDataset::Identify(GDALOpenInfo *poOpenInfo)
     190             : 
     191             : {
     192       55383 :     if (poOpenInfo->nHeaderBytes < 200 ||
     193        4289 :         !EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "TIL"))
     194       51084 :         return FALSE;
     195             : 
     196          10 :     if (strstr((const char *)poOpenInfo->pabyHeader, "numTiles") == nullptr)
     197           0 :         return FALSE;
     198             : 
     199          10 :     return TRUE;
     200             : }
     201             : 
     202             : /************************************************************************/
     203             : /*                                Open()                                */
     204             : /************************************************************************/
     205             : 
     206           5 : GDALDataset *TILDataset::Open(GDALOpenInfo *poOpenInfo)
     207             : 
     208             : {
     209           5 :     if (!Identify(poOpenInfo) || poOpenInfo->fpL == nullptr)
     210           0 :         return nullptr;
     211             : 
     212             :     /* -------------------------------------------------------------------- */
     213             :     /*      Confirm the requested access is supported.                      */
     214             :     /* -------------------------------------------------------------------- */
     215           5 :     if (poOpenInfo->eAccess == GA_Update)
     216             :     {
     217           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     218             :                  "The TIL driver does not support update access to existing"
     219             :                  " datasets.\n");
     220           0 :         return nullptr;
     221             :     }
     222             : 
     223          10 :     CPLString osDirname = CPLGetDirname(poOpenInfo->pszFilename);
     224             : 
     225             :     // get metadata reader
     226             : 
     227          10 :     GDALMDReaderManager mdreadermanager;
     228           5 :     GDALMDReaderBase *mdreader = mdreadermanager.GetReader(
     229           5 :         poOpenInfo->pszFilename, poOpenInfo->GetSiblingFiles(), MDR_DG);
     230             : 
     231           5 :     if (nullptr == mdreader)
     232             :     {
     233           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     234             :                  "Unable to open .TIL dataset due to missing metadata file.");
     235           0 :         return nullptr;
     236             :     }
     237             :     /* -------------------------------------------------------------------- */
     238             :     /*      Try to find the corresponding .IMD file.                        */
     239             :     /* -------------------------------------------------------------------- */
     240           5 :     char **papszIMD = mdreader->GetMetadataDomain(MD_DOMAIN_IMD);
     241             : 
     242           5 :     if (papszIMD == nullptr)
     243             :     {
     244           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     245             :                  "Unable to open .TIL dataset due to missing .IMD file.");
     246           0 :         return nullptr;
     247             :     }
     248             : 
     249           5 :     if (CSLFetchNameValue(papszIMD, "numRows") == nullptr ||
     250          10 :         CSLFetchNameValue(papszIMD, "numColumns") == nullptr ||
     251           5 :         CSLFetchNameValue(papszIMD, "bitsPerPixel") == nullptr)
     252             :     {
     253           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     254             :                  "Missing a required field in the .IMD file.");
     255           0 :         return nullptr;
     256             :     }
     257             : 
     258             :     /* -------------------------------------------------------------------- */
     259             :     /*      Try to load and parse the .TIL file.                            */
     260             :     /* -------------------------------------------------------------------- */
     261           5 :     VSILFILE *fp = poOpenInfo->fpL;
     262           5 :     poOpenInfo->fpL = nullptr;
     263             : 
     264          10 :     CPLKeywordParser oParser;
     265             : 
     266           5 :     if (!oParser.Ingest(fp))
     267             :     {
     268           0 :         VSIFCloseL(fp);
     269           0 :         return nullptr;
     270             :     }
     271             : 
     272           5 :     VSIFCloseL(fp);
     273             : 
     274           5 :     char **papszTIL = oParser.GetAllKeywords();
     275             : 
     276             :     /* -------------------------------------------------------------------- */
     277             :     /*      Create a corresponding GDALDataset.                             */
     278             :     /* -------------------------------------------------------------------- */
     279           5 :     TILDataset *poDS = new TILDataset();
     280           5 :     poDS->papszMetadataFiles = mdreader->GetMetadataFiles();
     281           5 :     mdreader->FillMetadata(&poDS->oMDMD);
     282           5 :     poDS->nRasterXSize =
     283           5 :         atoi(CSLFetchNameValueDef(papszIMD, "numColumns", "0"));
     284           5 :     poDS->nRasterYSize = atoi(CSLFetchNameValueDef(papszIMD, "numRows", "0"));
     285           5 :     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
     286             :     {
     287           0 :         delete poDS;
     288           0 :         return nullptr;
     289             :     }
     290             : 
     291             :     /* -------------------------------------------------------------------- */
     292             :     /*      We need to open one of the images in order to establish         */
     293             :     /*      details like the band count and types.                          */
     294             :     /* -------------------------------------------------------------------- */
     295           5 :     const char *pszFilename = CSLFetchNameValue(papszTIL, "TILE_1.filename");
     296           5 :     if (pszFilename == nullptr)
     297             :     {
     298           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     299             :                  "Missing TILE_1.filename in .TIL file.");
     300           0 :         delete poDS;
     301           0 :         return nullptr;
     302             :     }
     303             : 
     304             :     // trim double quotes.
     305           5 :     if (pszFilename[0] == '"')
     306           5 :         pszFilename++;
     307           5 :     if (pszFilename[strlen(pszFilename) - 1] == '"')
     308           5 :         const_cast<char *>(pszFilename)[strlen(pszFilename) - 1] = '\0';
     309             : 
     310          10 :     CPLString osFilename = CPLFormFilename(osDirname, pszFilename, nullptr);
     311             :     GDALDataset *poTemplateDS =
     312           5 :         GDALDataset::FromHandle(GDALOpen(osFilename, GA_ReadOnly));
     313           5 :     if (poTemplateDS == nullptr || poTemplateDS->GetRasterCount() == 0)
     314             :     {
     315           0 :         delete poDS;
     316           0 :         if (poTemplateDS != nullptr)
     317           0 :             GDALClose(poTemplateDS);
     318           0 :         return nullptr;
     319             :     }
     320             : 
     321           5 :     GDALRasterBand *poTemplateBand = poTemplateDS->GetRasterBand(1);
     322           5 :     const GDALDataType eDT = poTemplateBand->GetRasterDataType();
     323           5 :     const int nBandCount = poTemplateDS->GetRasterCount();
     324             : 
     325             :     // we suppose the first tile have the same projection as others (usually so)
     326          10 :     CPLString pszProjection(poTemplateDS->GetProjectionRef());
     327           5 :     if (!pszProjection.empty())
     328           5 :         poDS->SetProjection(pszProjection);
     329             : 
     330             :     // we suppose the first tile have the same GeoTransform as others (usually
     331             :     // so)
     332             :     double adfGeoTransform[6];
     333           5 :     if (poTemplateDS->GetGeoTransform(adfGeoTransform) == CE_None)
     334             :     {
     335             :         // According to
     336             :         // https://www.digitalglobe.com/sites/default/files/ISD_External.pdf,
     337             :         // ulx=originX and is "Easting of the center of the upper left pixel of
     338             :         // the image."
     339           5 :         adfGeoTransform[0] = CPLAtof(CSLFetchNameValueDef(
     340           5 :                                  papszIMD, "MAP_PROJECTED_PRODUCT.ULX", "0")) -
     341           5 :                              adfGeoTransform[1] / 2;
     342           5 :         adfGeoTransform[3] = CPLAtof(CSLFetchNameValueDef(
     343           5 :                                  papszIMD, "MAP_PROJECTED_PRODUCT.ULY", "0")) -
     344           5 :                              adfGeoTransform[5] / 2;
     345           5 :         poDS->SetGeoTransform(adfGeoTransform);
     346             :     }
     347             : 
     348           5 :     poTemplateBand = nullptr;
     349           5 :     GDALClose(poTemplateDS);
     350             : 
     351             :     /* -------------------------------------------------------------------- */
     352             :     /*      Create and initialize the corresponding VRT dataset used to     */
     353             :     /*      manage the tiled data access.                                   */
     354             :     /* -------------------------------------------------------------------- */
     355           5 :     poDS->poVRTDS = new VRTDataset(poDS->nRasterXSize, poDS->nRasterYSize);
     356             : 
     357          10 :     for (int iBand = 0; iBand < nBandCount; iBand++)
     358           5 :         poDS->poVRTDS->AddBand(eDT, nullptr);
     359             : 
     360             :     /* Don't try to write a VRT file */
     361           5 :     poDS->poVRTDS->SetWritable(FALSE);
     362             : 
     363             :     /* -------------------------------------------------------------------- */
     364             :     /*      Create band information objects.                                */
     365             :     /* -------------------------------------------------------------------- */
     366          10 :     for (int iBand = 1; iBand <= nBandCount; iBand++)
     367           5 :         poDS->SetBand(
     368             :             iBand, new TILRasterBand(poDS, iBand,
     369             :                                      reinterpret_cast<VRTSourcedRasterBand *>(
     370           5 :                                          poDS->poVRTDS->GetRasterBand(iBand))));
     371             : 
     372             :     /* -------------------------------------------------------------------- */
     373             :     /*      Add tiles as sources for each band.                             */
     374             :     /* -------------------------------------------------------------------- */
     375             :     const int nTileCount =
     376           5 :         atoi(CSLFetchNameValueDef(papszTIL, "numTiles", "0"));
     377           5 :     int iTile = 0;
     378             : 
     379          10 :     for (iTile = 1; iTile <= nTileCount; iTile++)
     380             :     {
     381           5 :         CPLString osKey;
     382           5 :         osKey.Printf("TILE_%d.filename", iTile);
     383           5 :         pszFilename = CSLFetchNameValue(papszTIL, osKey);
     384           5 :         if (pszFilename == nullptr)
     385             :         {
     386           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     387             :                      "Missing TILE_%d.filename in .TIL file.", iTile);
     388           0 :             delete poDS;
     389           0 :             return nullptr;
     390             :         }
     391             : 
     392             :         // trim double quotes.
     393           5 :         if (pszFilename[0] == '"')
     394           5 :             pszFilename++;
     395           5 :         if (pszFilename[strlen(pszFilename) - 1] == '"')
     396           0 :             const_cast<char *>(pszFilename)[strlen(pszFilename) - 1] = '\0';
     397           5 :         osFilename = CPLFormFilename(osDirname, pszFilename, nullptr);
     398           5 :         poDS->m_aosFilenames.push_back(osFilename);
     399             : 
     400           5 :         osKey.Printf("TILE_%d.ULColOffset", iTile);
     401           5 :         const int nULX = atoi(CSLFetchNameValueDef(papszTIL, osKey, "0"));
     402             : 
     403           5 :         osKey.Printf("TILE_%d.ULRowOffset", iTile);
     404           5 :         const int nULY = atoi(CSLFetchNameValueDef(papszTIL, osKey, "0"));
     405             : 
     406           5 :         osKey.Printf("TILE_%d.LRColOffset", iTile);
     407           5 :         const int nLRX = atoi(CSLFetchNameValueDef(papszTIL, osKey, "0"));
     408             : 
     409           5 :         osKey.Printf("TILE_%d.LRRowOffset", iTile);
     410           5 :         const int nLRY = atoi(CSLFetchNameValueDef(papszTIL, osKey, "0"));
     411             : 
     412          10 :         for (int iBand = 1; iBand <= nBandCount; iBand++)
     413             :         {
     414             :             VRTSourcedRasterBand *poVRTBand =
     415             :                 reinterpret_cast<VRTSourcedRasterBand *>(
     416           5 :                     poDS->poVRTDS->GetRasterBand(iBand));
     417             : 
     418           5 :             poVRTBand->AddSimpleSource(osFilename, iBand, 0, 0, nLRX - nULX + 1,
     419           5 :                                        nLRY - nULY + 1, nULX, nULY,
     420           5 :                                        nLRX - nULX + 1, nLRY - nULY + 1);
     421             :         }
     422             :     }
     423             : 
     424             :     /* -------------------------------------------------------------------- */
     425             :     /*      Initialize any PAM information.                                 */
     426             :     /* -------------------------------------------------------------------- */
     427           5 :     poDS->SetDescription(poOpenInfo->pszFilename);
     428           5 :     poDS->TryLoadXML();
     429             : 
     430             :     /* -------------------------------------------------------------------- */
     431             :     /*      Check for overviews.                                            */
     432             :     /* -------------------------------------------------------------------- */
     433           5 :     poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename);
     434             : 
     435           5 :     return poDS;
     436             : }
     437             : 
     438             : /************************************************************************/
     439             : /*                            GetFileList()                             */
     440             : /************************************************************************/
     441             : 
     442           3 : char **TILDataset::GetFileList()
     443             : 
     444             : {
     445           3 :     char **papszFileList = GDALPamDataset::GetFileList();
     446             : 
     447           6 :     for (const auto &osFilename : m_aosFilenames)
     448           3 :         papszFileList = CSLAddString(papszFileList, osFilename.c_str());
     449             : 
     450           3 :     if (nullptr != papszMetadataFiles)
     451             :     {
     452           6 :         for (int i = 0; papszMetadataFiles[i] != nullptr; i++)
     453             :         {
     454           3 :             papszFileList = CSLAddString(papszFileList, papszMetadataFiles[i]);
     455             :         }
     456             :     }
     457             : 
     458           3 :     return papszFileList;
     459             : }
     460             : 
     461             : /************************************************************************/
     462             : /*                          GDALRegister_TIL()                          */
     463             : /************************************************************************/
     464             : 
     465        1520 : void GDALRegister_TIL()
     466             : 
     467             : {
     468        1520 :     if (GDALGetDriverByName("TIL") != nullptr)
     469         301 :         return;
     470             : 
     471        1219 :     GDALDriver *poDriver = new GDALDriver();
     472             : 
     473        1219 :     poDriver->SetDescription("TIL");
     474        1219 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     475        1219 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "EarthWatch .TIL");
     476        1219 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/til.html");
     477        1219 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     478             : 
     479        1219 :     poDriver->pfnOpen = TILDataset::Open;
     480        1219 :     poDriver->pfnIdentify = TILDataset::Identify;
     481             : 
     482        1219 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     483             : }

Generated by: LCOV version 1.14