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

Generated by: LCOV version 1.14