LCOV - code coverage report
Current view: top level - frmts/northwood - grcdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 106 150 70.7 %
Date: 2024-04-29 17:29:47 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             :  * Permission is hereby granted, free of charge, to any person obtaining a
      12             :  * copy of this software and associated documentation files (the "Software"),
      13             :  * to deal in the Software without restriction, including without limitation
      14             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15             :  * and/or sell copies of the Software, and to permit persons to whom the
      16             :  * Software is furnished to do so, subject to the following conditions:
      17             :  *
      18             :  * The above copyright notice and this permission notice shall be included
      19             :  * in all copies or substantial portions of the Software.
      20             :  *
      21             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27             :  * DEALINGS IN THE SOFTWARE.
      28             :  ****************************************************************************/
      29             : 
      30             : #include "gdal_frmts.h"
      31             : #include "gdal_pam.h"
      32             : #include "northwood.h"
      33             : 
      34             : #ifdef MSVC
      35             : #include "..\..\ogr\ogrsf_frmts\mitab\mitab.h"
      36             : #else
      37             : #include "../../ogr/ogrsf_frmts/mitab/mitab.h"
      38             : #endif
      39             : 
      40             : /************************************************************************/
      41             : /* ==================================================================== */
      42             : /*                             NWT_GRCDataset                           */
      43             : /* ==================================================================== */
      44             : /************************************************************************/
      45             : class NWT_GRCRasterBand;
      46             : 
      47             : class NWT_GRCDataset final : public GDALPamDataset
      48             : {
      49             :     friend class NWT_GRCRasterBand;
      50             : 
      51             :   private:
      52             :     VSILFILE *fp;
      53             :     GByte abyHeader[1024];
      54             :     NWT_GRID *pGrd;
      55             :     char **papszCategories;
      56             :     mutable OGRSpatialReference m_oSRS{};
      57             : 
      58             :     NWT_GRCDataset(const NWT_GRCDataset &) = delete;
      59             :     NWT_GRCDataset &operator=(const NWT_GRCDataset &) = delete;
      60             : 
      61             :   protected:
      62             :     GDALColorTable *poColorTable;
      63             : 
      64             :   public:
      65             :     NWT_GRCDataset();
      66             :     ~NWT_GRCDataset();
      67             : 
      68             :     static GDALDataset *Open(GDALOpenInfo *);
      69             :     static int Identify(GDALOpenInfo *poOpenInfo);
      70             : 
      71             :     CPLErr GetGeoTransform(double *padfTransform) override;
      72             :     const OGRSpatialReference *GetSpatialRef() const override;
      73             : };
      74             : 
      75             : /************************************************************************/
      76             : /* ==================================================================== */
      77             : /*                            NWT_GRCRasterBand                         */
      78             : /* ==================================================================== */
      79             : /************************************************************************/
      80             : 
      81             : class NWT_GRCRasterBand final : public GDALPamRasterBand
      82             : {
      83             :     friend class NWT_GRCDataset;
      84             : 
      85             :   public:
      86             :     NWT_GRCRasterBand(NWT_GRCDataset *, int);
      87             :     virtual ~NWT_GRCRasterBand();
      88             : 
      89             :     virtual CPLErr IReadBlock(int, int, void *) override;
      90             :     virtual double GetNoDataValue(int *pbSuccess) override;
      91             : 
      92             :     virtual GDALColorInterp GetColorInterpretation() override;
      93             :     virtual char **GetCategoryNames() override;
      94             :     virtual GDALColorTable *GetColorTable() override;
      95             : };
      96             : 
      97             : /************************************************************************/
      98             : /*                           NWT_GRCRasterBand()                        */
      99             : /************************************************************************/
     100             : 
     101           2 : NWT_GRCRasterBand::NWT_GRCRasterBand(NWT_GRCDataset *poDSIn, int nBandIn)
     102             : {
     103           2 :     poDS = poDSIn;
     104           2 :     nBand = nBandIn;
     105           2 :     NWT_GRCDataset *poGDS = cpl::down_cast<NWT_GRCDataset *>(poDS);
     106             : 
     107           2 :     if (poGDS->pGrd->nBitsPerPixel == 8)
     108           2 :         eDataType = GDT_Byte;
     109           0 :     else if (poGDS->pGrd->nBitsPerPixel == 16)
     110           0 :         eDataType = GDT_UInt16;
     111             :     else                         /* if( poGDS->pGrd->nBitsPerPixel == 32 ) */
     112           0 :         eDataType = GDT_UInt32;  // this would be funny
     113             : 
     114           2 :     nBlockXSize = poDS->GetRasterXSize();
     115           2 :     nBlockYSize = 1;
     116             : 
     117             :     // load the color table and might as well to the ClassNames
     118           2 :     poGDS->poColorTable = new GDALColorTable();
     119             : 
     120           2 :     GDALColorEntry oEntry = {255, 255, 255, 0};
     121             :     // null value = 0 is transparent
     122             :     // alpha 0 = transparent
     123             : 
     124           2 :     poGDS->poColorTable->SetColorEntry(0, &oEntry);
     125             : 
     126           8 :     for (int i = 0;
     127           8 :          i < static_cast<int>(poGDS->pGrd->stClassDict->nNumClassifiedItems);
     128             :          i++)
     129             :     {
     130           6 :         oEntry.c1 = poGDS->pGrd->stClassDict->stClassifiedItem[i]->r;
     131           6 :         oEntry.c2 = poGDS->pGrd->stClassDict->stClassifiedItem[i]->g;
     132           6 :         oEntry.c3 = poGDS->pGrd->stClassDict->stClassifiedItem[i]->b;
     133           6 :         oEntry.c4 = 255;  // alpha 255 = solid
     134             : 
     135           6 :         poGDS->poColorTable->SetColorEntry(
     136           6 :             poGDS->pGrd->stClassDict->stClassifiedItem[i]->usPixVal, &oEntry);
     137             :     }
     138             : 
     139             :     // find the max value used in the grc
     140           2 :     int maxValue = 0;
     141           8 :     for (int i = 0;
     142           8 :          i < static_cast<int>(poGDS->pGrd->stClassDict->nNumClassifiedItems);
     143             :          i++)
     144             :     {
     145           6 :         if (poGDS->pGrd->stClassDict->stClassifiedItem[i]->usPixVal > maxValue)
     146           6 :             maxValue = poGDS->pGrd->stClassDict->stClassifiedItem[i]->usPixVal;
     147             :     }
     148             : 
     149             :     // load a value for the null value
     150           2 :     poGDS->papszCategories = CSLAddString(poGDS->papszCategories, "No Data");
     151             : 
     152             :     // for the class names we need to load nulls string for all classes that
     153             :     // are not defined
     154           8 :     for (int val = 1; val <= maxValue; val++)
     155             :     {
     156           6 :         int i = 0;
     157             :         // Loop through the GRC dictionary to see if the value is defined.
     158           6 :         for (; i <
     159          12 :                static_cast<int>(poGDS->pGrd->stClassDict->nNumClassifiedItems);
     160             :              i++)
     161             :         {
     162          12 :             if (static_cast<int>(
     163          12 :                     poGDS->pGrd->stClassDict->stClassifiedItem[i]->usPixVal) ==
     164             :                 val)
     165             :             {
     166          12 :                 poGDS->papszCategories = CSLAddString(
     167             :                     poGDS->papszCategories,
     168           6 :                     poGDS->pGrd->stClassDict->stClassifiedItem[i]->szClassName);
     169           6 :                 break;
     170             :             }
     171             :         }
     172           6 :         if (i >=
     173           6 :             static_cast<int>(poGDS->pGrd->stClassDict->nNumClassifiedItems))
     174           0 :             poGDS->papszCategories = CSLAddString(poGDS->papszCategories, "");
     175             :     }
     176           2 : }
     177             : 
     178           4 : NWT_GRCRasterBand::~NWT_GRCRasterBand()
     179             : {
     180           4 : }
     181             : 
     182           0 : double NWT_GRCRasterBand::GetNoDataValue(int *pbSuccess)
     183             : {
     184           0 :     if (pbSuccess != nullptr)
     185           0 :         *pbSuccess = TRUE;
     186             : 
     187           0 :     return 0.0;  // Northwood grid 0 is always null.
     188             : }
     189             : 
     190             : // return an array of null terminated strings for the class names
     191           0 : char **NWT_GRCRasterBand::GetCategoryNames()
     192             : {
     193           0 :     NWT_GRCDataset *poGDS = cpl::down_cast<NWT_GRCDataset *>(poDS);
     194             : 
     195           0 :     return poGDS->papszCategories;
     196             : }
     197             : 
     198             : // return the color table
     199           0 : GDALColorTable *NWT_GRCRasterBand::GetColorTable()
     200             : {
     201           0 :     NWT_GRCDataset *poGDS = cpl::down_cast<NWT_GRCDataset *>(poDS);
     202             : 
     203           0 :     return poGDS->poColorTable;
     204             : }
     205             : 
     206           0 : GDALColorInterp NWT_GRCRasterBand::GetColorInterpretation()
     207             : {
     208           0 :     if (nBand == 1)
     209           0 :         return GCI_PaletteIndex;
     210             : 
     211           0 :     return GCI_Undefined;
     212             : }
     213             : 
     214             : /************************************************************************/
     215             : /*                             IReadBlock()                             */
     216             : /************************************************************************/
     217         181 : CPLErr NWT_GRCRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
     218             :                                      void *pImage)
     219             : {
     220         181 :     NWT_GRCDataset *poGDS = cpl::down_cast<NWT_GRCDataset *>(poDS);
     221         181 :     const int nBytesPerPixel = poGDS->pGrd->nBitsPerPixel / 8;
     222         181 :     if (nBytesPerPixel <= 0 || nBlockXSize > INT_MAX / nBytesPerPixel)
     223           0 :         return CE_Failure;
     224         181 :     const int nRecordSize = nBlockXSize * nBytesPerPixel;
     225             : 
     226         181 :     if (nBand == 1)
     227             :     {  // grc's are just one band of indices
     228         181 :         VSIFSeekL(poGDS->fp,
     229         181 :                   1024 + nRecordSize * static_cast<vsi_l_offset>(nBlockYOff),
     230             :                   SEEK_SET);
     231         181 :         if (static_cast<int>(VSIFReadL(pImage, 1, nRecordSize, poGDS->fp)) !=
     232             :             nRecordSize)
     233           0 :             return CE_Failure;
     234             :     }
     235             :     else
     236             :     {
     237           0 :         CPLError(CE_Failure, CPLE_IllegalArg, "No band number %d", nBand);
     238           0 :         return CE_Failure;
     239             :     }
     240         181 :     return CE_None;
     241             : }
     242             : 
     243             : /************************************************************************/
     244             : /* ==================================================================== */
     245             : /*                          NWT_GRCDataset                              */
     246             : /* ==================================================================== */
     247             : /************************************************************************/
     248           2 : NWT_GRCDataset::NWT_GRCDataset()
     249             :     : fp(nullptr), pGrd(nullptr), papszCategories(nullptr),
     250           2 :       poColorTable(nullptr)
     251             : {
     252           2 :     m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     253           2 :     memset(abyHeader, 0, sizeof(abyHeader));
     254           2 : }
     255             : 
     256             : /************************************************************************/
     257             : /*                            ~NWT_GRCDataset()                         */
     258             : /************************************************************************/
     259           4 : NWT_GRCDataset::~NWT_GRCDataset()
     260             : {
     261           2 :     delete poColorTable;
     262           2 :     CSLDestroy(papszCategories);
     263             : 
     264           2 :     NWT_GRCDataset::FlushCache(true);
     265           2 :     pGrd->fp = nullptr;  // this prevents nwtCloseGrid from closing the fp
     266           2 :     nwtCloseGrid(pGrd);
     267             : 
     268           2 :     if (fp != nullptr)
     269           2 :         VSIFCloseL(fp);
     270           4 : }
     271             : 
     272             : /************************************************************************/
     273             : /*                          GetGeoTransform()                           */
     274             : /************************************************************************/
     275           0 : CPLErr NWT_GRCDataset::GetGeoTransform(double *padfTransform)
     276             : {
     277           0 :     padfTransform[0] = pGrd->dfMinX - (pGrd->dfStepSize * 0.5);
     278           0 :     padfTransform[3] = pGrd->dfMaxY + (pGrd->dfStepSize * 0.5);
     279           0 :     padfTransform[1] = pGrd->dfStepSize;
     280           0 :     padfTransform[2] = 0.0;
     281             : 
     282           0 :     padfTransform[4] = 0.0;
     283           0 :     padfTransform[5] = -1 * pGrd->dfStepSize;
     284             : 
     285           0 :     return CE_None;
     286             : }
     287             : 
     288             : /************************************************************************/
     289             : /*                          GetSpatialRef()                             */
     290             : /************************************************************************/
     291           0 : const OGRSpatialReference *NWT_GRCDataset::GetSpatialRef() const
     292             : {
     293           0 :     if (m_oSRS.IsEmpty())
     294             :     {
     295             :         OGRSpatialReference *poSpatialRef =
     296           0 :             MITABCoordSys2SpatialRef(pGrd->cMICoordSys);
     297           0 :         if (poSpatialRef)
     298             :         {
     299           0 :             m_oSRS = *poSpatialRef;
     300           0 :             m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     301           0 :             poSpatialRef->Release();
     302             :         }
     303             :     }
     304           0 :     return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
     305             : }
     306             : 
     307             : /************************************************************************/
     308             : /*                              Identify()                              */
     309             : /************************************************************************/
     310             : 
     311       48157 : int NWT_GRCDataset::Identify(GDALOpenInfo *poOpenInfo)
     312             : {
     313             :     /* -------------------------------------------------------------------- */
     314             :     /*  Look for the header                                                 */
     315             :     /* -------------------------------------------------------------------- */
     316       48157 :     if (poOpenInfo->nHeaderBytes < 1024)
     317       46504 :         return FALSE;
     318             : 
     319        1653 :     if (poOpenInfo->pabyHeader[0] != 'H' || poOpenInfo->pabyHeader[1] != 'G' ||
     320           8 :         poOpenInfo->pabyHeader[2] != 'P' || poOpenInfo->pabyHeader[3] != 'C' ||
     321           8 :         poOpenInfo->pabyHeader[4] != '8')
     322        1649 :         return FALSE;
     323             : 
     324           4 :     return TRUE;
     325             : }
     326             : 
     327             : /************************************************************************/
     328             : /*                                Open()                                */
     329             : /************************************************************************/
     330             : 
     331           2 : GDALDataset *NWT_GRCDataset::Open(GDALOpenInfo *poOpenInfo)
     332             : {
     333           2 :     if (!Identify(poOpenInfo) || poOpenInfo->fpL == nullptr)
     334           0 :         return nullptr;
     335             : 
     336             :     /* -------------------------------------------------------------------- */
     337             :     /*      Create a corresponding GDALDataset.                             */
     338             :     /* -------------------------------------------------------------------- */
     339           2 :     NWT_GRCDataset *poDS = new NWT_GRCDataset();
     340             : 
     341           2 :     poDS->fp = poOpenInfo->fpL;
     342           2 :     poOpenInfo->fpL = nullptr;
     343             : 
     344             :     /* -------------------------------------------------------------------- */
     345             :     /*      Read the header.                                                */
     346             :     /* -------------------------------------------------------------------- */
     347           2 :     VSIFSeekL(poDS->fp, 0, SEEK_SET);
     348           2 :     VSIFReadL(poDS->abyHeader, 1, 1024, poDS->fp);
     349           2 :     poDS->pGrd = static_cast<NWT_GRID *>(malloc(sizeof(NWT_GRID)));
     350             : 
     351           2 :     poDS->pGrd->fp = poDS->fp;
     352             : 
     353           2 :     if (!nwt_ParseHeader(poDS->pGrd, poDS->abyHeader) ||
     354           4 :         !GDALCheckDatasetDimensions(poDS->pGrd->nXSide, poDS->pGrd->nYSide) ||
     355           2 :         poDS->pGrd->stClassDict == nullptr)
     356             :     {
     357           0 :         delete poDS;
     358           0 :         return nullptr;
     359             :     }
     360             : 
     361           2 :     if (poDS->pGrd->nBitsPerPixel != 8 && poDS->pGrd->nBitsPerPixel != 16 &&
     362           0 :         poDS->pGrd->nBitsPerPixel != 32)
     363             :     {
     364           0 :         delete poDS;
     365           0 :         return nullptr;
     366             :     }
     367             : 
     368           2 :     poDS->nRasterXSize = poDS->pGrd->nXSide;
     369           2 :     poDS->nRasterYSize = poDS->pGrd->nYSide;
     370             : 
     371             :     /* -------------------------------------------------------------------- */
     372             :     /*      Create band information objects.                                */
     373             :     /* -------------------------------------------------------------------- */
     374           2 :     poDS->SetBand(1, new NWT_GRCRasterBand(poDS, 1));  // Class Indexes
     375             : 
     376             :     /* -------------------------------------------------------------------- */
     377             :     /*      Initialize any PAM information.                                 */
     378             :     /* -------------------------------------------------------------------- */
     379           2 :     poDS->SetDescription(poOpenInfo->pszFilename);
     380           2 :     poDS->TryLoadXML();
     381             : 
     382             :     /* -------------------------------------------------------------------- */
     383             :     /*      Check for external overviews.                                   */
     384             :     /* -------------------------------------------------------------------- */
     385           2 :     poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename,
     386             :                                 poOpenInfo->GetSiblingFiles());
     387             : 
     388           2 :     return poDS;
     389             : }
     390             : 
     391             : /************************************************************************/
     392             : /*                          GDALRegister_GRC()                          */
     393             : /************************************************************************/
     394             : 
     395        1512 : void GDALRegister_NWT_GRC()
     396             : 
     397             : {
     398        1512 :     if (GDALGetDriverByName("NWT_GRC") != nullptr)
     399         295 :         return;
     400             : 
     401        1217 :     GDALDriver *poDriver = new GDALDriver();
     402             : 
     403        1217 :     poDriver->SetDescription("NWT_GRC");
     404        1217 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     405        1217 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
     406        1217 :                               "Northwood Classified Grid Format .grc/.tab");
     407        1217 :     poDriver->SetMetadataItem(
     408             :         GDAL_DMD_HELPTOPIC,
     409        1217 :         "drivers/raster/nwtgrd.html#driver-capabilities-nwt-grc");
     410        1217 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "grc");
     411        1217 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     412             : 
     413        1217 :     poDriver->pfnOpen = NWT_GRCDataset::Open;
     414        1217 :     poDriver->pfnIdentify = NWT_GRCDataset::Identify;
     415             : 
     416        1217 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     417             : }

Generated by: LCOV version 1.14