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-11-21 22:18:42 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          18 : int TILDataset::CloseDependentDatasets()
     156             : {
     157          18 :     int bHasDroppedRef = GDALPamDataset::CloseDependentDatasets();
     158             : 
     159          18 :     if (poVRTDS)
     160             :     {
     161           5 :         bHasDroppedRef = TRUE;
     162           5 :         delete poVRTDS;
     163           5 :         poVRTDS = nullptr;
     164             :     }
     165             : 
     166          18 :     return bHasDroppedRef;
     167             : }
     168             : 
     169             : /************************************************************************/
     170             : /*                              Identify()                              */
     171             : /************************************************************************/
     172             : 
     173       53847 : int TILDataset::Identify(GDALOpenInfo *poOpenInfo)
     174             : 
     175             : {
     176       58268 :     if (poOpenInfo->nHeaderBytes < 200 ||
     177        4421 :         !EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "TIL"))
     178       53837 :         return FALSE;
     179             : 
     180          10 :     if (strstr((const char *)poOpenInfo->pabyHeader, "numTiles") == nullptr)
     181           0 :         return FALSE;
     182             : 
     183          10 :     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 :         CPLError(CE_Failure, CPLE_NotSupported,
     202             :                  "The TIL driver does not support update access to existing"
     203             :                  " datasets.\n");
     204           0 :         return nullptr;
     205             :     }
     206             : 
     207          10 :     CPLString osDirname = CPLGetDirname(poOpenInfo->pszFilename);
     208             : 
     209             :     // get metadata reader
     210             : 
     211          10 :     GDALMDReaderManager mdreadermanager;
     212           5 :     GDALMDReaderBase *mdreader = mdreadermanager.GetReader(
     213           5 :         poOpenInfo->pszFilename, poOpenInfo->GetSiblingFiles(), MDR_DG);
     214             : 
     215           5 :     if (nullptr == mdreader)
     216             :     {
     217           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     218             :                  "Unable to open .TIL dataset due to missing metadata file.");
     219           0 :         return nullptr;
     220             :     }
     221             :     /* -------------------------------------------------------------------- */
     222             :     /*      Try to find the corresponding .IMD file.                        */
     223             :     /* -------------------------------------------------------------------- */
     224           5 :     char **papszIMD = mdreader->GetMetadataDomain(MD_DOMAIN_IMD);
     225             : 
     226           5 :     if (papszIMD == nullptr)
     227             :     {
     228           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     229             :                  "Unable to open .TIL dataset due to missing .IMD file.");
     230           0 :         return nullptr;
     231             :     }
     232             : 
     233           5 :     if (CSLFetchNameValue(papszIMD, "numRows") == nullptr ||
     234          10 :         CSLFetchNameValue(papszIMD, "numColumns") == nullptr ||
     235           5 :         CSLFetchNameValue(papszIMD, "bitsPerPixel") == nullptr)
     236             :     {
     237           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     238             :                  "Missing a required field in the .IMD file.");
     239           0 :         return nullptr;
     240             :     }
     241             : 
     242             :     /* -------------------------------------------------------------------- */
     243             :     /*      Try to load and parse the .TIL file.                            */
     244             :     /* -------------------------------------------------------------------- */
     245           5 :     VSILFILE *fp = poOpenInfo->fpL;
     246           5 :     poOpenInfo->fpL = nullptr;
     247             : 
     248          10 :     CPLKeywordParser oParser;
     249             : 
     250           5 :     if (!oParser.Ingest(fp))
     251             :     {
     252           0 :         VSIFCloseL(fp);
     253           0 :         return nullptr;
     254             :     }
     255             : 
     256           5 :     VSIFCloseL(fp);
     257             : 
     258           5 :     char **papszTIL = oParser.GetAllKeywords();
     259             : 
     260             :     /* -------------------------------------------------------------------- */
     261             :     /*      Create a corresponding GDALDataset.                             */
     262             :     /* -------------------------------------------------------------------- */
     263           5 :     TILDataset *poDS = new TILDataset();
     264           5 :     poDS->papszMetadataFiles = mdreader->GetMetadataFiles();
     265           5 :     mdreader->FillMetadata(&poDS->oMDMD);
     266           5 :     poDS->nRasterXSize =
     267           5 :         atoi(CSLFetchNameValueDef(papszIMD, "numColumns", "0"));
     268           5 :     poDS->nRasterYSize = atoi(CSLFetchNameValueDef(papszIMD, "numRows", "0"));
     269           5 :     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
     270             :     {
     271           0 :         delete poDS;
     272           0 :         return nullptr;
     273             :     }
     274             : 
     275             :     /* -------------------------------------------------------------------- */
     276             :     /*      We need to open one of the images in order to establish         */
     277             :     /*      details like the band count and types.                          */
     278             :     /* -------------------------------------------------------------------- */
     279           5 :     const char *pszFilename = CSLFetchNameValue(papszTIL, "TILE_1.filename");
     280           5 :     if (pszFilename == nullptr)
     281             :     {
     282           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     283             :                  "Missing TILE_1.filename in .TIL file.");
     284           0 :         delete poDS;
     285           0 :         return nullptr;
     286             :     }
     287             : 
     288             :     // trim double quotes.
     289           5 :     if (pszFilename[0] == '"')
     290           5 :         pszFilename++;
     291           5 :     if (pszFilename[strlen(pszFilename) - 1] == '"')
     292           5 :         const_cast<char *>(pszFilename)[strlen(pszFilename) - 1] = '\0';
     293             : 
     294          10 :     CPLString osFilename = CPLFormFilename(osDirname, pszFilename, nullptr);
     295             :     GDALDataset *poTemplateDS =
     296           5 :         GDALDataset::FromHandle(GDALOpen(osFilename, GA_ReadOnly));
     297           5 :     if (poTemplateDS == nullptr || poTemplateDS->GetRasterCount() == 0)
     298             :     {
     299           0 :         delete poDS;
     300           0 :         if (poTemplateDS != nullptr)
     301           0 :             GDALClose(poTemplateDS);
     302           0 :         return nullptr;
     303             :     }
     304             : 
     305           5 :     GDALRasterBand *poTemplateBand = poTemplateDS->GetRasterBand(1);
     306           5 :     const GDALDataType eDT = poTemplateBand->GetRasterDataType();
     307           5 :     const int nBandCount = poTemplateDS->GetRasterCount();
     308             : 
     309             :     // we suppose the first tile have the same projection as others (usually so)
     310          10 :     CPLString pszProjection(poTemplateDS->GetProjectionRef());
     311           5 :     if (!pszProjection.empty())
     312           5 :         poDS->SetProjection(pszProjection);
     313             : 
     314             :     // we suppose the first tile have the same GeoTransform as others (usually
     315             :     // so)
     316             :     double adfGeoTransform[6];
     317           5 :     if (poTemplateDS->GetGeoTransform(adfGeoTransform) == CE_None)
     318             :     {
     319             :         // According to
     320             :         // https://www.digitalglobe.com/sites/default/files/ISD_External.pdf,
     321             :         // ulx=originX and is "Easting of the center of the upper left pixel of
     322             :         // the image."
     323           5 :         adfGeoTransform[0] = CPLAtof(CSLFetchNameValueDef(
     324           5 :                                  papszIMD, "MAP_PROJECTED_PRODUCT.ULX", "0")) -
     325           5 :                              adfGeoTransform[1] / 2;
     326           5 :         adfGeoTransform[3] = CPLAtof(CSLFetchNameValueDef(
     327           5 :                                  papszIMD, "MAP_PROJECTED_PRODUCT.ULY", "0")) -
     328           5 :                              adfGeoTransform[5] / 2;
     329           5 :         poDS->SetGeoTransform(adfGeoTransform);
     330             :     }
     331             : 
     332           5 :     poTemplateBand = nullptr;
     333           5 :     GDALClose(poTemplateDS);
     334             : 
     335             :     /* -------------------------------------------------------------------- */
     336             :     /*      Create and initialize the corresponding VRT dataset used to     */
     337             :     /*      manage the tiled data access.                                   */
     338             :     /* -------------------------------------------------------------------- */
     339           5 :     poDS->poVRTDS = new VRTDataset(poDS->nRasterXSize, poDS->nRasterYSize);
     340             : 
     341          10 :     for (int iBand = 0; iBand < nBandCount; iBand++)
     342           5 :         poDS->poVRTDS->AddBand(eDT, nullptr);
     343             : 
     344             :     /* Don't try to write a VRT file */
     345           5 :     poDS->poVRTDS->SetWritable(FALSE);
     346             : 
     347             :     /* -------------------------------------------------------------------- */
     348             :     /*      Create band information objects.                                */
     349             :     /* -------------------------------------------------------------------- */
     350          10 :     for (int iBand = 1; iBand <= nBandCount; iBand++)
     351           5 :         poDS->SetBand(
     352             :             iBand, new TILRasterBand(poDS, iBand,
     353             :                                      reinterpret_cast<VRTSourcedRasterBand *>(
     354           5 :                                          poDS->poVRTDS->GetRasterBand(iBand))));
     355             : 
     356             :     /* -------------------------------------------------------------------- */
     357             :     /*      Add tiles as sources for each band.                             */
     358             :     /* -------------------------------------------------------------------- */
     359             :     const int nTileCount =
     360           5 :         atoi(CSLFetchNameValueDef(papszTIL, "numTiles", "0"));
     361           5 :     int iTile = 0;
     362             : 
     363          10 :     for (iTile = 1; iTile <= nTileCount; iTile++)
     364             :     {
     365           5 :         CPLString osKey;
     366           5 :         osKey.Printf("TILE_%d.filename", iTile);
     367           5 :         pszFilename = CSLFetchNameValue(papszTIL, osKey);
     368           5 :         if (pszFilename == nullptr)
     369             :         {
     370           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     371             :                      "Missing TILE_%d.filename in .TIL file.", iTile);
     372           0 :             delete poDS;
     373           0 :             return nullptr;
     374             :         }
     375             : 
     376             :         // trim double quotes.
     377           5 :         if (pszFilename[0] == '"')
     378           5 :             pszFilename++;
     379           5 :         if (pszFilename[strlen(pszFilename) - 1] == '"')
     380           0 :             const_cast<char *>(pszFilename)[strlen(pszFilename) - 1] = '\0';
     381           5 :         osFilename = CPLFormFilename(osDirname, pszFilename, nullptr);
     382           5 :         poDS->m_aosFilenames.push_back(osFilename);
     383             : 
     384           5 :         osKey.Printf("TILE_%d.ULColOffset", iTile);
     385           5 :         const int nULX = atoi(CSLFetchNameValueDef(papszTIL, osKey, "0"));
     386             : 
     387           5 :         osKey.Printf("TILE_%d.ULRowOffset", iTile);
     388           5 :         const int nULY = atoi(CSLFetchNameValueDef(papszTIL, osKey, "0"));
     389             : 
     390           5 :         osKey.Printf("TILE_%d.LRColOffset", iTile);
     391           5 :         const int nLRX = atoi(CSLFetchNameValueDef(papszTIL, osKey, "0"));
     392             : 
     393           5 :         osKey.Printf("TILE_%d.LRRowOffset", iTile);
     394           5 :         const int nLRY = atoi(CSLFetchNameValueDef(papszTIL, osKey, "0"));
     395             : 
     396          10 :         for (int iBand = 1; iBand <= nBandCount; iBand++)
     397             :         {
     398             :             VRTSourcedRasterBand *poVRTBand =
     399             :                 reinterpret_cast<VRTSourcedRasterBand *>(
     400           5 :                     poDS->poVRTDS->GetRasterBand(iBand));
     401             : 
     402           5 :             poVRTBand->AddSimpleSource(osFilename, iBand, 0, 0, nLRX - nULX + 1,
     403           5 :                                        nLRY - nULY + 1, nULX, nULY,
     404           5 :                                        nLRX - nULX + 1, nLRY - nULY + 1);
     405             :         }
     406             :     }
     407             : 
     408             :     /* -------------------------------------------------------------------- */
     409             :     /*      Initialize any PAM information.                                 */
     410             :     /* -------------------------------------------------------------------- */
     411           5 :     poDS->SetDescription(poOpenInfo->pszFilename);
     412           5 :     poDS->TryLoadXML();
     413             : 
     414             :     /* -------------------------------------------------------------------- */
     415             :     /*      Check for overviews.                                            */
     416             :     /* -------------------------------------------------------------------- */
     417           5 :     poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename);
     418             : 
     419           5 :     return poDS;
     420             : }
     421             : 
     422             : /************************************************************************/
     423             : /*                            GetFileList()                             */
     424             : /************************************************************************/
     425             : 
     426           3 : char **TILDataset::GetFileList()
     427             : 
     428             : {
     429           3 :     char **papszFileList = GDALPamDataset::GetFileList();
     430             : 
     431           6 :     for (const auto &osFilename : m_aosFilenames)
     432           3 :         papszFileList = CSLAddString(papszFileList, osFilename.c_str());
     433             : 
     434           3 :     if (nullptr != papszMetadataFiles)
     435             :     {
     436           6 :         for (int i = 0; papszMetadataFiles[i] != nullptr; i++)
     437             :         {
     438           3 :             papszFileList = CSLAddString(papszFileList, papszMetadataFiles[i]);
     439             :         }
     440             :     }
     441             : 
     442           3 :     return papszFileList;
     443             : }
     444             : 
     445             : /************************************************************************/
     446             : /*                          GDALRegister_TIL()                          */
     447             : /************************************************************************/
     448             : 
     449        1595 : void GDALRegister_TIL()
     450             : 
     451             : {
     452        1595 :     if (GDALGetDriverByName("TIL") != nullptr)
     453         302 :         return;
     454             : 
     455        1293 :     GDALDriver *poDriver = new GDALDriver();
     456             : 
     457        1293 :     poDriver->SetDescription("TIL");
     458        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     459        1293 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "EarthWatch .TIL");
     460        1293 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/til.html");
     461        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     462             : 
     463        1293 :     poDriver->pfnOpen = TILDataset::Open;
     464        1293 :     poDriver->pfnIdentify = TILDataset::Identify;
     465             : 
     466        1293 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     467             : }

Generated by: LCOV version 1.14