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

Generated by: LCOV version 1.14