LCOV - code coverage report
Current view: top level - frmts/map - mapdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 16 192 8.3 %
Date: 2025-02-18 14:19:29 Functions: 2 17 11.8 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OziExplorer .MAP Driver
       4             :  * Purpose:  GDALDataset driver for OziExplorer .MAP files
       5             :  * Author:   Jean-Claude Repetto, <jrepetto at @free dot fr>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2012, Jean-Claude Repetto
       9             :  * Copyright (c) 2012, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "gdal_frmts.h"
      15             : #include "gdal_pam.h"
      16             : #include "gdal_proxy.h"
      17             : #include "ogr_geometry.h"
      18             : #include "ogr_spatialref.h"
      19             : 
      20             : /************************************************************************/
      21             : /* ==================================================================== */
      22             : /*                                MAPDataset                            */
      23             : /* ==================================================================== */
      24             : /************************************************************************/
      25             : 
      26             : class MAPDataset final : public GDALDataset
      27             : {
      28             :     GDALDataset *poImageDS;
      29             : 
      30             :     OGRSpatialReference m_oSRS{};
      31             :     int bGeoTransformValid;
      32             :     double adfGeoTransform[6];
      33             :     int nGCPCount;
      34             :     GDAL_GCP *pasGCPList;
      35             :     OGRPolygon *poNeatLine;
      36             :     CPLString osImgFilename;
      37             : 
      38             :   public:
      39             :     MAPDataset();
      40             :     virtual ~MAPDataset();
      41             : 
      42             :     const OGRSpatialReference *GetSpatialRef() const override;
      43             :     virtual CPLErr GetGeoTransform(double *) override;
      44             :     virtual int GetGCPCount() override;
      45             :     const OGRSpatialReference *GetGCPSpatialRef() const override;
      46             :     virtual const GDAL_GCP *GetGCPs() override;
      47             :     virtual char **GetFileList() override;
      48             : 
      49             :     virtual int CloseDependentDatasets() override;
      50             : 
      51             :     static GDALDataset *Open(GDALOpenInfo *);
      52             :     static int Identify(GDALOpenInfo *poOpenInfo);
      53             : };
      54             : 
      55             : /************************************************************************/
      56             : /* ==================================================================== */
      57             : /*                         MAPWrapperRasterBand                         */
      58             : /* ==================================================================== */
      59             : /************************************************************************/
      60             : class MAPWrapperRasterBand final : public GDALProxyRasterBand
      61             : {
      62             :     GDALRasterBand *poBaseBand;
      63             : 
      64             :   protected:
      65             :     virtual GDALRasterBand *
      66           0 :     RefUnderlyingRasterBand(bool /*bForceOpen*/) const override
      67             :     {
      68           0 :         return poBaseBand;
      69             :     }
      70             : 
      71             :   public:
      72           0 :     explicit MAPWrapperRasterBand(GDALRasterBand *poBaseBandIn)
      73           0 :     {
      74           0 :         this->poBaseBand = poBaseBandIn;
      75           0 :         eDataType = poBaseBand->GetRasterDataType();
      76           0 :         poBaseBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
      77           0 :     }
      78             : 
      79           0 :     ~MAPWrapperRasterBand()
      80           0 :     {
      81           0 :     }
      82             : };
      83             : 
      84             : /************************************************************************/
      85             : /* ==================================================================== */
      86             : /*                             MAPDataset                               */
      87             : /* ==================================================================== */
      88             : /************************************************************************/
      89             : 
      90           0 : MAPDataset::MAPDataset()
      91             :     : poImageDS(nullptr), bGeoTransformValid(false), nGCPCount(0),
      92           0 :       pasGCPList(nullptr), poNeatLine(nullptr)
      93             : {
      94           0 :     m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
      95           0 :     adfGeoTransform[0] = 0.0;
      96           0 :     adfGeoTransform[1] = 1.0;
      97           0 :     adfGeoTransform[2] = 0.0;
      98           0 :     adfGeoTransform[3] = 0.0;
      99           0 :     adfGeoTransform[4] = 0.0;
     100           0 :     adfGeoTransform[5] = 1.0;
     101           0 : }
     102             : 
     103             : /************************************************************************/
     104             : /*                            ~MAPDataset()                             */
     105             : /************************************************************************/
     106             : 
     107           0 : MAPDataset::~MAPDataset()
     108             : 
     109             : {
     110           0 :     if (poImageDS != nullptr)
     111             :     {
     112           0 :         GDALClose(poImageDS);
     113           0 :         poImageDS = nullptr;
     114             :     }
     115             : 
     116           0 :     if (nGCPCount)
     117             :     {
     118           0 :         GDALDeinitGCPs(nGCPCount, pasGCPList);
     119           0 :         CPLFree(pasGCPList);
     120             :     }
     121             : 
     122           0 :     if (poNeatLine != nullptr)
     123             :     {
     124           0 :         delete poNeatLine;
     125           0 :         poNeatLine = nullptr;
     126             :     }
     127           0 : }
     128             : 
     129             : /************************************************************************/
     130             : /*                       CloseDependentDatasets()                       */
     131             : /************************************************************************/
     132             : 
     133           0 : int MAPDataset::CloseDependentDatasets()
     134             : {
     135           0 :     int bRet = GDALDataset::CloseDependentDatasets();
     136           0 :     if (poImageDS != nullptr)
     137             :     {
     138           0 :         GDALClose(poImageDS);
     139           0 :         poImageDS = nullptr;
     140           0 :         bRet = TRUE;
     141             :     }
     142           0 :     return bRet;
     143             : }
     144             : 
     145             : /************************************************************************/
     146             : /*                              Identify()                              */
     147             : /************************************************************************/
     148             : 
     149       53583 : int MAPDataset::Identify(GDALOpenInfo *poOpenInfo)
     150             : 
     151             : {
     152       57462 :     if (poOpenInfo->nHeaderBytes < 200 ||
     153        3879 :         !poOpenInfo->IsExtensionEqualToCI("MAP"))
     154       53586 :         return FALSE;
     155             : 
     156           0 :     if (strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
     157             :                "OziExplorer Map Data File") == nullptr)
     158           0 :         return FALSE;
     159             : 
     160           0 :     return TRUE;
     161             : }
     162             : 
     163             : /************************************************************************/
     164             : /*                                Open()                                */
     165             : /************************************************************************/
     166             : 
     167           0 : GDALDataset *MAPDataset::Open(GDALOpenInfo *poOpenInfo)
     168             : {
     169           0 :     if (!Identify(poOpenInfo))
     170           0 :         return nullptr;
     171             : 
     172             :     /* -------------------------------------------------------------------- */
     173             :     /*      Confirm the requested access is supported.                      */
     174             :     /* -------------------------------------------------------------------- */
     175           0 :     if (poOpenInfo->eAccess == GA_Update)
     176             :     {
     177           0 :         ReportUpdateNotSupportedByDriver("MAP");
     178           0 :         return nullptr;
     179             :     }
     180             : 
     181             :     /* -------------------------------------------------------------------- */
     182             :     /*      Create a corresponding GDALDataset.                             */
     183             :     /* -------------------------------------------------------------------- */
     184             : 
     185           0 :     MAPDataset *poDS = new MAPDataset();
     186             : 
     187             :     /* -------------------------------------------------------------------- */
     188             :     /*      Try to load and parse the .MAP file.                            */
     189             :     /* -------------------------------------------------------------------- */
     190             : 
     191           0 :     char *pszWKT = nullptr;
     192           0 :     bool bOziFileOK = CPL_TO_BOOL(
     193           0 :         GDALLoadOziMapFile(poOpenInfo->pszFilename, poDS->adfGeoTransform,
     194             :                            &pszWKT, &poDS->nGCPCount, &poDS->pasGCPList));
     195           0 :     if (pszWKT)
     196             :     {
     197           0 :         poDS->m_oSRS.importFromWkt(pszWKT);
     198           0 :         CPLFree(pszWKT);
     199             :     }
     200             : 
     201           0 :     if (bOziFileOK && poDS->nGCPCount == 0)
     202           0 :         poDS->bGeoTransformValid = TRUE;
     203             : 
     204             :     /* We need to read again the .map file because the GDALLoadOziMapFile
     205             :        function does not returns all required data . An API change is necessary
     206             :        : maybe in GDAL 2.0 ? */
     207             : 
     208           0 :     char **papszLines = CSLLoad2(poOpenInfo->pszFilename, 200, 200, nullptr);
     209             : 
     210           0 :     if (!papszLines)
     211             :     {
     212           0 :         delete poDS;
     213           0 :         return nullptr;
     214             :     }
     215             : 
     216           0 :     const int nLines = CSLCount(papszLines);
     217           0 :     if (nLines < 3)
     218             :     {
     219           0 :         delete poDS;
     220           0 :         CSLDestroy(papszLines);
     221           0 :         return nullptr;
     222             :     }
     223             : 
     224             :     /* -------------------------------------------------------------------- */
     225             :     /*      We need to open the image in order to establish                 */
     226             :     /*      details like the band count and types.                          */
     227             :     /* -------------------------------------------------------------------- */
     228           0 :     poDS->osImgFilename = papszLines[2];
     229             : 
     230           0 :     const CPLString osPath = CPLGetPathSafe(poOpenInfo->pszFilename);
     231           0 :     if (CPLIsFilenameRelative(poDS->osImgFilename))
     232             :     {
     233             :         poDS->osImgFilename =
     234           0 :             CPLFormCIFilenameSafe(osPath, poDS->osImgFilename, nullptr);
     235             :     }
     236             :     else
     237             :     {
     238             :         VSIStatBufL sStat;
     239           0 :         if (VSIStatL(poDS->osImgFilename, &sStat) != 0)
     240             :         {
     241           0 :             poDS->osImgFilename = CPLGetFilename(poDS->osImgFilename);
     242             :             poDS->osImgFilename =
     243           0 :                 CPLFormCIFilenameSafe(osPath, poDS->osImgFilename, nullptr);
     244             :         }
     245             :     }
     246             : 
     247             :     /* -------------------------------------------------------------------- */
     248             :     /*      Try and open the file.                                          */
     249             :     /* -------------------------------------------------------------------- */
     250           0 :     poDS->poImageDS =
     251           0 :         GDALDataset::FromHandle(GDALOpen(poDS->osImgFilename, GA_ReadOnly));
     252           0 :     if (poDS->poImageDS == nullptr || poDS->poImageDS->GetRasterCount() == 0)
     253             :     {
     254           0 :         CSLDestroy(papszLines);
     255           0 :         delete poDS;
     256           0 :         return nullptr;
     257             :     }
     258             : 
     259             :     /* -------------------------------------------------------------------- */
     260             :     /*      Attach the bands.                                               */
     261             :     /* -------------------------------------------------------------------- */
     262           0 :     poDS->nRasterXSize = poDS->poImageDS->GetRasterXSize();
     263           0 :     poDS->nRasterYSize = poDS->poImageDS->GetRasterYSize();
     264           0 :     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
     265             :     {
     266           0 :         CSLDestroy(papszLines);
     267           0 :         GDALClose(poDS->poImageDS);
     268           0 :         delete poDS;
     269           0 :         return nullptr;
     270             :     }
     271             : 
     272           0 :     for (int iBand = 1; iBand <= poDS->poImageDS->GetRasterCount(); iBand++)
     273           0 :         poDS->SetBand(iBand, new MAPWrapperRasterBand(
     274           0 :                                  poDS->poImageDS->GetRasterBand(iBand)));
     275             : 
     276             :     /* -------------------------------------------------------------------- */
     277             :     /*      Add the neatline/cutline, if required                           */
     278             :     /* -------------------------------------------------------------------- */
     279             : 
     280             :     /* First, we need to check if it is necessary to define a neatline */
     281           0 :     bool bNeatLine = false;
     282           0 :     for (int iLine = 10; iLine < nLines; iLine++)
     283             :     {
     284           0 :         if (STARTS_WITH_CI(papszLines[iLine], "MMPXY,"))
     285             :         {
     286             :             char **papszTok =
     287           0 :                 CSLTokenizeString2(papszLines[iLine], ",",
     288             :                                    CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES);
     289             : 
     290           0 :             if (CSLCount(papszTok) != 4)
     291             :             {
     292           0 :                 CSLDestroy(papszTok);
     293           0 :                 continue;
     294             :             }
     295             : 
     296           0 :             const int x = atoi(papszTok[2]);
     297           0 :             const int y = atoi(papszTok[3]);
     298           0 :             if ((x != 0 && x != poDS->nRasterXSize) ||
     299           0 :                 (y != 0 && y != poDS->nRasterYSize))
     300             :             {
     301           0 :                 bNeatLine = true;
     302           0 :                 CSLDestroy(papszTok);
     303           0 :                 break;
     304             :             }
     305           0 :             CSLDestroy(papszTok);
     306             :         }
     307             :     }
     308             : 
     309             :     /* Create and fill the neatline polygon */
     310           0 :     if (bNeatLine)
     311             :     {
     312           0 :         poDS->poNeatLine =
     313           0 :             new OGRPolygon(); /* Create a polygon to store the neatline */
     314           0 :         OGRLinearRing *poRing = new OGRLinearRing();
     315             : 
     316           0 :         if (poDS->bGeoTransformValid) /* Compute the projected coordinates of
     317             :                                          the corners */
     318             :         {
     319           0 :             for (int iLine = 10; iLine < nLines; iLine++)
     320             :             {
     321           0 :                 if (STARTS_WITH_CI(papszLines[iLine], "MMPXY,"))
     322             :                 {
     323           0 :                     char **papszTok = CSLTokenizeString2(
     324           0 :                         papszLines[iLine], ",",
     325             :                         CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES);
     326             : 
     327           0 :                     if (CSLCount(papszTok) != 4)
     328             :                     {
     329           0 :                         CSLDestroy(papszTok);
     330           0 :                         continue;
     331             :                     }
     332             : 
     333           0 :                     const double x = CPLAtofM(papszTok[2]);
     334           0 :                     const double y = CPLAtofM(papszTok[3]);
     335           0 :                     const double X = poDS->adfGeoTransform[0] +
     336           0 :                                      x * poDS->adfGeoTransform[1] +
     337           0 :                                      y * poDS->adfGeoTransform[2];
     338           0 :                     const double Y = poDS->adfGeoTransform[3] +
     339           0 :                                      x * poDS->adfGeoTransform[4] +
     340           0 :                                      y * poDS->adfGeoTransform[5];
     341           0 :                     poRing->addPoint(X, Y);
     342           0 :                     CPLDebug("CORNER MMPXY", "%f, %f, %f, %f", x, y, X, Y);
     343           0 :                     CSLDestroy(papszTok);
     344             :                 }
     345             :             }
     346             :         }
     347             :         else /* Convert the geographic coordinates to projected coordinates */
     348             :         {
     349           0 :             OGRCoordinateTransformation *poTransform = nullptr;
     350           0 :             if (!poDS->m_oSRS.IsEmpty())
     351             :             {
     352           0 :                 OGRSpatialReference *poLongLat = poDS->m_oSRS.CloneGeogCS();
     353           0 :                 if (poLongLat)
     354             :                 {
     355           0 :                     poLongLat->SetAxisMappingStrategy(
     356             :                         OAMS_TRADITIONAL_GIS_ORDER);
     357           0 :                     poTransform = OGRCreateCoordinateTransformation(
     358           0 :                         poLongLat, &poDS->m_oSRS);
     359           0 :                     delete poLongLat;
     360             :                 }
     361             :             }
     362             : 
     363           0 :             for (int iLine = 10; iLine < nLines; iLine++)
     364             :             {
     365           0 :                 if (STARTS_WITH_CI(papszLines[iLine], "MMPLL,"))
     366             :                 {
     367           0 :                     CPLDebug("MMPLL", "%s", papszLines[iLine]);
     368             : 
     369           0 :                     char **papszTok = CSLTokenizeString2(
     370           0 :                         papszLines[iLine], ",",
     371             :                         CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES);
     372             : 
     373           0 :                     if (CSLCount(papszTok) != 4)
     374             :                     {
     375           0 :                         CSLDestroy(papszTok);
     376           0 :                         continue;
     377             :                     }
     378             : 
     379           0 :                     double dfLon = CPLAtofM(papszTok[2]);
     380           0 :                     double dfLat = CPLAtofM(papszTok[3]);
     381             : 
     382           0 :                     if (poTransform)
     383           0 :                         poTransform->Transform(1, &dfLon, &dfLat);
     384           0 :                     poRing->addPoint(dfLon, dfLat);
     385           0 :                     CPLDebug("CORNER MMPLL", "%f, %f", dfLon, dfLat);
     386           0 :                     CSLDestroy(papszTok);
     387             :                 }
     388             :             }
     389           0 :             if (poTransform)
     390           0 :                 delete poTransform;
     391             :         }
     392             : 
     393           0 :         poRing->closeRings();
     394           0 :         poDS->poNeatLine->addRingDirectly(poRing);
     395             : 
     396           0 :         char *pszNeatLineWkt = nullptr;
     397           0 :         poDS->poNeatLine->exportToWkt(&pszNeatLineWkt);
     398           0 :         CPLDebug("NEATLINE", "%s", pszNeatLineWkt);
     399           0 :         poDS->SetMetadataItem("NEATLINE", pszNeatLineWkt);
     400           0 :         CPLFree(pszNeatLineWkt);
     401             :     }
     402             : 
     403           0 :     CSLDestroy(papszLines);
     404             : 
     405           0 :     return poDS;
     406             : }
     407             : 
     408             : /************************************************************************/
     409             : /*                          GetSpatialRef()                             */
     410             : /************************************************************************/
     411             : 
     412           0 : const OGRSpatialReference *MAPDataset::GetSpatialRef() const
     413             : {
     414           0 :     return (!m_oSRS.IsEmpty() && nGCPCount == 0) ? &m_oSRS : nullptr;
     415             : }
     416             : 
     417             : /************************************************************************/
     418             : /*                          GetGeoTransform()                           */
     419             : /************************************************************************/
     420             : 
     421           0 : CPLErr MAPDataset::GetGeoTransform(double *padfTransform)
     422             : 
     423             : {
     424           0 :     memcpy(padfTransform, adfGeoTransform, 6 * sizeof(double));
     425             : 
     426           0 :     return (nGCPCount == 0) ? CE_None : CE_Failure;
     427             : }
     428             : 
     429             : /************************************************************************/
     430             : /*                           GetGCPCount()                              */
     431             : /************************************************************************/
     432             : 
     433           0 : int MAPDataset::GetGCPCount()
     434             : {
     435           0 :     return nGCPCount;
     436             : }
     437             : 
     438             : /************************************************************************/
     439             : /*                          GetGCPSpatialRef()                          */
     440             : /************************************************************************/
     441             : 
     442           0 : const OGRSpatialReference *MAPDataset::GetGCPSpatialRef() const
     443             : {
     444           0 :     return (!m_oSRS.IsEmpty() && nGCPCount != 0) ? &m_oSRS : nullptr;
     445             : }
     446             : 
     447             : /************************************************************************/
     448             : /*                               GetGCPs()                              */
     449             : /************************************************************************/
     450             : 
     451           0 : const GDAL_GCP *MAPDataset::GetGCPs()
     452             : {
     453           0 :     return pasGCPList;
     454             : }
     455             : 
     456             : /************************************************************************/
     457             : /*                            GetFileList()                             */
     458             : /************************************************************************/
     459             : 
     460           0 : char **MAPDataset::GetFileList()
     461             : {
     462           0 :     char **papszFileList = GDALDataset::GetFileList();
     463             : 
     464           0 :     papszFileList = CSLAddString(papszFileList, osImgFilename);
     465             : 
     466           0 :     return papszFileList;
     467             : }
     468             : 
     469             : /************************************************************************/
     470             : /*                          GDALRegister_MAP()                          */
     471             : /************************************************************************/
     472             : 
     473        1686 : void GDALRegister_MAP()
     474             : 
     475             : {
     476        1686 :     if (GDALGetDriverByName("MAP") != nullptr)
     477         302 :         return;
     478             : 
     479        1384 :     GDALDriver *poDriver = new GDALDriver();
     480             : 
     481        1384 :     poDriver->SetDescription("MAP");
     482        1384 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     483        1384 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "OziExplorer .MAP");
     484        1384 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/map.html");
     485             : 
     486        1384 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     487             : 
     488        1384 :     poDriver->pfnOpen = MAPDataset::Open;
     489        1384 :     poDriver->pfnIdentify = MAPDataset::Identify;
     490             : 
     491        1384 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     492             : }

Generated by: LCOV version 1.14