LCOV - code coverage report
Current view: top level - frmts/northwood - grcdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 107 151 70.9 %
Date: 2024-11-21 22:18:42 Functions: 10 16 62.5 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GRC Reader
       4             :  * Purpose:  GDAL driver for Northwood Classified Format
       5             :  * Author:   Perry Casson
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2007, Waypoint Information Technology
       9             :  * Copyright (c) 2009-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 "northwood.h"
      17             : #include "ogrmitabspatialref.h"
      18             : 
      19             : /************************************************************************/
      20             : /* ==================================================================== */
      21             : /*                             NWT_GRCDataset                           */
      22             : /* ==================================================================== */
      23             : /************************************************************************/
      24             : class NWT_GRCRasterBand;
      25             : 
      26             : class NWT_GRCDataset final : public GDALPamDataset
      27             : {
      28             :     friend class NWT_GRCRasterBand;
      29             : 
      30             :   private:
      31             :     VSILFILE *fp;
      32             :     GByte abyHeader[1024];
      33             :     NWT_GRID *pGrd;
      34             :     char **papszCategories;
      35             :     mutable OGRSpatialReference m_oSRS{};
      36             : 
      37             :     NWT_GRCDataset(const NWT_GRCDataset &) = delete;
      38             :     NWT_GRCDataset &operator=(const NWT_GRCDataset &) = delete;
      39             : 
      40             :   protected:
      41             :     GDALColorTable *poColorTable;
      42             : 
      43             :   public:
      44             :     NWT_GRCDataset();
      45             :     ~NWT_GRCDataset();
      46             : 
      47             :     static GDALDataset *Open(GDALOpenInfo *);
      48             :     static int Identify(GDALOpenInfo *poOpenInfo);
      49             : 
      50             :     CPLErr GetGeoTransform(double *padfTransform) override;
      51             :     const OGRSpatialReference *GetSpatialRef() const override;
      52             : };
      53             : 
      54             : /************************************************************************/
      55             : /* ==================================================================== */
      56             : /*                            NWT_GRCRasterBand                         */
      57             : /* ==================================================================== */
      58             : /************************************************************************/
      59             : 
      60             : class NWT_GRCRasterBand final : public GDALPamRasterBand
      61             : {
      62             :     friend class NWT_GRCDataset;
      63             : 
      64             :   public:
      65             :     NWT_GRCRasterBand(NWT_GRCDataset *, int);
      66             :     virtual ~NWT_GRCRasterBand();
      67             : 
      68             :     virtual CPLErr IReadBlock(int, int, void *) override;
      69             :     virtual double GetNoDataValue(int *pbSuccess) override;
      70             : 
      71             :     virtual GDALColorInterp GetColorInterpretation() override;
      72             :     virtual char **GetCategoryNames() override;
      73             :     virtual GDALColorTable *GetColorTable() override;
      74             : };
      75             : 
      76             : /************************************************************************/
      77             : /*                           NWT_GRCRasterBand()                        */
      78             : /************************************************************************/
      79             : 
      80           2 : NWT_GRCRasterBand::NWT_GRCRasterBand(NWT_GRCDataset *poDSIn, int nBandIn)
      81             : {
      82           2 :     poDS = poDSIn;
      83           2 :     nBand = nBandIn;
      84           2 :     NWT_GRCDataset *poGDS = cpl::down_cast<NWT_GRCDataset *>(poDS);
      85             : 
      86           2 :     if (poGDS->pGrd->nBitsPerPixel == 8)
      87           2 :         eDataType = GDT_Byte;
      88           0 :     else if (poGDS->pGrd->nBitsPerPixel == 16)
      89           0 :         eDataType = GDT_UInt16;
      90             :     else                         /* if( poGDS->pGrd->nBitsPerPixel == 32 ) */
      91           0 :         eDataType = GDT_UInt32;  // this would be funny
      92             : 
      93           2 :     nBlockXSize = poDS->GetRasterXSize();
      94           2 :     nBlockYSize = 1;
      95             : 
      96             :     // load the color table and might as well to the ClassNames
      97           2 :     poGDS->poColorTable = new GDALColorTable();
      98             : 
      99           2 :     GDALColorEntry oEntry = {255, 255, 255, 0};
     100             :     // null value = 0 is transparent
     101             :     // alpha 0 = transparent
     102             : 
     103           2 :     poGDS->poColorTable->SetColorEntry(0, &oEntry);
     104             : 
     105           8 :     for (int i = 0;
     106           8 :          i < static_cast<int>(poGDS->pGrd->stClassDict->nNumClassifiedItems);
     107             :          i++)
     108             :     {
     109           6 :         oEntry.c1 = poGDS->pGrd->stClassDict->stClassifiedItem[i]->r;
     110           6 :         oEntry.c2 = poGDS->pGrd->stClassDict->stClassifiedItem[i]->g;
     111           6 :         oEntry.c3 = poGDS->pGrd->stClassDict->stClassifiedItem[i]->b;
     112           6 :         oEntry.c4 = 255;  // alpha 255 = solid
     113             : 
     114           6 :         poGDS->poColorTable->SetColorEntry(
     115           6 :             poGDS->pGrd->stClassDict->stClassifiedItem[i]->usPixVal, &oEntry);
     116             :     }
     117             : 
     118             :     // find the max value used in the grc
     119           2 :     int maxValue = 0;
     120           8 :     for (int i = 0;
     121           8 :          i < static_cast<int>(poGDS->pGrd->stClassDict->nNumClassifiedItems);
     122             :          i++)
     123             :     {
     124           6 :         if (poGDS->pGrd->stClassDict->stClassifiedItem[i]->usPixVal > maxValue)
     125           6 :             maxValue = poGDS->pGrd->stClassDict->stClassifiedItem[i]->usPixVal;
     126             :     }
     127             : 
     128             :     // load a value for the null value
     129           2 :     poGDS->papszCategories = CSLAddString(poGDS->papszCategories, "No Data");
     130             : 
     131             :     // for the class names we need to load nulls string for all classes that
     132             :     // are not defined
     133           8 :     for (int val = 1; val <= maxValue; val++)
     134             :     {
     135           6 :         int i = 0;
     136             :         // Loop through the GRC dictionary to see if the value is defined.
     137           6 :         for (; i <
     138          12 :                static_cast<int>(poGDS->pGrd->stClassDict->nNumClassifiedItems);
     139             :              i++)
     140             :         {
     141          12 :             if (static_cast<int>(
     142          12 :                     poGDS->pGrd->stClassDict->stClassifiedItem[i]->usPixVal) ==
     143             :                 val)
     144             :             {
     145          12 :                 poGDS->papszCategories = CSLAddString(
     146             :                     poGDS->papszCategories,
     147           6 :                     poGDS->pGrd->stClassDict->stClassifiedItem[i]->szClassName);
     148           6 :                 break;
     149             :             }
     150             :         }
     151           6 :         if (i >=
     152           6 :             static_cast<int>(poGDS->pGrd->stClassDict->nNumClassifiedItems))
     153           0 :             poGDS->papszCategories = CSLAddString(poGDS->papszCategories, "");
     154             :     }
     155           2 : }
     156             : 
     157           4 : NWT_GRCRasterBand::~NWT_GRCRasterBand()
     158             : {
     159           4 : }
     160             : 
     161           0 : double NWT_GRCRasterBand::GetNoDataValue(int *pbSuccess)
     162             : {
     163           0 :     if (pbSuccess != nullptr)
     164           0 :         *pbSuccess = TRUE;
     165             : 
     166           0 :     return 0.0;  // Northwood grid 0 is always null.
     167             : }
     168             : 
     169             : // return an array of null terminated strings for the class names
     170           0 : char **NWT_GRCRasterBand::GetCategoryNames()
     171             : {
     172           0 :     NWT_GRCDataset *poGDS = cpl::down_cast<NWT_GRCDataset *>(poDS);
     173             : 
     174           0 :     return poGDS->papszCategories;
     175             : }
     176             : 
     177             : // return the color table
     178           0 : GDALColorTable *NWT_GRCRasterBand::GetColorTable()
     179             : {
     180           0 :     NWT_GRCDataset *poGDS = cpl::down_cast<NWT_GRCDataset *>(poDS);
     181             : 
     182           0 :     return poGDS->poColorTable;
     183             : }
     184             : 
     185           0 : GDALColorInterp NWT_GRCRasterBand::GetColorInterpretation()
     186             : {
     187           0 :     if (nBand == 1)
     188           0 :         return GCI_PaletteIndex;
     189             : 
     190           0 :     return GCI_Undefined;
     191             : }
     192             : 
     193             : /************************************************************************/
     194             : /*                             IReadBlock()                             */
     195             : /************************************************************************/
     196         181 : CPLErr NWT_GRCRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
     197             :                                      void *pImage)
     198             : {
     199         181 :     NWT_GRCDataset *poGDS = cpl::down_cast<NWT_GRCDataset *>(poDS);
     200         181 :     const int nBytesPerPixel = poGDS->pGrd->nBitsPerPixel / 8;
     201         181 :     if (nBytesPerPixel <= 0 || nBlockXSize > INT_MAX / nBytesPerPixel)
     202           0 :         return CE_Failure;
     203         181 :     const int nRecordSize = nBlockXSize * nBytesPerPixel;
     204             : 
     205         181 :     if (nBand == 1)
     206             :     {  // grc's are just one band of indices
     207         181 :         VSIFSeekL(poGDS->fp,
     208         181 :                   1024 + nRecordSize * static_cast<vsi_l_offset>(nBlockYOff),
     209             :                   SEEK_SET);
     210         181 :         if (static_cast<int>(VSIFReadL(pImage, 1, nRecordSize, poGDS->fp)) !=
     211             :             nRecordSize)
     212           0 :             return CE_Failure;
     213             :     }
     214             :     else
     215             :     {
     216           0 :         CPLError(CE_Failure, CPLE_IllegalArg, "No band number %d", nBand);
     217           0 :         return CE_Failure;
     218             :     }
     219         181 :     return CE_None;
     220             : }
     221             : 
     222             : /************************************************************************/
     223             : /* ==================================================================== */
     224             : /*                          NWT_GRCDataset                              */
     225             : /* ==================================================================== */
     226             : /************************************************************************/
     227           2 : NWT_GRCDataset::NWT_GRCDataset()
     228             :     : fp(nullptr), pGrd(nullptr), papszCategories(nullptr),
     229           2 :       poColorTable(nullptr)
     230             : {
     231           2 :     m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     232           2 :     memset(abyHeader, 0, sizeof(abyHeader));
     233           2 : }
     234             : 
     235             : /************************************************************************/
     236             : /*                            ~NWT_GRCDataset()                         */
     237             : /************************************************************************/
     238           4 : NWT_GRCDataset::~NWT_GRCDataset()
     239             : {
     240           2 :     delete poColorTable;
     241           2 :     CSLDestroy(papszCategories);
     242             : 
     243           2 :     NWT_GRCDataset::FlushCache(true);
     244           2 :     pGrd->fp = nullptr;  // this prevents nwtCloseGrid from closing the fp
     245           2 :     nwtCloseGrid(pGrd);
     246             : 
     247           2 :     if (fp != nullptr)
     248           2 :         VSIFCloseL(fp);
     249           4 : }
     250             : 
     251             : /************************************************************************/
     252             : /*                          GetGeoTransform()                           */
     253             : /************************************************************************/
     254           0 : CPLErr NWT_GRCDataset::GetGeoTransform(double *padfTransform)
     255             : {
     256           0 :     padfTransform[0] = pGrd->dfMinX - (pGrd->dfStepSize * 0.5);
     257           0 :     padfTransform[3] = pGrd->dfMaxY + (pGrd->dfStepSize * 0.5);
     258           0 :     padfTransform[1] = pGrd->dfStepSize;
     259           0 :     padfTransform[2] = 0.0;
     260             : 
     261           0 :     padfTransform[4] = 0.0;
     262           0 :     padfTransform[5] = -1 * pGrd->dfStepSize;
     263             : 
     264           0 :     return CE_None;
     265             : }
     266             : 
     267             : /************************************************************************/
     268             : /*                          GetSpatialRef()                             */
     269             : /************************************************************************/
     270           0 : const OGRSpatialReference *NWT_GRCDataset::GetSpatialRef() const
     271             : {
     272           0 :     if (m_oSRS.IsEmpty())
     273             :     {
     274             :         OGRSpatialReference *poSpatialRef =
     275           0 :             MITABCoordSys2SpatialRef(pGrd->cMICoordSys);
     276           0 :         if (poSpatialRef)
     277             :         {
     278           0 :             m_oSRS = *poSpatialRef;
     279           0 :             m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     280           0 :             poSpatialRef->Release();
     281             :         }
     282             :     }
     283           0 :     return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
     284             : }
     285             : 
     286             : /************************************************************************/
     287             : /*                              Identify()                              */
     288             : /************************************************************************/
     289             : 
     290       50848 : int NWT_GRCDataset::Identify(GDALOpenInfo *poOpenInfo)
     291             : {
     292             :     /* -------------------------------------------------------------------- */
     293             :     /*  Look for the header                                                 */
     294             :     /* -------------------------------------------------------------------- */
     295       50848 :     if (poOpenInfo->nHeaderBytes < 1024)
     296       49136 :         return FALSE;
     297             : 
     298        1712 :     if (poOpenInfo->pabyHeader[0] != 'H' || poOpenInfo->pabyHeader[1] != 'G' ||
     299           8 :         poOpenInfo->pabyHeader[2] != 'P' || poOpenInfo->pabyHeader[3] != 'C' ||
     300           8 :         poOpenInfo->pabyHeader[4] != '8')
     301        1708 :         return FALSE;
     302             : 
     303           4 :     return TRUE;
     304             : }
     305             : 
     306             : /************************************************************************/
     307             : /*                                Open()                                */
     308             : /************************************************************************/
     309             : 
     310           2 : GDALDataset *NWT_GRCDataset::Open(GDALOpenInfo *poOpenInfo)
     311             : {
     312           2 :     if (!Identify(poOpenInfo) || poOpenInfo->fpL == nullptr)
     313           0 :         return nullptr;
     314             : 
     315             :     /* -------------------------------------------------------------------- */
     316             :     /*      Create a corresponding GDALDataset.                             */
     317             :     /* -------------------------------------------------------------------- */
     318           2 :     NWT_GRCDataset *poDS = new NWT_GRCDataset();
     319             : 
     320           2 :     poDS->fp = poOpenInfo->fpL;
     321           2 :     poOpenInfo->fpL = nullptr;
     322             : 
     323             :     /* -------------------------------------------------------------------- */
     324             :     /*      Read the header.                                                */
     325             :     /* -------------------------------------------------------------------- */
     326           2 :     VSIFSeekL(poDS->fp, 0, SEEK_SET);
     327           2 :     VSIFReadL(poDS->abyHeader, 1, 1024, poDS->fp);
     328           2 :     poDS->pGrd = static_cast<NWT_GRID *>(malloc(sizeof(NWT_GRID)));
     329             : 
     330           2 :     poDS->pGrd->fp = poDS->fp;
     331             : 
     332           2 :     if (!nwt_ParseHeader(poDS->pGrd, poDS->abyHeader) ||
     333           4 :         !GDALCheckDatasetDimensions(poDS->pGrd->nXSide, poDS->pGrd->nYSide) ||
     334           2 :         poDS->pGrd->stClassDict == nullptr)
     335             :     {
     336           0 :         delete poDS;
     337           0 :         return nullptr;
     338             :     }
     339             : 
     340           2 :     if (poDS->pGrd->nBitsPerPixel != 8 && poDS->pGrd->nBitsPerPixel != 16 &&
     341           0 :         poDS->pGrd->nBitsPerPixel != 32)
     342             :     {
     343           0 :         delete poDS;
     344           0 :         return nullptr;
     345             :     }
     346             : 
     347           2 :     poDS->nRasterXSize = poDS->pGrd->nXSide;
     348           2 :     poDS->nRasterYSize = poDS->pGrd->nYSide;
     349             : 
     350             :     /* -------------------------------------------------------------------- */
     351             :     /*      Create band information objects.                                */
     352             :     /* -------------------------------------------------------------------- */
     353           2 :     poDS->SetBand(1, new NWT_GRCRasterBand(poDS, 1));  // Class Indexes
     354             : 
     355             :     /* -------------------------------------------------------------------- */
     356             :     /*      Initialize any PAM information.                                 */
     357             :     /* -------------------------------------------------------------------- */
     358           2 :     poDS->SetDescription(poOpenInfo->pszFilename);
     359           2 :     poDS->TryLoadXML();
     360             : 
     361             :     /* -------------------------------------------------------------------- */
     362             :     /*      Check for external overviews.                                   */
     363             :     /* -------------------------------------------------------------------- */
     364           4 :     poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename,
     365           2 :                                 poOpenInfo->GetSiblingFiles());
     366             : 
     367           2 :     return poDS;
     368             : }
     369             : 
     370             : /************************************************************************/
     371             : /*                          GDALRegister_GRC()                          */
     372             : /************************************************************************/
     373             : 
     374        1595 : void GDALRegister_NWT_GRC()
     375             : 
     376             : {
     377        1595 :     if (GDALGetDriverByName("NWT_GRC") != nullptr)
     378         302 :         return;
     379             : 
     380        1293 :     GDALDriver *poDriver = new GDALDriver();
     381             : 
     382        1293 :     poDriver->SetDescription("NWT_GRC");
     383        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     384        1293 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
     385        1293 :                               "Northwood Classified Grid Format .grc/.tab");
     386        1293 :     poDriver->SetMetadataItem(
     387             :         GDAL_DMD_HELPTOPIC,
     388        1293 :         "drivers/raster/nwtgrd.html#driver-capabilities-nwt-grc");
     389        1293 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "grc");
     390        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     391             : 
     392        1293 :     poDriver->pfnOpen = NWT_GRCDataset::Open;
     393        1293 :     poDriver->pfnIdentify = NWT_GRCDataset::Identify;
     394             : 
     395        1293 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     396             : }

Generated by: LCOV version 1.14