LCOV - code coverage report
Current view: top level - frmts/coasp - coasp_dataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 18 216 8.3 %
Date: 2024-05-02 14:43:06 Functions: 2 19 10.5 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  DRDC Configurable Airborne SAR Processor (COASP) data reader
       4             :  * Purpose:  Support in GDAL for the DRDC COASP format data, both Metadata
       5             :  *           and complex imagery.
       6             :  * Author:   Philippe Vachon <philippe@cowpig.ca>
       7             :  * Notes:    I have seen a grand total of 2 COASP scenes (3 sets of headers).
       8             :  *           This is based on my best observations, some educated guesses and
       9             :  *           such. So if you have a scene that doesn't work, send it to me
      10             :  *           please and I will make it work... with violence.
      11             :  *
      12             :  ******************************************************************************
      13             :  * Copyright (c) 2007, Philippe Vachon
      14             :  * Copyright (c) 2009-2012, Even Rouault <even dot rouault at spatialys.com>
      15             :  *
      16             :  * Permission is hereby granted, free of charge, to any person obtaining a
      17             :  * copy of this software and associated documentation files (the "Software"),
      18             :  * to deal in the Software without restriction, including without limitation
      19             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      20             :  * and/or sell copies of the Software, and to permit persons to whom the
      21             :  * Software is furnished to do so, subject to the following conditions:
      22             :  *
      23             :  * The above copyright notice and this permission notice shall be included
      24             :  * in all copies or substantial portions of the Software.
      25             :  *
      26             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      27             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      28             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      29             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      30             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      31             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      32             :  * DEALINGS IN THE SOFTWARE.
      33             :  ****************************************************************************/
      34             : 
      35             : #include "cpl_conv.h"
      36             : #include "cpl_port.h"
      37             : #include "cpl_string.h"
      38             : #include "cpl_vsi.h"
      39             : #include "gdal_frmts.h"
      40             : #include "gdal_priv.h"
      41             : 
      42             : constexpr int TYPE_GENERIC = 0;
      43             : constexpr int TYPE_GEOREF = 1;
      44             : 
      45             : enum ePolarization
      46             : {
      47             :     hh = 0,
      48             :     hv,
      49             :     vh,
      50             :     vv
      51             : };
      52             : 
      53             : /*******************************************************************
      54             :  * Declaration of the COASPMetadata classes                        *
      55             :  *******************************************************************/
      56             : 
      57             : class COASPMetadataItem;
      58             : 
      59             : class COASPMetadataReader
      60             : {
      61             :     char **papszMetadata;
      62             :     int nMetadataCount;
      63             :     int nCurrentItem;
      64             : 
      65             :   public:
      66             :     explicit COASPMetadataReader(char *pszFname);
      67             :     ~COASPMetadataReader();
      68             :     COASPMetadataItem *GetNextItem();
      69             :     COASPMetadataItem *GetItem(int nItem);
      70             :     int GotoMetadataItem(const char *pszName);
      71             : 
      72             :     int GetCurrentItem() const
      73             :     {
      74             :         return nCurrentItem;
      75             :     }
      76             : };
      77             : 
      78             : /* Your average metadata item */
      79             : class COASPMetadataItem
      80             : {
      81             :   protected:
      82             :     char *pszItemName;
      83             :     char *pszItemValue;
      84             : 
      85             :   public:
      86           0 :     COASPMetadataItem() : pszItemName(nullptr), pszItemValue(nullptr)
      87             :     {
      88           0 :     }
      89             : 
      90             :     COASPMetadataItem(char *pszItemName, char *pszItemValue);
      91             :     ~COASPMetadataItem();
      92             : 
      93             :     char *GetItemName();
      94             :     char *GetItemValue();
      95             : 
      96             :     static int GetType()
      97             :     {
      98             :         return TYPE_GENERIC;
      99             :     }
     100             : };
     101             : 
     102             : /* Same as MetadataItem class except parses GCP properly and returns
     103             :  * a GDAL_GCP struct
     104             :  */
     105             : class COASPMetadataGeorefGridItem : public COASPMetadataItem
     106             : {
     107             : #ifdef unused
     108             :     int nId;
     109             :     int nPixels;
     110             :     int nLines;
     111             :     double ndLat;
     112             :     double ndLong;
     113             : #endif
     114             : 
     115             :   public:
     116             :     COASPMetadataGeorefGridItem(int nId, int nPixels, int nLines, double ndLat,
     117             :                                 double ndLong);
     118             : 
     119             :     static const char *GetItemName()
     120             :     {
     121             :         return "georef_grid";
     122             :     }
     123             : 
     124             :     static GDAL_GCP *GetItemValue();
     125             : 
     126             :     static int GetType()
     127             :     {
     128             :         return TYPE_GEOREF;
     129             :     }
     130             : };
     131             : 
     132             : /********************************************************************
     133             :  * ================================================================ *
     134             :  * Implementation of the COASPMetadataItem Classes                  *
     135             :  * ================================================================ *
     136             :  ********************************************************************/
     137             : 
     138           0 : COASPMetadataItem::COASPMetadataItem(char *pszItemName_, char *pszItemValue_)
     139           0 :     : pszItemName(VSIStrdup(pszItemName_)),
     140           0 :       pszItemValue(VSIStrdup(pszItemValue_))
     141             : {
     142           0 : }
     143             : 
     144           0 : COASPMetadataItem::~COASPMetadataItem()
     145             : {
     146           0 :     CPLFree(pszItemName);
     147           0 :     CPLFree(pszItemValue);
     148           0 : }
     149             : 
     150           0 : char *COASPMetadataItem::GetItemName()
     151             : {
     152           0 :     return VSIStrdup(pszItemName);
     153             : }
     154             : 
     155           0 : char *COASPMetadataItem::GetItemValue()
     156             : {
     157           0 :     return VSIStrdup(pszItemValue);
     158             : }
     159             : 
     160           0 : COASPMetadataGeorefGridItem::COASPMetadataGeorefGridItem(int /*nIdIn*/,
     161             :                                                          int /*nPixelsIn*/,
     162             :                                                          int /*nLinesIn*/,
     163             :                                                          double /*ndLatIn*/,
     164           0 :                                                          double /*ndLongIn*/)
     165             : #ifdef unused
     166             :     : nId(nIdIn), nPixels(nPixelsIn), nLines(nLinesIn), ndLat(ndLatIn),
     167             :       ndLong(ndLongIn)
     168             : #endif
     169             : {
     170           0 :     pszItemName = VSIStrdup("georef_grid");
     171           0 : }
     172             : 
     173           0 : GDAL_GCP *COASPMetadataGeorefGridItem::GetItemValue()
     174             : {
     175           0 :     return nullptr;
     176             : }
     177             : 
     178             : /********************************************************************
     179             :  * ================================================================ *
     180             :  * Implementation of the COASPMetadataReader Class                  *
     181             :  * ================================================================ *
     182             :  ********************************************************************/
     183             : 
     184           0 : COASPMetadataReader::COASPMetadataReader(char *pszFname)
     185           0 :     : papszMetadata(CSLLoad(pszFname)), nMetadataCount(0), nCurrentItem(0)
     186             : {
     187           0 :     nMetadataCount = CSLCount(papszMetadata);
     188           0 : }
     189             : 
     190           0 : COASPMetadataReader::~COASPMetadataReader()
     191             : {
     192           0 :     CSLDestroy(papszMetadata);
     193           0 : }
     194             : 
     195           0 : COASPMetadataItem *COASPMetadataReader::GetNextItem()
     196             : {
     197           0 :     if (nCurrentItem < 0 || nCurrentItem >= nMetadataCount)
     198           0 :         return nullptr;
     199             : 
     200           0 :     COASPMetadataItem *poMetadata = nullptr;
     201             : 
     202           0 :     char **papszMDTokens = CSLTokenizeString2(papszMetadata[nCurrentItem], " ",
     203             :                                               CSLT_HONOURSTRINGS);
     204           0 :     char *pszItemName = papszMDTokens[0];
     205           0 :     if (STARTS_WITH_CI(pszItemName, "georef_grid") &&
     206           0 :         CSLCount(papszMDTokens) >= 8)
     207             :     {
     208             :         // georef_grid ( pixels lines ) ( lat long )
     209             :         // 0           1 2      3     4 5 6   7    8
     210           0 :         int nPixels = atoi(papszMDTokens[2]);
     211           0 :         int nLines = atoi(papszMDTokens[3]);
     212           0 :         double dfLat = CPLAtof(papszMDTokens[6]);
     213           0 :         double dfLong = CPLAtof(papszMDTokens[7]);
     214           0 :         poMetadata = new COASPMetadataGeorefGridItem(nCurrentItem, nPixels,
     215           0 :                                                      nLines, dfLat, dfLong);
     216             :     }
     217             :     else
     218             :     {
     219           0 :         int nCount = CSLCount(papszMDTokens);
     220           0 :         if (nCount >= 2)
     221             :         {
     222           0 :             char *pszItemValue = CPLStrdup(papszMDTokens[1]);
     223           0 :             for (int i = 2; i < nCount; i++)
     224             :             {
     225           0 :                 const size_t nSize =
     226           0 :                     strlen(pszItemValue) + 1 + strlen(papszMDTokens[i]);
     227           0 :                 pszItemValue = (char *)CPLRealloc(pszItemValue, nSize);
     228           0 :                 snprintf(pszItemValue + strlen(pszItemValue),
     229           0 :                          nSize - strlen(pszItemValue), " %s", papszMDTokens[i]);
     230             :             }
     231             : 
     232           0 :             poMetadata = new COASPMetadataItem(pszItemName, pszItemValue);
     233             : 
     234           0 :             CPLFree(pszItemValue);
     235             :         }
     236             :     }
     237           0 :     CSLDestroy(papszMDTokens);
     238           0 :     nCurrentItem++;
     239           0 :     return poMetadata;
     240             : }
     241             : 
     242             : /* Goto the first metadata item with a particular name */
     243           0 : int COASPMetadataReader::GotoMetadataItem(const char *pszName)
     244             : {
     245           0 :     nCurrentItem = CSLPartialFindString(papszMetadata, pszName);
     246           0 :     return nCurrentItem;
     247             : }
     248             : 
     249             : /*******************************************************************
     250             :  * Declaration of the COASPDataset class                           *
     251             :  *******************************************************************/
     252             : 
     253             : class COASPRasterBand;
     254             : 
     255             : /* A couple of observations based on the data I have available to me:
     256             :  * a) the headers don't really change, beyond indicating data sources
     257             :  *    and such. As such, I only read the first header specified by the
     258             :  *    user. Note that this is agnostic: you can specify hh, vv, vh, hv and
     259             :  *    all the data needed will be immediately available.
     260             :  * b) Lots of GCPs are present in the headers. This is most excellent.
     261             :  * c) There is no documentation on this format. All the knowledge contained
     262             :  *    herein is from harassing various Defence Scientists at DRDC Ottawa.
     263             :  */
     264             : 
     265             : class COASPDataset final : public GDALDataset
     266             : {
     267             :     friend class COASPRasterBand;
     268             :     VSILFILE *fpHdr;   /* File pointer for the header file */
     269             :     VSILFILE *fpBinHH; /* File pointer for the binary matrix */
     270             :     VSILFILE *fpBinHV;
     271             :     VSILFILE *fpBinVH;
     272             :     VSILFILE *fpBinVV;
     273             : 
     274             :     char *pszFileName; /* line and mission ID, mostly, i.e. l27p7 */
     275             : 
     276             :   public:
     277           0 :     COASPDataset()
     278           0 :         : fpHdr(nullptr), fpBinHH(nullptr), fpBinHV(nullptr), fpBinVH(nullptr),
     279           0 :           fpBinVV(nullptr), pszFileName(nullptr)
     280             :     {
     281           0 :     }
     282             : 
     283             :     ~COASPDataset();
     284             : 
     285             :     static GDALDataset *Open(GDALOpenInfo *);
     286             :     static int Identify(GDALOpenInfo *poOpenInfo);
     287             : };
     288             : 
     289             : /********************************************************************
     290             :  * ================================================================ *
     291             :  * Declaration and implementation of the COASPRasterBand Class      *
     292             :  * ================================================================ *
     293             :  ********************************************************************/
     294             : 
     295             : class COASPRasterBand final : public GDALRasterBand
     296             : {
     297             :     VSILFILE *fp;
     298             :     // int ePol;
     299             :   public:
     300             :     COASPRasterBand(COASPDataset *poDS, GDALDataType eDataType, int ePol,
     301             :                     VSILFILE *fp);
     302             :     CPLErr IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage) override;
     303             : };
     304             : 
     305           0 : COASPRasterBand::COASPRasterBand(COASPDataset *poDSIn, GDALDataType eDataTypeIn,
     306           0 :                                  int /*ePolIn*/, VSILFILE *fpIn)
     307           0 :     : fp(fpIn) /*,
     308             :        ePol(ePolIn)*/
     309             : {
     310           0 :     poDS = poDSIn;
     311           0 :     eDataType = eDataTypeIn;
     312           0 :     nBlockXSize = poDS->GetRasterXSize();
     313           0 :     nBlockYSize = 1;
     314           0 : }
     315             : 
     316           0 : CPLErr COASPRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
     317             :                                    void *pImage)
     318             : {
     319           0 :     if (this->fp == nullptr)
     320             :     {
     321           0 :         CPLError(CE_Fatal, CPLE_AppDefined, "File pointer freed unexpectedly");
     322           0 :         return CE_Fatal;
     323             :     }
     324             : 
     325             :     /* 8 bytes per pixel: 4 bytes I, 4 bytes Q */
     326             :     const vsi_l_offset nByteNum =
     327           0 :         static_cast<vsi_l_offset>(poDS->GetRasterXSize()) * 8 * nBlockYOff;
     328             : 
     329           0 :     VSIFSeekL(this->fp, nByteNum, SEEK_SET);
     330             :     int nReadSize =
     331           0 :         (GDALGetDataTypeSize(eDataType) / 8) * poDS->GetRasterXSize();
     332           0 :     VSIFReadL((char *)pImage, 1, nReadSize, this->fp);
     333             : 
     334             : #ifdef CPL_LSB
     335           0 :     GDALSwapWords(pImage, 4, nBlockXSize * 2, 4);
     336             : #endif
     337           0 :     return CE_None;
     338             : }
     339             : 
     340             : /********************************************************************
     341             :  * ================================================================ *
     342             :  * Implementation of the COASPDataset Class                         *
     343             :  * ================================================================ *
     344             :  ********************************************************************/
     345             : 
     346             : /************************************************************************/
     347             : /*                          ~COASPDataset()                             */
     348             : /************************************************************************/
     349             : 
     350           0 : COASPDataset::~COASPDataset()
     351             : {
     352           0 :     CPLFree(pszFileName);
     353           0 :     if (fpHdr)
     354           0 :         VSIFCloseL(fpHdr);
     355           0 :     if (fpBinHH)
     356           0 :         VSIFCloseL(fpBinHH);
     357           0 :     if (fpBinHV)
     358           0 :         VSIFCloseL(fpBinHV);
     359           0 :     if (fpBinVH)
     360           0 :         VSIFCloseL(fpBinVH);
     361           0 :     if (fpBinVV)
     362           0 :         VSIFCloseL(fpBinVV);
     363           0 : }
     364             : 
     365             : /************************************************************************/
     366             : /*                              Identify()                              */
     367             : /************************************************************************/
     368             : 
     369       50077 : int COASPDataset::Identify(GDALOpenInfo *poOpenInfo)
     370             : {
     371       50077 :     if (poOpenInfo->fpL == nullptr || poOpenInfo->nHeaderBytes < 256)
     372       46535 :         return 0;
     373             : 
     374             :     // With a COASP .hdr file, the first line or so is: time_first_datarec
     375             : 
     376        3542 :     if (STARTS_WITH_CI((char *)poOpenInfo->pabyHeader, "time_first_datarec"))
     377           0 :         return 1;
     378             : 
     379        3542 :     return 0;
     380             : }
     381             : 
     382             : /************************************************************************/
     383             : /*                                Open()                                */
     384             : /************************************************************************/
     385             : 
     386           0 : GDALDataset *COASPDataset::Open(GDALOpenInfo *poOpenInfo)
     387             : {
     388           0 :     if (!COASPDataset::Identify(poOpenInfo))
     389           0 :         return nullptr;
     390             : 
     391             :     /* -------------------------------------------------------------------- */
     392             :     /*      Confirm the requested access is supported.                      */
     393             :     /* -------------------------------------------------------------------- */
     394           0 :     if (poOpenInfo->eAccess == GA_Update)
     395             :     {
     396           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     397             :                  "The COASP driver does not support update access to existing"
     398             :                  " datasets.\n");
     399           0 :         return nullptr;
     400             :     }
     401             : 
     402             :     /* Create a fresh dataset for us to work with */
     403           0 :     COASPDataset *poDS = new COASPDataset();
     404             : 
     405             :     /* Steal the file pointer for the header */
     406           0 :     poDS->fpHdr = poOpenInfo->fpL;
     407           0 :     poOpenInfo->fpL = nullptr;
     408             : 
     409           0 :     poDS->pszFileName = VSIStrdup(poOpenInfo->pszFilename);
     410             : 
     411             :     /* determine the file name prefix */
     412           0 :     char *pszBaseName = VSIStrdup(CPLGetBasename(poDS->pszFileName));
     413           0 :     char *pszDir = VSIStrdup(CPLGetPath(poDS->pszFileName));
     414           0 :     const char *pszExt = "rc";
     415           0 :     int nNull = static_cast<int>(strlen(pszBaseName)) - 1;
     416           0 :     if (nNull <= 0)
     417             :     {
     418           0 :         VSIFree(pszDir);
     419           0 :         VSIFree(pszBaseName);
     420           0 :         delete poDS;
     421           0 :         return nullptr;
     422             :     }
     423           0 :     char *pszBase = (char *)CPLMalloc(nNull);
     424           0 :     strncpy(pszBase, pszBaseName, nNull);
     425           0 :     pszBase[nNull - 1] = '\0';
     426           0 :     VSIFree(pszBaseName);
     427             : 
     428           0 :     char *psChan = strstr(pszBase, "hh");
     429           0 :     if (psChan == nullptr)
     430             :     {
     431           0 :         psChan = strstr(pszBase, "hv");
     432             :     }
     433           0 :     if (psChan == nullptr)
     434             :     {
     435           0 :         psChan = strstr(pszBase, "vh");
     436             :     }
     437           0 :     if (psChan == nullptr)
     438             :     {
     439           0 :         psChan = strstr(pszBase, "vv");
     440             :     }
     441             : 
     442           0 :     if (psChan == nullptr)
     443             :     {
     444           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     445             :                  "Unable to recognize file as COASP.");
     446           0 :         VSIFree(pszBase);
     447           0 :         VSIFree(pszDir);
     448           0 :         delete poDS;
     449           0 :         return nullptr;
     450             :     }
     451             : 
     452             :     /* Read Metadata, set GCPs as is appropriate */
     453           0 :     COASPMetadataReader oReader(poDS->pszFileName);
     454             : 
     455             :     /* Get Image X and Y widths */
     456           0 :     oReader.GotoMetadataItem("number_lines");
     457           0 :     COASPMetadataItem *poItem = oReader.GetNextItem();
     458           0 :     if (poItem == nullptr)
     459             :     {
     460           0 :         VSIFree(pszBase);
     461           0 :         VSIFree(pszDir);
     462           0 :         delete poDS;
     463           0 :         return nullptr;
     464             :     }
     465           0 :     char *nValue = poItem->GetItemValue();
     466           0 :     poDS->nRasterYSize = atoi(nValue);
     467           0 :     delete poItem;
     468           0 :     VSIFree(nValue);
     469             : 
     470           0 :     oReader.GotoMetadataItem("number_samples");
     471           0 :     poItem = oReader.GetNextItem();
     472           0 :     if (poItem == nullptr)
     473             :     {
     474           0 :         VSIFree(pszBase);
     475           0 :         VSIFree(pszDir);
     476           0 :         delete poDS;
     477           0 :         return nullptr;
     478             :     }
     479           0 :     nValue = poItem->GetItemValue();
     480           0 :     poDS->nRasterXSize = atoi(nValue);
     481           0 :     delete poItem;
     482           0 :     VSIFree(nValue);
     483             : 
     484           0 :     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
     485             :     {
     486           0 :         VSIFree(pszBase);
     487           0 :         VSIFree(pszDir);
     488           0 :         delete poDS;
     489           0 :         return nullptr;
     490             :     }
     491             : 
     492             :     /* Horizontal transmit, horizontal receive */
     493           0 :     psChan[0] = 'h';
     494           0 :     psChan[1] = 'h';
     495           0 :     const char *pszFilename = CPLFormFilename(pszDir, pszBase, pszExt);
     496             : 
     497           0 :     poDS->fpBinHH = VSIFOpenL(pszFilename, "r");
     498             : 
     499           0 :     if (poDS->fpBinHH != nullptr)
     500             :     {
     501             :         /* Set raster band */
     502           0 :         poDS->SetBand(
     503           0 :             1, new COASPRasterBand(poDS, GDT_CFloat32, hh, poDS->fpBinHH));
     504             :     }
     505             : 
     506             :     /* Horizontal transmit, vertical receive */
     507           0 :     psChan[0] = 'h';
     508           0 :     psChan[1] = 'v';
     509           0 :     pszFilename = CPLFormFilename(pszDir, pszBase, pszExt);
     510             : 
     511           0 :     poDS->fpBinHV = VSIFOpenL(pszFilename, "r");
     512             : 
     513           0 :     if (poDS->fpBinHV != nullptr)
     514             :     {
     515           0 :         poDS->SetBand(
     516           0 :             2, new COASPRasterBand(poDS, GDT_CFloat32, hv, poDS->fpBinHV));
     517             :     }
     518             : 
     519             :     /* Vertical transmit, horizontal receive */
     520           0 :     psChan[0] = 'v';
     521           0 :     psChan[1] = 'h';
     522           0 :     pszFilename = CPLFormFilename(pszDir, pszBase, pszExt);
     523             : 
     524           0 :     poDS->fpBinVH = VSIFOpenL(pszFilename, "r");
     525             : 
     526           0 :     if (poDS->fpBinVH != nullptr)
     527             :     {
     528           0 :         poDS->SetBand(
     529           0 :             3, new COASPRasterBand(poDS, GDT_CFloat32, vh, poDS->fpBinVH));
     530             :     }
     531             : 
     532             :     /* Vertical transmit, vertical receive */
     533           0 :     psChan[0] = 'v';
     534           0 :     psChan[1] = 'v';
     535           0 :     pszFilename = CPLFormFilename(pszDir, pszBase, pszExt);
     536             : 
     537           0 :     poDS->fpBinVV = VSIFOpenL(pszFilename, "r");
     538             : 
     539           0 :     if (poDS->fpBinVV != nullptr)
     540             :     {
     541           0 :         poDS->SetBand(
     542           0 :             4, new COASPRasterBand(poDS, GDT_CFloat32, vv, poDS->fpBinVV));
     543             :     }
     544             : 
     545             :     /* Oops, missing all the data? */
     546           0 :     if (poDS->fpBinHH == nullptr && poDS->fpBinHV == nullptr &&
     547           0 :         poDS->fpBinVH == nullptr && poDS->fpBinVV == nullptr)
     548             :     {
     549           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Unable to find any data!");
     550           0 :         VSIFree(pszBase);
     551           0 :         VSIFree(pszDir);
     552           0 :         delete poDS;
     553           0 :         return nullptr;
     554             :     }
     555             : 
     556           0 :     if (poDS->GetRasterCount() == 4)
     557             :     {
     558           0 :         poDS->SetMetadataItem("MATRIX_REPRESENTATION", "SCATTERING");
     559             :     }
     560             : 
     561           0 :     VSIFree(pszBase);
     562           0 :     VSIFree(pszDir);
     563             : 
     564           0 :     return poDS;
     565             : }
     566             : 
     567             : /************************************************************************/
     568             : /*                         GDALRegister_COASP()                         */
     569             : /************************************************************************/
     570             : 
     571        1512 : void GDALRegister_COASP()
     572             : {
     573        1512 :     if (GDALGetDriverByName("COASP") != nullptr)
     574         295 :         return;
     575             : 
     576        1217 :     GDALDriver *poDriver = new GDALDriver();
     577             : 
     578        1217 :     poDriver->SetDescription("COASP");
     579        1217 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     580        1217 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
     581        1217 :                               "DRDC COASP SAR Processor Raster");
     582        1217 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "hdr");
     583        1217 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/coasp.html");
     584        1217 :     poDriver->pfnIdentify = COASPDataset::Identify;
     585        1217 :     poDriver->pfnOpen = COASPDataset::Open;
     586        1217 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     587             : }

Generated by: LCOV version 1.14