LCOV - code coverage report
Current view: top level - frmts/fit - fitdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 291 645 45.1 %
Date: 2024-04-27 17:22:41 Functions: 11 13 84.6 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  FIT Driver
       4             :  * Purpose:  Implement FIT Support - not using the SGI iflFIT library.
       5             :  * Author:   Philip Nemec, nemec@keyholecorp.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2001, Keyhole, Inc.
       9             :  * Copyright (c) 2007-2011, 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 "cpl_string.h"
      31             : #include "fit.h"
      32             : #include "gdal_frmts.h"
      33             : #include "gdal_pam.h"
      34             : #include "gstEndian.h"
      35             : #include "cpl_safemaths.hpp"
      36             : 
      37             : #include <algorithm>
      38             : #include <limits>
      39             : 
      40             : constexpr size_t FIT_PAGE_SIZE = 128;
      41             : 
      42             : using namespace gstEndian;
      43             : 
      44             : /************************************************************************/
      45             : /* ==================================================================== */
      46             : /*                              FITDataset                              */
      47             : /* ==================================================================== */
      48             : /************************************************************************/
      49             : 
      50             : class FITRasterBand;
      51             : 
      52             : class FITDataset final : public GDALPamDataset
      53             : {
      54             :     friend class FITRasterBand;
      55             : 
      56             :     VSILFILE *fp;
      57             :     FITinfo *info;
      58             :     double adfGeoTransform[6];
      59             : 
      60             :   public:
      61             :     FITDataset();
      62             :     ~FITDataset();
      63             :     static GDALDataset *Open(GDALOpenInfo *);
      64             :     // virtual CPLErr GetGeoTransform( double * );
      65             : };
      66             : 
      67             : static GDALDataset *FITCreateCopy(const char *pszFilename, GDALDataset *poSrcDS,
      68             :                                   int bStrict, char **papszOptions,
      69             :                                   GDALProgressFunc pfnProgress,
      70             :                                   void *pProgressData);
      71             : 
      72             : /************************************************************************/
      73             : /* ==================================================================== */
      74             : /*                            FITRasterBand                             */
      75             : /* ==================================================================== */
      76             : /************************************************************************/
      77             : 
      78             : class FITRasterBand final : public GDALPamRasterBand
      79             : {
      80             :     friend class FITDataset;
      81             : 
      82             :     unsigned long recordSize;  // number of bytes of a single page/block/record
      83             :     unsigned long numXBlocks;  // number of pages in the X direction
      84             :     unsigned long numYBlocks;  // number of pages in the Y direction
      85             :     unsigned long bytesPerComponent;
      86             :     unsigned long bytesPerPixel;
      87             :     char *tmpImage;
      88             : 
      89             :   public:
      90             :     FITRasterBand(FITDataset *, int nBandIn, int nBandsIn);
      91             :     ~FITRasterBand() override;
      92             : 
      93             :     // should override RasterIO eventually.
      94             : 
      95             :     CPLErr IReadBlock(int, int, void *) override;
      96             :     // virtual CPLErr WriteBlock( int, int, void * );
      97             :     double GetMinimum(int *pbSuccess) override;
      98             :     double GetMaximum(int *pbSuccess) override;
      99             :     GDALColorInterp GetColorInterpretation() override;
     100             : };
     101             : 
     102             : /************************************************************************/
     103             : /*                           FITRasterBand()                            */
     104             : /************************************************************************/
     105             : 
     106          35 : FITRasterBand::FITRasterBand(FITDataset *poDSIn, int nBandIn, int nBandsIn)
     107             :     : recordSize(0), numXBlocks(0), numYBlocks(0), bytesPerComponent(0),
     108          35 :       bytesPerPixel(0), tmpImage(nullptr)
     109             : {
     110          35 :     poDS = poDSIn;
     111          35 :     nBand = nBandIn;
     112             : 
     113             :     /* -------------------------------------------------------------------- */
     114             :     /*      Get the GDAL data type.                                         */
     115             :     /* -------------------------------------------------------------------- */
     116          35 :     eDataType = fitDataType(poDSIn->info->dtype);
     117             : 
     118             :     /* -------------------------------------------------------------------- */
     119             :     /*      Get the page sizes.                                             */
     120             :     /* -------------------------------------------------------------------- */
     121          35 :     nBlockXSize = poDSIn->info->xPageSize;
     122          35 :     nBlockYSize = poDSIn->info->yPageSize;
     123             : 
     124             :     /* -------------------------------------------------------------------- */
     125             :     /*      Calculate the values for record offset calculations.             */
     126             :     /* -------------------------------------------------------------------- */
     127          35 :     bytesPerComponent = GDALGetDataTypeSizeBytes(eDataType);
     128          35 :     if (bytesPerComponent == 0)
     129           0 :         return;
     130          35 :     bytesPerPixel = nBandsIn * bytesPerComponent;
     131          35 :     const auto knIntMax = std::numeric_limits<int>::max();
     132          35 :     if (nBlockXSize <= 0 || nBlockYSize <= 0 ||
     133          35 :         nBlockXSize > knIntMax / static_cast<int>(bytesPerPixel) ||
     134          35 :         nBlockYSize >
     135          35 :             knIntMax / (nBlockXSize * static_cast<int>(bytesPerPixel)))
     136           0 :         return;
     137          35 :     recordSize = bytesPerPixel * nBlockXSize * nBlockYSize;
     138          35 :     numXBlocks = (unsigned long)ceil((double)poDSIn->info->xSize / nBlockXSize);
     139          35 :     numYBlocks = (unsigned long)ceil((double)poDSIn->info->ySize / nBlockYSize);
     140             : 
     141          35 :     tmpImage = (char *)VSI_MALLOC_VERBOSE(recordSize);
     142             :     /* -------------------------------------------------------------------- */
     143             :     /*      Set the access flag.  For now we set it the same as the         */
     144             :     /*      whole dataset, but eventually this should take account of       */
     145             :     /*      locked channels, or read-only secondary data files.             */
     146             :     /* -------------------------------------------------------------------- */
     147             :     /* ... */
     148             : }
     149             : 
     150          70 : FITRasterBand::~FITRasterBand()
     151             : {
     152          35 :     VSIFree(tmpImage);
     153          70 : }
     154             : 
     155             : /************************************************************************/
     156             : /*                            IReadBlock()                              */
     157             : /************************************************************************/
     158             : 
     159             : #define COPY_XFIRST(t)                                                         \
     160             :     {                                                                          \
     161             :         t *dstp = (t *)pImage;                                                 \
     162             :         t *srcp = (t *)tmpImage;                                               \
     163             :         srcp += nBand - 1;                                                     \
     164             :         long imacro = 0;                                                       \
     165             :         for (long y = ystart; y != ystop; y += yinc)                           \
     166             :             for (long x = xstart; x != xstop; x += xinc, imacro++)             \
     167             :             {                                                                  \
     168             :                 dstp[imacro] = srcp[(y * nBlockXSize + x) * poFIT_DS->nBands]; \
     169             :             }                                                                  \
     170             :     }
     171             : 
     172             : #define COPY_YFIRST(t)                                                         \
     173             :     {                                                                          \
     174             :         t *dstp = (t *)pImage;                                                 \
     175             :         t *srcp = (t *)tmpImage;                                               \
     176             :         srcp += nBand - 1;                                                     \
     177             :         long imacro = 0;                                                       \
     178             :         for (long x = xstart; x != xstop; x += xinc, imacro++)                 \
     179             :             for (long y = ystart; y != ystop; y += yinc)                       \
     180             :             {                                                                  \
     181             :                 dstp[imacro] = srcp[(x * nBlockYSize + y) * poFIT_DS->nBands]; \
     182             :             }                                                                  \
     183             :     }
     184             : 
     185         700 : CPLErr FITRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
     186             : 
     187             : {
     188         700 :     FITDataset *poFIT_DS = (FITDataset *)poDS;
     189             : 
     190         700 :     uint64 tilenum = 0;
     191             : 
     192         700 :     switch (poFIT_DS->info->space)
     193             :     {
     194         700 :         case 1:
     195             :             // iflUpperLeftOrigin - from upper left corner
     196             :             // scan right then down
     197         700 :             tilenum = nBlockYOff * numXBlocks + nBlockXOff;
     198         700 :             break;
     199           0 :         case 2:
     200             :             // iflUpperRightOrigin - from upper right corner
     201             :             // scan left then down
     202           0 :             tilenum = numYBlocks * numXBlocks + (numXBlocks - 1 - nBlockXOff);
     203           0 :             break;
     204           0 :         case 3:
     205             :             // iflLowerRightOrigin - from lower right corner
     206             :             // scan left then up
     207           0 :             tilenum = (numYBlocks - 1 - nBlockYOff) * numXBlocks +
     208           0 :                       (numXBlocks - 1 - nBlockXOff);
     209           0 :             break;
     210           0 :         case 4:
     211             :             // iflLowerLeftOrigin - from lower left corner
     212             :             // scan right then up
     213           0 :             tilenum = (numYBlocks - 1 - nBlockYOff) * numXBlocks + nBlockXOff;
     214           0 :             break;
     215           0 :         case 5:
     216             :             // iflLeftUpperOrigin -* from upper left corner
     217             :             // scan down then right
     218           0 :             tilenum = nBlockXOff * numYBlocks + nBlockYOff;
     219           0 :             break;
     220           0 :         case 6:
     221             :             // iflRightUpperOrigin - from upper right corner
     222             :             // scan down then left
     223           0 :             tilenum = (numXBlocks - 1 - nBlockXOff) * numYBlocks + nBlockYOff;
     224           0 :             break;
     225           0 :         case 7:
     226             :             // iflRightLowerOrigin - from lower right corner
     227             :             // scan up then left
     228           0 :             tilenum = nBlockXOff * numYBlocks + (numYBlocks - 1 - nBlockYOff);
     229           0 :             break;
     230           0 :         case 8:
     231             :             // iflLeftLowerOrigin -* from lower left corner
     232             :             // scan up then right
     233           0 :             tilenum = (numXBlocks - 1 - nBlockXOff) * numYBlocks +
     234           0 :                       (numYBlocks - 1 - nBlockYOff);
     235           0 :             break;
     236           0 :         default:
     237           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     238             :                      "FIT - unrecognized image space %i",
     239           0 :                      poFIT_DS->info->space);
     240           0 :             return CE_Failure;
     241             :     }  // switch
     242             : 
     243         700 :     uint64 offset = poFIT_DS->info->dataOffset + recordSize * tilenum;
     244             :     //     CPLDebug("FIT", "%i RasterBand::IReadBlock %i %i (out of %i %i) --
     245             :     //     %i",
     246             :     //              poFIT_DS->info->space,
     247             :     //              nBlockXOff, nBlockYOff, numXBlocks, numYBlocks, tilenum);
     248             : 
     249         700 :     if (VSIFSeekL(poFIT_DS->fp, offset, SEEK_SET) == -1)
     250             :     {
     251           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     252             :                  "FIT - 64bit file seek failure, handle=%p", poFIT_DS->fp);
     253           0 :         return CE_Failure;
     254             :     }
     255             : 
     256             :     // XXX - should handle status
     257             :     // fast path is single component (ll?) - no copy needed
     258         700 :     int fastpath = FALSE;
     259             : 
     260         700 :     if ((poFIT_DS->nBands == 1) && (poFIT_DS->info->space == 1))  // upper left
     261         700 :         fastpath = TRUE;
     262             : 
     263         700 :     size_t nRead = 0;
     264         700 :     char *p = nullptr;
     265         700 :     if (!fastpath)
     266             :     {
     267           0 :         nRead = VSIFReadL(tmpImage, recordSize, 1, poFIT_DS->fp);
     268             :         // offset to correct component to swap
     269           0 :         p = (char *)tmpImage + nBand - 1;
     270             :     }
     271             :     else
     272             :     {
     273         700 :         nRead = VSIFReadL(pImage, recordSize, 1, poFIT_DS->fp);
     274         700 :         p = (char *)pImage;
     275             :     }
     276         700 :     if (nRead != 1)
     277             :     {
     278           0 :         CPLError(CE_Failure, CPLE_FileIO, "Cannot read record");
     279           0 :         return CE_Failure;
     280             :     }
     281             : 
     282             : #ifdef swapping
     283         700 :     unsigned long i = 0;
     284             : 
     285         700 :     switch (bytesPerComponent)
     286             :     {
     287         100 :         case 1:
     288             :             // do nothing
     289         100 :             break;
     290         200 :         case 2:
     291        1000 :             for (i = 0; i < recordSize; i += bytesPerPixel)
     292         800 :                 gst_swap16(p + i);
     293         200 :             break;
     294         300 :         case 4:
     295        1500 :             for (i = 0; i < recordSize; i += bytesPerPixel)
     296        1200 :                 gst_swap32(p + i);
     297         300 :             break;
     298         100 :         case 8:
     299         500 :             for (i = 0; i < recordSize; i += bytesPerPixel)
     300         400 :                 gst_swap64(p + i);
     301         100 :             break;
     302           0 :         default:
     303           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     304             :                      "FITRasterBand::IReadBlock unsupported bytesPerPixel %lu",
     305             :                      bytesPerComponent);
     306             :     }  // switch
     307             : #else
     308             :     (void)p;  // avoid warnings.
     309             : #endif  // swapping
     310             : 
     311         700 :     if (!fastpath)
     312             :     {
     313             :         long xinc, yinc, xstart, ystart, xstop, ystop;
     314           0 :         if (poFIT_DS->info->space <= 4)
     315             :         {
     316             :             // scan left/right first
     317             : 
     318           0 :             switch (poFIT_DS->info->space)
     319             :             {
     320           0 :                 case 1:
     321             :                     // iflUpperLeftOrigin - from upper left corner
     322             :                     // scan right then down
     323           0 :                     xinc = 1;
     324           0 :                     yinc = 1;
     325           0 :                     break;
     326           0 :                 case 2:
     327             :                     // iflUpperRightOrigin - from upper right corner
     328             :                     // scan left then down
     329           0 :                     xinc = -1;
     330           0 :                     yinc = 1;
     331           0 :                     break;
     332           0 :                 case 3:
     333             :                     // iflLowerRightOrigin - from lower right corner
     334             :                     // scan left then up
     335           0 :                     xinc = -1;
     336           0 :                     yinc = -1;
     337           0 :                     break;
     338           0 :                 case 4:
     339             :                     // iflLowerLeftOrigin - from lower left corner
     340             :                     // scan right then up
     341           0 :                     xinc = 1;
     342           0 :                     yinc = -1;
     343           0 :                     break;
     344           0 :                 default:
     345           0 :                     CPLError(CE_Failure, CPLE_NotSupported,
     346             :                              "FIT - unrecognized image space %i",
     347           0 :                              poFIT_DS->info->space);
     348           0 :                     xinc = 1;
     349           0 :                     yinc = 1;
     350             :             }  // switch
     351             : 
     352           0 :             if (xinc == 1)
     353             :             {
     354           0 :                 xstart = 0;
     355           0 :                 xstop = nBlockXSize;
     356             :             }
     357             :             else
     358             :             {
     359           0 :                 xstart = nBlockXSize - 1;
     360           0 :                 xstop = -1;
     361             :             }
     362           0 :             if (yinc == 1)
     363             :             {
     364           0 :                 ystart = 0;
     365           0 :                 ystop = nBlockYSize;
     366             :             }
     367             :             else
     368             :             {
     369           0 :                 int localBlockYSize = nBlockYSize;
     370           0 :                 long maxy_full =
     371           0 :                     (long)floor(poFIT_DS->info->ySize / (double)nBlockYSize);
     372           0 :                 if (nBlockYOff >= maxy_full)
     373           0 :                     localBlockYSize = poFIT_DS->info->ySize % nBlockYSize;
     374           0 :                 ystart = localBlockYSize - 1;
     375           0 :                 ystop = -1;
     376             :             }
     377             : 
     378           0 :             switch (bytesPerComponent)
     379             :             {
     380           0 :                 case 1:
     381           0 :                     COPY_XFIRST(char);
     382           0 :                     break;
     383           0 :                 case 2:
     384           0 :                     COPY_XFIRST(uint16);
     385           0 :                     break;
     386           0 :                 case 4:
     387           0 :                     COPY_XFIRST(uint32);
     388           0 :                     break;
     389           0 :                 case 8:
     390           0 :                     COPY_XFIRST(uint64);
     391           0 :                     break;
     392           0 :                 default:
     393           0 :                     CPLError(CE_Failure, CPLE_NotSupported,
     394             :                              "FITRasterBand::IReadBlock unsupported "
     395             :                              "bytesPerComponent %lu",
     396             :                              bytesPerComponent);
     397             :             }  // switch
     398             :         }      // Scan left/right first.
     399             :         else
     400             :         {
     401             :             // Scan up/down first.
     402           0 :             switch (poFIT_DS->info->space)
     403             :             {
     404           0 :                 case 5:
     405             :                     // iflLeftUpperOrigin -* from upper left corner
     406             :                     // scan down then right
     407           0 :                     xinc = 1;
     408           0 :                     yinc = 1;
     409           0 :                     break;
     410           0 :                 case 6:
     411             :                     // iflRightUpperOrigin - from upper right corner
     412             :                     // scan down then left
     413           0 :                     xinc = -1;
     414           0 :                     yinc = 1;
     415           0 :                     break;
     416           0 :                 case 7:
     417             :                     // iflRightLowerOrigin - from lower right corner
     418             :                     // scan up then left
     419           0 :                     xinc = -1;
     420           0 :                     yinc = -1;
     421           0 :                     break;
     422           0 :                 case 8:
     423             :                     // iflLeftLowerOrigin -* from lower left corner
     424             :                     // scan up then right
     425           0 :                     xinc = 1;
     426           0 :                     yinc = -1;
     427           0 :                     break;
     428           0 :                 default:
     429           0 :                     CPLError(CE_Failure, CPLE_NotSupported,
     430             :                              "FIT - unrecognized image space %i",
     431           0 :                              poFIT_DS->info->space);
     432           0 :                     xinc = 1;
     433           0 :                     yinc = 1;
     434             :             }  // switch
     435             : 
     436           0 :             if (xinc == 1)
     437             :             {
     438           0 :                 xstart = 0;
     439           0 :                 xstop = nBlockXSize;
     440             :             }
     441             :             else
     442             :             {
     443           0 :                 int localBlockXSize = nBlockXSize;
     444           0 :                 long maxx_full =
     445           0 :                     (long)floor(poFIT_DS->info->xSize / (double)nBlockXSize);
     446           0 :                 if (nBlockXOff >= maxx_full)
     447           0 :                     localBlockXSize = poFIT_DS->info->xSize % nBlockXSize;
     448           0 :                 xstart = localBlockXSize - 1;
     449           0 :                 xstop = -1;
     450             :             }
     451           0 :             if (yinc == 1)
     452             :             {
     453           0 :                 ystart = 0;
     454           0 :                 ystop = nBlockYSize;
     455             :             }
     456             :             else
     457             :             {
     458           0 :                 ystart = nBlockYSize - 1;
     459           0 :                 ystop = -1;
     460             :             }
     461             : 
     462           0 :             switch (bytesPerComponent)
     463             :             {
     464           0 :                 case 1:
     465           0 :                     COPY_YFIRST(char);
     466           0 :                     break;
     467           0 :                 case 2:
     468           0 :                     COPY_YFIRST(uint16);
     469           0 :                     break;
     470           0 :                 case 4:
     471           0 :                     COPY_YFIRST(uint32);
     472           0 :                     break;
     473           0 :                 case 8:
     474           0 :                     COPY_YFIRST(uint64);
     475           0 :                     break;
     476           0 :                 default:
     477           0 :                     CPLError(CE_Failure, CPLE_NotSupported,
     478             :                              "FITRasterBand::IReadBlock unsupported "
     479             :                              "bytesPerComponent %lu",
     480             :                              bytesPerComponent);
     481             :             }  // switch
     482             :         }      // Scan up/down first.
     483             :     }          // !fastpath
     484         700 :     return CE_None;
     485             : }
     486             : 
     487             : #if 0
     488             : /************************************************************************/
     489             : /*                             ReadBlock()                              */
     490             : /************************************************************************/
     491             : 
     492             : CPLErr FITRasterBand::ReadBlock( int nBlockXOff, int nBlockYOff,
     493             :                                  void * pImage )
     494             : 
     495             : {
     496             :     FITDataset *poFIT_DS = (FITDataset *) poDS;
     497             : 
     498             :     return CE_None;
     499             : }
     500             : 
     501             : /************************************************************************/
     502             : /*                             WriteBlock()                             */
     503             : /************************************************************************/
     504             : 
     505             : CPLErr FITRasterBand::WriteBlock( int nBlockXOff, int nBlockYOff,
     506             :                                  void * pImage )
     507             : 
     508             : {
     509             :     FITDataset *poFIT_DS = (FITDataset *) poDS;
     510             : 
     511             :     return CE_None;
     512             : }
     513             : #endif
     514             : 
     515             : /************************************************************************/
     516             : /*                             GetMinimum()                             */
     517             : /************************************************************************/
     518             : 
     519           0 : double FITRasterBand::GetMinimum(int *pbSuccess)
     520             : {
     521           0 :     FITDataset *poFIT_DS = (FITDataset *)poDS;
     522             : 
     523           0 :     if ((!poFIT_DS) || (!poFIT_DS->info))
     524           0 :         return GDALRasterBand::GetMinimum(pbSuccess);
     525             : 
     526           0 :     if (pbSuccess)
     527           0 :         *pbSuccess = TRUE;
     528             : 
     529           0 :     if (poFIT_DS->info->version &&
     530           0 :         STARTS_WITH_CI((const char *)&(poFIT_DS->info->version), "02"))
     531             :     {
     532           0 :         return poFIT_DS->info->minValue;
     533             :     }
     534             : 
     535           0 :     return GDALRasterBand::GetMinimum(pbSuccess);
     536             : }
     537             : 
     538             : /************************************************************************/
     539             : /*                             GetMaximum()                             */
     540             : /************************************************************************/
     541             : 
     542           0 : double FITRasterBand::GetMaximum(int *pbSuccess)
     543             : {
     544           0 :     FITDataset *poFIT_DS = (FITDataset *)poDS;
     545             : 
     546           0 :     if ((!poFIT_DS) || (!poFIT_DS->info))
     547           0 :         return GDALRasterBand::GetMaximum(pbSuccess);
     548             : 
     549           0 :     if (pbSuccess)
     550           0 :         *pbSuccess = TRUE;
     551             : 
     552           0 :     if (STARTS_WITH_CI((const char *)&poFIT_DS->info->version, "02"))
     553             :     {
     554           0 :         return poFIT_DS->info->maxValue;
     555             :     }
     556             : 
     557           0 :     return GDALRasterBand::GetMaximum(pbSuccess);
     558             : }
     559             : 
     560             : /************************************************************************/
     561             : /*                       GetColorInterpretation()                       */
     562             : /************************************************************************/
     563             : 
     564           7 : GDALColorInterp FITRasterBand::GetColorInterpretation()
     565             : {
     566           7 :     FITDataset *poFIT_DS = (FITDataset *)poDS;
     567             : 
     568           7 :     if ((!poFIT_DS) || (!poFIT_DS->info))
     569           0 :         return GCI_Undefined;
     570             : 
     571           7 :     switch (poFIT_DS->info->cm)
     572             :     {
     573           0 :         case 1:  // iflNegative - inverted luminance (min value is white)
     574           0 :             CPLError(
     575             :                 CE_Warning, CPLE_NotSupported,
     576             :                 "FIT - color model Negative not supported - ignoring model");
     577           0 :             return GCI_Undefined;
     578             : 
     579           7 :         case 2:  // iflLuminance - luminance
     580           7 :             if (poFIT_DS->nBands != 1)
     581             :             {
     582           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
     583             :                          "FIT - color model Luminance mismatch with %i bands",
     584             :                          poFIT_DS->nBands);
     585           0 :                 return GCI_Undefined;
     586             :             }
     587           7 :             switch (nBand)
     588             :             {
     589           7 :                 case 1:
     590           7 :                     return GCI_GrayIndex;
     591           0 :                 default:
     592           0 :                     CPLError(CE_Failure, CPLE_NotSupported,
     593             :                              "FIT - color model Luminance unknown band %i",
     594             :                              nBand);
     595           0 :                     return GCI_Undefined;
     596             :             }  // switch nBand
     597             : 
     598           0 :         case 3:  // iflRGB - full color (Red, Green, Blue triplets)
     599           0 :             if (poFIT_DS->nBands != 3)
     600             :             {
     601           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
     602             :                          "FIT - color model RGB mismatch with %i bands",
     603             :                          poFIT_DS->nBands);
     604           0 :                 return GCI_Undefined;
     605             :             }
     606           0 :             switch (nBand)
     607             :             {
     608           0 :                 case 1:
     609           0 :                     return GCI_RedBand;
     610           0 :                 case 2:
     611           0 :                     return GCI_GreenBand;
     612           0 :                 case 3:
     613           0 :                     return GCI_BlueBand;
     614           0 :                 default:
     615           0 :                     CPLError(CE_Failure, CPLE_NotSupported,
     616             :                              "FIT - color model RGB unknown band %i", nBand);
     617           0 :                     return GCI_Undefined;
     618             :             }  // switch nBand
     619             : 
     620           0 :         case 4:  // iflRGBPalette - color mapped values
     621           0 :             CPLError(CE_Warning, CPLE_NotSupported,
     622             :                      "FIT - color model  RGBPalette not supported - "
     623             :                      "ignoring model");
     624           0 :             return GCI_Undefined;
     625             : 
     626           0 :         case 5:  // iflRGBA - full color with transparency (alpha channel)
     627           0 :             if (poFIT_DS->nBands != 4)
     628             :             {
     629           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
     630             :                          "FIT - color model RGBA mismatch with %i bands",
     631             :                          poFIT_DS->nBands);
     632           0 :                 return GCI_Undefined;
     633             :             }
     634           0 :             switch (nBand)
     635             :             {
     636           0 :                 case 1:
     637           0 :                     return GCI_RedBand;
     638           0 :                 case 2:
     639           0 :                     return GCI_GreenBand;
     640           0 :                 case 3:
     641           0 :                     return GCI_BlueBand;
     642           0 :                 case 4:
     643           0 :                     return GCI_AlphaBand;
     644           0 :                 default:
     645           0 :                     CPLError(CE_Failure, CPLE_NotSupported,
     646             :                              "FIT - color model RGBA unknown band %i", nBand);
     647           0 :                     return GCI_Undefined;
     648             :             }  // switch nBand
     649             : 
     650           0 :         case 6:  // iflHSV - Hue, Saturation, Value
     651           0 :             if (poFIT_DS->nBands != 3)
     652             :             {
     653           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
     654             :                          "FIT - color model HSV mismatch with %i bands",
     655             :                          poFIT_DS->nBands);
     656           0 :                 return GCI_Undefined;
     657             :             }
     658           0 :             switch (nBand)
     659             :             {
     660           0 :                 case 1:
     661           0 :                     return GCI_HueBand;
     662           0 :                 case 2:
     663           0 :                     return GCI_SaturationBand;
     664           0 :                 case 3:
     665           0 :                     return GCI_LightnessBand;
     666           0 :                 default:
     667           0 :                     CPLError(CE_Failure, CPLE_NotSupported,
     668             :                              "FIT - color model HSV unknown band %i", nBand);
     669           0 :                     return GCI_Undefined;
     670             :             }  // switch nBand
     671             : 
     672           0 :         case 7:  // iflCMY - Cyan, Magenta, Yellow
     673           0 :             if (poFIT_DS->nBands != 3)
     674             :             {
     675           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
     676             :                          "FIT - color model CMY mismatch with %i bands",
     677             :                          poFIT_DS->nBands);
     678           0 :                 return GCI_Undefined;
     679             :             }
     680           0 :             switch (nBand)
     681             :             {
     682           0 :                 case 1:
     683           0 :                     return GCI_CyanBand;
     684           0 :                 case 2:
     685           0 :                     return GCI_MagentaBand;
     686           0 :                 case 3:
     687           0 :                     return GCI_YellowBand;
     688           0 :                 default:
     689           0 :                     CPLError(CE_Failure, CPLE_NotSupported,
     690             :                              "FIT - color model CMY unknown band %i", nBand);
     691           0 :                     return GCI_Undefined;
     692             :             }  // switch nBand
     693             : 
     694           0 :         case 8:  // iflCMYK - Cyan, Magenta, Yellow, Black
     695           0 :             if (poFIT_DS->nBands != 4)
     696             :             {
     697           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
     698             :                          "FIT - color model CMYK mismatch with %i bands",
     699             :                          poFIT_DS->nBands);
     700           0 :                 return GCI_Undefined;
     701             :             }
     702           0 :             switch (nBand)
     703             :             {
     704           0 :                 case 1:
     705           0 :                     return GCI_CyanBand;
     706           0 :                 case 2:
     707           0 :                     return GCI_MagentaBand;
     708           0 :                 case 3:
     709           0 :                     return GCI_YellowBand;
     710           0 :                 case 4:
     711           0 :                     return GCI_BlackBand;
     712           0 :                 default:
     713           0 :                     CPLError(CE_Failure, CPLE_NotSupported,
     714             :                              "FIT - color model CMYK unknown band %i", nBand);
     715           0 :                     return GCI_Undefined;
     716             :             }  // switch nBand
     717             : 
     718           0 :         case 9:  // iflBGR - full color (ordered Blue, Green, Red)
     719           0 :             if (poFIT_DS->nBands != 3)
     720             :             {
     721           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
     722             :                          "FIT - color model BGR mismatch with %i bands",
     723             :                          poFIT_DS->nBands);
     724           0 :                 return GCI_Undefined;
     725             :             }
     726           0 :             switch (nBand)
     727             :             {
     728           0 :                 case 1:
     729           0 :                     return GCI_BlueBand;
     730           0 :                 case 2:
     731           0 :                     return GCI_GreenBand;
     732           0 :                 case 3:
     733           0 :                     return GCI_RedBand;
     734           0 :                 default:
     735           0 :                     CPLError(CE_Failure, CPLE_NotSupported,
     736             :                              "FIT - color model BGR unknown band %i", nBand);
     737           0 :                     return GCI_Undefined;
     738             :             }  // switch nBand
     739             : 
     740           0 :         case 10:  // iflABGR - Alpha, Blue, Green, Red (SGI frame buffers)
     741           0 :             if (poFIT_DS->nBands != 4)
     742             :             {
     743           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
     744             :                          "FIT - color model ABGR mismatch with %i bands",
     745             :                          poFIT_DS->nBands);
     746           0 :                 return GCI_Undefined;
     747             :             }
     748           0 :             switch (nBand)
     749             :             {
     750           0 :                 case 1:
     751           0 :                     return GCI_AlphaBand;
     752           0 :                 case 2:
     753           0 :                     return GCI_BlueBand;
     754           0 :                 case 3:
     755           0 :                     return GCI_GreenBand;
     756           0 :                 case 4:
     757           0 :                     return GCI_RedBand;
     758           0 :                 default:
     759           0 :                     CPLError(CE_Failure, CPLE_NotSupported,
     760             :                              "FIT - color model ABGR unknown band %i", nBand);
     761           0 :                     return GCI_Undefined;
     762             :             }  // switch nBand
     763             : 
     764           0 :         case 11:  // iflMultiSpectral - multi-spectral data, arbitrary number of
     765             :             // chans
     766           0 :             return GCI_Undefined;
     767             : 
     768           0 :         case 12:  // iflYCC PhotoCD color model (Luminance, Chrominance)
     769           0 :             CPLError(CE_Warning, CPLE_NotSupported,
     770             :                      "FIT - color model YCC not supported - ignoring model");
     771           0 :             return GCI_Undefined;
     772             : 
     773           0 :         case 13:  // iflLuminanceAlpha - Luminance plus alpha
     774           0 :             if (poFIT_DS->nBands != 2)
     775             :             {
     776           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
     777             :                          "FIT - color model LuminanceAlpha mismatch with "
     778             :                          "%i bands",
     779             :                          poFIT_DS->nBands);
     780           0 :                 return GCI_Undefined;
     781             :             }
     782           0 :             switch (nBand)
     783             :             {
     784           0 :                 case 1:
     785           0 :                     return GCI_GrayIndex;
     786           0 :                 case 2:
     787           0 :                     return GCI_AlphaBand;
     788           0 :                 default:
     789           0 :                     CPLError(CE_Failure, CPLE_NotSupported,
     790             :                              "FIT - color model LuminanceAlpha unknown band %i",
     791             :                              nBand);
     792           0 :                     return GCI_Undefined;
     793             :             }  // switch nBand
     794             : 
     795           0 :         default:
     796           0 :             CPLError(CE_Warning, CPLE_NotSupported,
     797             :                      "FIT - unrecognized color model %i - ignoring model",
     798           0 :                      poFIT_DS->info->cm);
     799           0 :             return GCI_Undefined;
     800             :     }  // switch
     801             : }
     802             : 
     803             : /************************************************************************/
     804             : /*                             FITDataset()                             */
     805             : /************************************************************************/
     806             : 
     807          25 : FITDataset::FITDataset() : fp(nullptr), info(nullptr)
     808             : {
     809          25 :     adfGeoTransform[0] = 0.0;  // x origin (top left corner)
     810          25 :     adfGeoTransform[1] = 1.0;  // x pixel size
     811          25 :     adfGeoTransform[2] = 0.0;
     812          25 :     adfGeoTransform[3] = 0.0;  // y origin (top left corner)
     813          25 :     adfGeoTransform[4] = 0.0;
     814          25 :     adfGeoTransform[5] = 1.0;  // y pixel size
     815          25 : }
     816             : 
     817             : /************************************************************************/
     818             : /*                             ~FITDataset()                             */
     819             : /************************************************************************/
     820             : 
     821          50 : FITDataset::~FITDataset()
     822             : {
     823          25 :     FlushCache(true);
     824          25 :     if (info)
     825          25 :         delete (info);
     826          25 :     if (fp)
     827             :     {
     828          25 :         if (VSIFCloseL(fp) != 0)
     829             :         {
     830           0 :             CPLError(CE_Failure, CPLE_FileIO, "I/O error");
     831             :         }
     832             :     }
     833          50 : }
     834             : 
     835             : /************************************************************************/
     836             : /*                                Open()                                */
     837             : /************************************************************************/
     838             : 
     839       31165 : GDALDataset *FITDataset::Open(GDALOpenInfo *poOpenInfo)
     840             : {
     841             :     /* -------------------------------------------------------------------- */
     842             :     /*      First we check to see if the file has the expected header       */
     843             :     /*      bytes.                                                          */
     844             :     /* -------------------------------------------------------------------- */
     845             : 
     846       31165 :     if (poOpenInfo->nHeaderBytes < 5 || poOpenInfo->fpL == nullptr)
     847       26856 :         return nullptr;
     848             : 
     849        4309 :     if (!STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader, "IT01") &&
     850        4309 :         !STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader, "IT02"))
     851        4284 :         return nullptr;
     852             : 
     853          25 :     if (poOpenInfo->eAccess == GA_Update)
     854             :     {
     855           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     856             :                  "The FIT driver does not support update access to existing"
     857             :                  " files.\n");
     858           0 :         return nullptr;
     859             :     }
     860             : 
     861             :     /* -------------------------------------------------------------------- */
     862             :     /*      Create a corresponding GDALDataset.                             */
     863             :     /* -------------------------------------------------------------------- */
     864          50 :     auto poDS = std::make_unique<FITDataset>();
     865          25 :     poDS->eAccess = poOpenInfo->eAccess;
     866          25 :     poDS->fp = poOpenInfo->fpL;
     867          25 :     poOpenInfo->fpL = nullptr;
     868             : 
     869          25 :     poDS->info = new FITinfo;
     870          25 :     FITinfo *info = poDS->info;
     871             : 
     872             :     /* -------------------------------------------------------------------- */
     873             :     /*      Read other header values.                                       */
     874             :     /* -------------------------------------------------------------------- */
     875          25 :     FIThead02 *head = (FIThead02 *)poOpenInfo->pabyHeader;
     876             : 
     877             :     // extract the image attributes from the file header
     878          25 :     if (STARTS_WITH_CI((const char *)&head->version, "02"))
     879             :     {
     880             :         // incomplete header
     881          25 :         if (poOpenInfo->nHeaderBytes < (signed)sizeof(FIThead02))
     882           0 :             return nullptr;
     883             : 
     884          25 :         CPLDebug("FIT", "Loading file with header version 02");
     885             : 
     886          25 :         gst_swapb(head->minValue);
     887          25 :         info->minValue = head->minValue;
     888          25 :         gst_swapb(head->maxValue);
     889          25 :         info->maxValue = head->maxValue;
     890          25 :         gst_swapb(head->dataOffset);
     891          25 :         info->dataOffset = head->dataOffset;
     892             : 
     893          25 :         info->userOffset = sizeof(FIThead02);
     894             :     }
     895           0 :     else if (STARTS_WITH_CI((const char *)&head->version, "01"))
     896             :     {
     897             :         // incomplete header
     898           0 :         if (poOpenInfo->nHeaderBytes < (signed)sizeof(FIThead01))
     899           0 :             return nullptr;
     900             : 
     901           0 :         CPLDebug("FIT", "Loading file with header version 01");
     902             : 
     903             :         // map old style header into new header structure
     904           0 :         FIThead01 *head01 = (FIThead01 *)head;
     905           0 :         gst_swapb(head->dataOffset);
     906           0 :         info->dataOffset = head01->dataOffset;
     907             : 
     908           0 :         info->userOffset = sizeof(FIThead01);
     909             :     }
     910             :     else
     911             :     {
     912             :         // unrecognized header version
     913           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     914             :                  "FIT - unsupported header version %.2s\n",
     915           0 :                  (const char *)&head->version);
     916           0 :         return nullptr;
     917             :     }
     918             : 
     919          25 :     CPLDebug("FIT", "userOffset %i, dataOffset %i", info->userOffset,
     920             :              info->dataOffset);
     921             : 
     922          25 :     info->magic = head->magic;
     923          25 :     info->version = head->version;
     924             : 
     925          25 :     gst_swapb(head->xSize);
     926          25 :     info->xSize = head->xSize;
     927          25 :     gst_swapb(head->ySize);
     928          25 :     info->ySize = head->ySize;
     929          25 :     gst_swapb(head->zSize);
     930          25 :     info->zSize = head->zSize;
     931          25 :     gst_swapb(head->cSize);
     932          25 :     info->cSize = head->cSize;
     933          25 :     gst_swapb(head->dtype);
     934          25 :     info->dtype = head->dtype;
     935          25 :     gst_swapb(head->order);
     936          25 :     info->order = head->order;
     937          25 :     gst_swapb(head->space);
     938          25 :     info->space = head->space;
     939          25 :     gst_swapb(head->cm);
     940          25 :     info->cm = head->cm;
     941          25 :     gst_swapb(head->xPageSize);
     942          25 :     info->xPageSize = head->xPageSize;
     943          25 :     gst_swapb(head->yPageSize);
     944          25 :     info->yPageSize = head->yPageSize;
     945          25 :     gst_swapb(head->zPageSize);
     946          25 :     info->zPageSize = head->zPageSize;
     947          25 :     gst_swapb(head->cPageSize);
     948          25 :     info->cPageSize = head->cPageSize;
     949             : 
     950          25 :     CPLDebug("FIT", "size %i %i %i %i, pageSize %i %i %i %i", info->xSize,
     951             :              info->ySize, info->zSize, info->cSize, info->xPageSize,
     952             :              info->yPageSize, info->zPageSize, info->cPageSize);
     953             : 
     954          25 :     CPLDebug("FIT", "dtype %i order %i space %i cm %i", info->dtype,
     955             :              info->order, info->space, info->cm);
     956             : 
     957             :     /**************************/
     958             : 
     959          25 :     poDS->nRasterXSize = head->xSize;
     960          25 :     poDS->nRasterYSize = head->ySize;
     961             : 
     962          25 :     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
     963          50 :         !GDALCheckBandCount(head->cSize, FALSE) || head->xPageSize == 0 ||
     964          25 :         head->yPageSize == 0)
     965             :     {
     966           0 :         return nullptr;
     967             :     }
     968             : 
     969             :     /* -------------------------------------------------------------------- */
     970             :     /*      Verify all "unused" header values.                              */
     971             :     /* -------------------------------------------------------------------- */
     972             : 
     973          25 :     if (info->zSize != 1)
     974             :     {
     975           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     976             :                  "FIT driver - unsupported zSize %i\n", info->zSize);
     977           0 :         return nullptr;
     978             :     }
     979             : 
     980          25 :     if (info->order != 1)  // interleaved - RGBRGB
     981             :     {
     982           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     983             :                  "FIT driver - unsupported order %i\n", info->order);
     984           0 :         return nullptr;
     985             :     }
     986             : 
     987          25 :     if (info->zPageSize != 1)
     988             :     {
     989           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     990             :                  "FIT driver - unsupported zPageSize %i\n", info->zPageSize);
     991           0 :         return nullptr;
     992             :     }
     993             : 
     994          25 :     if (info->cPageSize != info->cSize)
     995             :     {
     996           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     997             :                  "FIT driver - unsupported cPageSize %i (!= %i)\n",
     998             :                  info->cPageSize, info->cSize);
     999           0 :         return nullptr;
    1000             :     }
    1001             : 
    1002             :     /* -------------------------------------------------------------------- */
    1003             :     /*      Create band information objects.                                */
    1004             :     /* -------------------------------------------------------------------- */
    1005             :     // Verified by above GDALCheckBandCount()
    1006             :     // coverity[tainted_data]
    1007          60 :     for (int i = 0; i < (int)head->cSize; i++)
    1008             :     {
    1009             :         FITRasterBand *poBand =
    1010          35 :             new FITRasterBand(poDS.get(), i + 1, (int)head->cSize);
    1011          35 :         poDS->SetBand(i + 1, poBand);
    1012          35 :         if (poBand->tmpImage == nullptr)
    1013           0 :             return nullptr;
    1014             :     }
    1015             : 
    1016             :     /* -------------------------------------------------------------------- */
    1017             :     /*      Initialize any PAM information.                                 */
    1018             :     /* -------------------------------------------------------------------- */
    1019          25 :     poDS->SetDescription(poOpenInfo->pszFilename);
    1020          25 :     poDS->TryLoadXML();
    1021             : 
    1022             :     /* -------------------------------------------------------------------- */
    1023             :     /*      Check for external overviews.                                   */
    1024             :     /* -------------------------------------------------------------------- */
    1025          25 :     poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename,
    1026             :                                 poOpenInfo->GetSiblingFiles());
    1027             : 
    1028          25 :     return poDS.release();
    1029             : }
    1030             : 
    1031             : /************************************************************************/
    1032             : /*                           FITCreateCopy()                            */
    1033             : /************************************************************************/
    1034             : 
    1035          35 : static GDALDataset *FITCreateCopy(const char *pszFilename, GDALDataset *poSrcDS,
    1036             :                                   int bStrict, char **papszOptions,
    1037             :                                   GDALProgressFunc pfnProgress,
    1038             :                                   void *pProgressData)
    1039             : {
    1040          35 :     CPLDebug("FIT", "CreateCopy %s - %i", pszFilename, bStrict);
    1041             : 
    1042          35 :     int nBands = poSrcDS->GetRasterCount();
    1043          35 :     if (nBands == 0)
    1044             :     {
    1045           1 :         CPLError(
    1046             :             CE_Failure, CPLE_NotSupported,
    1047             :             "FIT driver does not support source dataset with zero band.\n");
    1048           1 :         return nullptr;
    1049             :     }
    1050             : 
    1051             :     /* -------------------------------------------------------------------- */
    1052             :     /*      Create the dataset.                                             */
    1053             :     /* -------------------------------------------------------------------- */
    1054          34 :     if (!pfnProgress(0.0, nullptr, pProgressData))
    1055             :     {
    1056           0 :         CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    1057           0 :         return nullptr;
    1058             :     }
    1059             : 
    1060          34 :     VSILFILE *fpImage = VSIFOpenL(pszFilename, "wb");
    1061          34 :     if (fpImage == nullptr)
    1062             :     {
    1063           2 :         CPLError(CE_Failure, CPLE_OpenFailed,
    1064             :                  "FIT - unable to create file %s.\n", pszFilename);
    1065           2 :         return nullptr;
    1066             :     }
    1067             : 
    1068             :     /* -------------------------------------------------------------------- */
    1069             :     /*      Generate header.                                                */
    1070             :     /* -------------------------------------------------------------------- */
    1071             :     // XXX - should FIT_PAGE_SIZE be based on file page size ??
    1072             : 
    1073          32 :     const size_t size = std::max(sizeof(FIThead02), FIT_PAGE_SIZE);
    1074          64 :     std::vector<GByte> abyHeader;
    1075          32 :     abyHeader.resize(size);
    1076          32 :     FIThead02 *head = reinterpret_cast<FIThead02 *>(abyHeader.data());
    1077             : 
    1078             :     // clean header so padding (past real header) is all zeros
    1079          32 :     memset(head, 0, size);
    1080             : 
    1081          32 :     memcpy((char *)&head->magic, "IT", 2);
    1082          32 :     memcpy((char *)&head->version, "02", 2);
    1083             : 
    1084          32 :     head->xSize = poSrcDS->GetRasterXSize();
    1085          32 :     gst_swapb(head->xSize);
    1086          32 :     head->ySize = poSrcDS->GetRasterYSize();
    1087          32 :     gst_swapb(head->ySize);
    1088          32 :     head->zSize = 1;
    1089          32 :     gst_swapb(head->zSize);
    1090             : 
    1091          32 :     head->cSize = nBands;
    1092          32 :     gst_swapb(head->cSize);
    1093             : 
    1094          32 :     GDALRasterBand *firstBand = poSrcDS->GetRasterBand(1);
    1095          32 :     if (!firstBand)
    1096             :     {
    1097           0 :         CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage));
    1098           0 :         return nullptr;
    1099             :     }
    1100             : 
    1101          32 :     head->dtype = fitGetDataType(firstBand->GetRasterDataType());
    1102          32 :     if (!head->dtype)
    1103             :     {
    1104           4 :         CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage));
    1105           4 :         return nullptr;
    1106             :     }
    1107          28 :     gst_swapb(head->dtype);
    1108          28 :     head->order = 1;  // interleaved - RGBRGB
    1109          28 :     gst_swapb(head->order);
    1110          28 :     head->space = 1;  // upper left
    1111          28 :     gst_swapb(head->space);
    1112             : 
    1113             :     // XXX - need to check all bands
    1114          28 :     head->cm = fitGetColorModel(firstBand->GetColorInterpretation(), nBands);
    1115          28 :     gst_swapb(head->cm);
    1116             : 
    1117             :     int blockX, blockY;
    1118          28 :     firstBand->GetBlockSize(&blockX, &blockY);
    1119          28 :     blockX = std::min(blockX, poSrcDS->GetRasterXSize());
    1120          28 :     blockY = std::min(blockY, poSrcDS->GetRasterYSize());
    1121          28 :     int nDTSize = GDALGetDataTypeSizeBytes(firstBand->GetRasterDataType());
    1122             :     try
    1123             :     {
    1124          56 :         CPL_IGNORE_RET_VAL(CPLSM(blockX) * CPLSM(blockY) * CPLSM(nDTSize) *
    1125          56 :                            CPLSM(nBands));
    1126          28 :         CPLDebug("FIT write", "inherited block size %ix%i", blockX, blockY);
    1127             :     }
    1128           0 :     catch (...)
    1129             :     {
    1130           0 :         blockX = std::min(256, poSrcDS->GetRasterXSize());
    1131           0 :         blockY = std::min(256, poSrcDS->GetRasterYSize());
    1132             :     }
    1133             : 
    1134          28 :     if (CSLFetchNameValue(papszOptions, "PAGESIZE") != nullptr)
    1135             :     {
    1136           7 :         const char *str = CSLFetchNameValue(papszOptions, "PAGESIZE");
    1137             :         int newBlockX, newBlockY;
    1138           7 :         sscanf(str, "%i,%i", &newBlockX, &newBlockY);
    1139           7 :         if (newBlockX > 0 && newBlockY > 0)
    1140             :         {
    1141           7 :             blockX = newBlockX;
    1142           7 :             blockY = newBlockY;
    1143           7 :             try
    1144             :             {
    1145          14 :                 CPL_IGNORE_RET_VAL(CPLSM(blockX) * CPLSM(blockY) *
    1146          21 :                                    CPLSM(nDTSize) * CPLSM(nBands));
    1147             :             }
    1148           0 :             catch (...)
    1149             :             {
    1150           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1151             :                          "Too big values in PAGESIZE");
    1152           0 :                 CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage));
    1153           0 :                 return nullptr;
    1154             :             }
    1155             :         }
    1156             :         else
    1157             :         {
    1158           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
    1159             :                      "FIT - Unable to parse option PAGESIZE values [%s]", str);
    1160             :         }
    1161             :     }
    1162             : 
    1163             :     // XXX - need to do lots of checking of block size
    1164             :     // * provide ability to override block size with options
    1165             :     // * handle non-square block size (like scanline)
    1166             :     //   - probably default from non-tiled image - have default block size
    1167             :     // * handle block size bigger than image size
    1168             :     // * undesirable block size (non power of 2, others?)
    1169             :     // * mismatched block sizes for different bands
    1170             :     // * image that isn't even pages (i.e. partially empty pages at edge)
    1171          28 :     CPLDebug("FIT write", "using block size %ix%i", blockX, blockY);
    1172             : 
    1173          28 :     head->xPageSize = blockX;
    1174          28 :     gst_swapb(head->xPageSize);
    1175          28 :     head->yPageSize = blockY;
    1176          28 :     gst_swapb(head->yPageSize);
    1177          28 :     head->zPageSize = 1;
    1178          28 :     gst_swapb(head->zPageSize);
    1179          28 :     head->cPageSize = nBands;
    1180          28 :     gst_swapb(head->cPageSize);
    1181             : 
    1182             :     // XXX - need to check all bands
    1183          28 :     head->minValue = firstBand->GetMinimum();
    1184          28 :     gst_swapb(head->minValue);
    1185             :     // XXX - need to check all bands
    1186          28 :     head->maxValue = firstBand->GetMaximum();
    1187          28 :     gst_swapb(head->maxValue);
    1188          28 :     head->dataOffset = static_cast<unsigned int>(size);
    1189          28 :     gst_swapb(head->dataOffset);
    1190             : 
    1191          28 :     CPL_IGNORE_RET_VAL(VSIFWriteL(head, size, 1, fpImage));
    1192             : 
    1193             :     /* -------------------------------------------------------------------- */
    1194             :     /*      Loop over image, copying image data.                            */
    1195             :     /* -------------------------------------------------------------------- */
    1196          28 :     const size_t bytesPerPixel = static_cast<size_t>(nBands) * nDTSize;
    1197             : 
    1198          28 :     const size_t pageBytes =
    1199          28 :         static_cast<size_t>(blockX) * blockY * bytesPerPixel;
    1200          56 :     std::vector<GByte> output;
    1201             :     try
    1202             :     {
    1203          28 :         output.resize(pageBytes);
    1204             :     }
    1205           0 :     catch (const std::bad_alloc &)
    1206             :     {
    1207           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    1208             :                  "FITRasterBand couldn't allocate %lu bytes",
    1209             :                  static_cast<unsigned long>(pageBytes));
    1210           0 :         CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage));
    1211           0 :         return nullptr;
    1212             :     }
    1213             : 
    1214          28 :     long maxx = (long)ceil(poSrcDS->GetRasterXSize() / (double)blockX);
    1215          28 :     long maxy = (long)ceil(poSrcDS->GetRasterYSize() / (double)blockY);
    1216          28 :     long maxx_full = (long)floor(poSrcDS->GetRasterXSize() / (double)blockX);
    1217          28 :     long maxy_full = (long)floor(poSrcDS->GetRasterYSize() / (double)blockY);
    1218             : 
    1219          28 :     CPLDebug("FIT", "about to write %ld x %ld blocks", maxx, maxy);
    1220             : 
    1221         254 :     for (long y = 0; y < maxy; y++)
    1222        1091 :         for (long x = 0; x < maxx; x++)
    1223             :         {
    1224         865 :             long readX = blockX;
    1225         865 :             long readY = blockY;
    1226         865 :             int do_clean = FALSE;
    1227             : 
    1228             :             // handle cases where image size isn't an exact multiple
    1229             :             // of page size
    1230         865 :             if (x >= maxx_full)
    1231             :             {
    1232           0 :                 readX = poSrcDS->GetRasterXSize() % blockX;
    1233           0 :                 do_clean = TRUE;
    1234             :             }
    1235         865 :             if (y >= maxy_full)
    1236             :             {
    1237           0 :                 readY = poSrcDS->GetRasterYSize() % blockY;
    1238           0 :                 do_clean = TRUE;
    1239             :             }
    1240             : 
    1241             :             // clean out image if only doing partial reads
    1242         865 :             if (do_clean)
    1243           0 :                 memset(output.data(), 0, pageBytes);
    1244             : 
    1245        1830 :             for (int iBand = 0; iBand < nBands; iBand++)
    1246             :             {
    1247         965 :                 GDALRasterBand *poBand = poSrcDS->GetRasterBand(iBand + 1);
    1248        3860 :                 CPLErr eErr = poBand->RasterIO(
    1249             :                     GF_Read,                       // eRWFlag
    1250             :                     static_cast<int>(x * blockX),  // nXOff
    1251             :                     static_cast<int>(y * blockY),  // nYOff
    1252             :                     static_cast<int>(readX),       // nXSize
    1253             :                     static_cast<int>(readY),       // nYSize
    1254         965 :                     output.data() + iBand * nDTSize,
    1255             :                     // pData
    1256             :                     blockX,  // nBufXSize
    1257             :                     blockY,  // nBufYSize
    1258             :                     firstBand->GetRasterDataType(),
    1259             :                     // eBufType
    1260             :                     bytesPerPixel,                     // nPixelSpace
    1261         965 :                     bytesPerPixel * blockX, nullptr);  // nLineSpace
    1262         965 :                 if (eErr != CE_None)
    1263             :                 {
    1264           0 :                     CPLError(CE_Failure, CPLE_FileIO,
    1265             :                              "FIT write - CreateCopy got read error %i", eErr);
    1266           0 :                     CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage));
    1267           0 :                     VSIUnlink(pszFilename);
    1268           0 :                     return nullptr;
    1269             :                 }
    1270             :             }  // for iBand
    1271             : 
    1272             : #ifdef swapping
    1273         865 :             GByte *p = output.data();
    1274             :             unsigned long i;
    1275         865 :             switch (nDTSize)
    1276             :             {
    1277         205 :                 case 1:
    1278             :                     // do nothing
    1279         205 :                     break;
    1280         220 :                 case 2:
    1281        1220 :                     for (i = 0; i < pageBytes; i += nDTSize)
    1282             :                     {
    1283        1000 :                         CPL_SWAP16PTR(p + i);
    1284             :                     }
    1285         220 :                     break;
    1286         330 :                 case 4:
    1287        1830 :                     for (i = 0; i < pageBytes; i += nDTSize)
    1288             :                     {
    1289        1500 :                         CPL_SWAP32PTR(p + i);
    1290             :                     }
    1291         330 :                     break;
    1292         110 :                 case 8:
    1293         610 :                     for (i = 0; i < pageBytes; i += nDTSize)
    1294             :                     {
    1295         500 :                         CPL_SWAP64PTR(p + i);
    1296             :                     }
    1297         110 :                     break;
    1298           0 :                 default:
    1299           0 :                     CPLError(CE_Failure, CPLE_NotSupported,
    1300             :                              "FIT write - unsupported bytesPerPixel %d",
    1301             :                              nDTSize);
    1302             :             }  // switch
    1303             : #endif         // swapping
    1304             : 
    1305         865 :             if (VSIFWriteL(output.data(), 1, pageBytes, fpImage) != pageBytes)
    1306             :             {
    1307           9 :                 CPLError(CE_Failure, CPLE_FileIO, "Write failed");
    1308           9 :                 CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage));
    1309           9 :                 VSIUnlink(pszFilename);
    1310           9 :                 return nullptr;
    1311             :             }
    1312             : 
    1313         856 :             double perc = ((double)(y * maxx + x)) / (maxx * maxy);
    1314         856 :             if (!pfnProgress(perc, nullptr, pProgressData))
    1315             :             {
    1316           0 :                 CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    1317           0 :                 CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage));
    1318           0 :                 VSIUnlink(pszFilename);
    1319           0 :                 return nullptr;
    1320             :             }
    1321             :         }  // for x
    1322             : 
    1323          19 :     CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage));
    1324             : 
    1325          19 :     pfnProgress(1.0, nullptr, pProgressData);
    1326             : 
    1327             :     /* -------------------------------------------------------------------- */
    1328             :     /*      Re-open dataset, and copy any auxiliary pam information.         */
    1329             :     /* -------------------------------------------------------------------- */
    1330          19 :     GDALPamDataset *poDS = (GDALPamDataset *)GDALOpen(pszFilename, GA_ReadOnly);
    1331             : 
    1332          19 :     if (poDS)
    1333          18 :         poDS->CloneInfo(poSrcDS, GCIF_PAM_DEFAULT);
    1334             : 
    1335          19 :     return poDS;
    1336             : }
    1337             : 
    1338             : /************************************************************************/
    1339             : /*                           GetGeoTransform()                          */
    1340             : /************************************************************************/
    1341             : 
    1342             : // CPLErr FITDataset::GetGeoTransform( double * padfTransform )
    1343             : // {
    1344             : //     CPLDebug("FIT", "FITDataset::GetGeoTransform");
    1345             : //     memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
    1346             : //     return CE_None;
    1347             : // }
    1348             : 
    1349             : /************************************************************************/
    1350             : /*                          GDALRegister_FIT()                          */
    1351             : /************************************************************************/
    1352             : 
    1353        1509 : void GDALRegister_FIT()
    1354             : 
    1355             : {
    1356        1509 :     if (GDALGetDriverByName("FIT") != nullptr)
    1357         295 :         return;
    1358             : 
    1359        1214 :     GDALDriver *poDriver = new GDALDriver();
    1360             : 
    1361        1214 :     poDriver->SetDescription("FIT");
    1362        1214 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
    1363        1214 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "FIT Image");
    1364        1214 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/fit.html");
    1365        1214 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "");
    1366        1214 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
    1367             : 
    1368        1214 :     poDriver->pfnOpen = FITDataset::Open;
    1369        1214 :     poDriver->pfnCreateCopy = FITCreateCopy;
    1370        1214 :     poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
    1371             :                               "Byte UInt16 Int16 UInt32 Int32 "
    1372        1214 :                               "Float32 Float64");
    1373             : 
    1374        1214 :     GetGDALDriverManager()->RegisterDriver(poDriver);
    1375             : }

Generated by: LCOV version 1.14