LCOV - code coverage report
Current view: top level - frmts/sgi - sgidataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 275 357 77.0 %
Date: 2024-05-06 11:10:03 Functions: 14 15 93.3 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  SGI Image Driver
       4             :  * Purpose:  Implement SGI Image Support based on Paul Bourke's SGI Image code.
       5             :  *           http://astronomy.swin.edu.au/~pbourke/dataformats/sgirgb/
       6             :  *           ftp://ftp.sgi.com/graphics/SGIIMAGESPEC
       7             :  * Authors:  Mike Mazzella (GDAL driver)
       8             :  *           Paul Bourke (original SGI format code)
       9             :  *           Frank Warmerdam (write support)
      10             :  *
      11             :  ******************************************************************************
      12             :  * Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com>
      13             :  * Copyright (c) 2008-2010, Even Rouault <even dot rouault at spatialys.com>
      14             :  *
      15             :  * Permission is hereby granted, free of charge, to any person obtaining a
      16             :  * copy of this software and associated documentation files (the "Software"),
      17             :  * to deal in the Software without restriction, including without limitation
      18             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      19             :  * and/or sell copies of the Software, and to permit persons to whom the
      20             :  * Software is furnished to do so, subject to the following conditions:
      21             :  *
      22             :  * The above copyright notice and this permission notice shall be included
      23             :  * in all copies or substantial portions of the Software.
      24             :  *
      25             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      26             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      27             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      28             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      29             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      30             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      31             :  * DEALINGS IN THE SOFTWARE.
      32             :  ****************************************************************************/
      33             : 
      34             : #include "cpl_port.h"
      35             : #include "cpl_string.h"
      36             : #include "gdal_frmts.h"
      37             : #include "gdal_pam.h"
      38             : 
      39             : #include <algorithm>
      40             : 
      41             : struct ImageRec
      42             : {
      43             :     GUInt16 imagic;
      44             :     GByte type;
      45             :     GByte bpc;
      46             :     GUInt16 dim;
      47             :     GUInt16 xsize;
      48             :     GUInt16 ysize;
      49             :     GUInt16 zsize;
      50             :     GUInt32 min;
      51             :     GUInt32 max;
      52             :     char wasteBytes[4];
      53             :     char name[80];
      54             :     GUInt32 colorMap;
      55             : 
      56             :     VSILFILE *file;
      57             :     std::string fileName;
      58             :     int tmpSize;
      59             :     unsigned char *tmp;
      60             :     GUInt32 rleEnd;
      61             :     int rleTableDirty;
      62             :     GUInt32 *rowStart;
      63             :     GInt32 *rowSize;
      64             : 
      65        5606 :     ImageRec()
      66        5606 :         : imagic(0), type(0), bpc(1), dim(0), xsize(0), ysize(0), zsize(0),
      67             :           min(0), max(0), colorMap(0), file(nullptr), fileName(""), tmpSize(0),
      68             :           tmp(nullptr), rleEnd(0), rleTableDirty(FALSE), rowStart(nullptr),
      69        5606 :           rowSize(nullptr)
      70             :     {
      71        5606 :         memset(wasteBytes, 0, 4);
      72        5606 :         memset(name, 0, 80);
      73        5606 :     }
      74             : 
      75        5606 :     void Swap()
      76             :     {
      77             : #ifdef CPL_LSB
      78        5606 :         CPL_SWAP16PTR(&imagic);
      79        5606 :         CPL_SWAP16PTR(&dim);
      80        5606 :         CPL_SWAP16PTR(&xsize);
      81        5606 :         CPL_SWAP16PTR(&ysize);
      82        5606 :         CPL_SWAP16PTR(&zsize);
      83        5606 :         CPL_SWAP32PTR(&min);
      84        5606 :         CPL_SWAP32PTR(&max);
      85             : #endif
      86        5606 :     }
      87             : };
      88             : 
      89             : /************************************************************************/
      90             : /*                            ConvertLong()                             */
      91             : /************************************************************************/
      92             : #ifdef CPL_LSB
      93          60 : static void ConvertLong(GUInt32 *array, GInt32 length)
      94             : {
      95          60 :     GUInt32 *ptr = reinterpret_cast<GUInt32 *>(array);
      96        7300 :     while (length--)
      97             :     {
      98        7240 :         CPL_SWAP32PTR(ptr);
      99        7240 :         ptr++;
     100             :     }
     101          60 : }
     102             : #else
     103             : static void ConvertLong(GUInt32 * /*array*/, GInt32 /*length */)
     104             : {
     105             : }
     106             : #endif
     107             : 
     108             : /************************************************************************/
     109             : /*                            ImageGetRow()                             */
     110             : /************************************************************************/
     111          90 : static CPLErr ImageGetRow(ImageRec *image, unsigned char *buf, int y, int z)
     112             : {
     113          90 :     y = image->ysize - 1 - y;
     114             : 
     115          90 :     if (static_cast<int>(image->type) != 1)
     116             :     {
     117           0 :         VSIFSeekL(image->file,
     118           0 :                   512 + (y * static_cast<vsi_l_offset>(image->xsize)) +
     119           0 :                       (z * static_cast<vsi_l_offset>(image->xsize) *
     120           0 :                        static_cast<vsi_l_offset>(image->ysize)),
     121             :                   SEEK_SET);
     122           0 :         if (VSIFReadL(buf, 1, image->xsize, image->file) != image->xsize)
     123             :         {
     124           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
     125             :                      "file read error: row (%d) of (%s)\n", y,
     126           0 :                      image->fileName.empty() ? "none"
     127           0 :                                              : image->fileName.c_str());
     128           0 :             return CE_Failure;
     129             :         }
     130           0 :         return CE_None;
     131             :     }
     132             : 
     133             :     // Image type 1.
     134             : 
     135             :     // reads row
     136          90 :     if (image->rowSize[y + z * image->ysize] < 0 ||
     137          90 :         image->rowSize[y + z * image->ysize] > image->tmpSize)
     138             :     {
     139           0 :         return CE_Failure;
     140             :     }
     141          90 :     VSIFSeekL(image->file,
     142          90 :               static_cast<long>(image->rowStart[y + z * image->ysize]),
     143             :               SEEK_SET);
     144         180 :     if (VSIFReadL(image->tmp, 1,
     145          90 :                   static_cast<GUInt32>(image->rowSize[y + z * image->ysize]),
     146          90 :                   image->file) !=
     147          90 :         static_cast<GUInt32>(image->rowSize[y + z * image->ysize]))
     148             :     {
     149           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     150             :                  "file read error: row (%d) of (%s)\n", y,
     151           0 :                  image->fileName.empty() ? "none" : image->fileName.c_str());
     152           0 :         return CE_Failure;
     153             :     }
     154             : 
     155             :     // expands row
     156          90 :     unsigned char *iPtr = image->tmp;
     157          90 :     unsigned char *oPtr = buf;
     158          90 :     int xsizeCount = 0;
     159             :     for (;;)
     160             :     {
     161         288 :         unsigned char pixel = *iPtr++;
     162         288 :         int count = static_cast<int>(pixel & 0x7F);
     163         288 :         if (!count)
     164             :         {
     165          90 :             if (xsizeCount != image->xsize)
     166             :             {
     167           0 :                 CPLError(CE_Failure, CPLE_OpenFailed,
     168             :                          "file read error: row (%d) of (%s)\n", y,
     169           0 :                          image->fileName.empty() ? "none"
     170           0 :                                                  : image->fileName.c_str());
     171           0 :                 return CE_Failure;
     172             :             }
     173             :             else
     174             :             {
     175          90 :                 break;
     176             :             }
     177             :         }
     178             : 
     179         198 :         if (xsizeCount + count > image->xsize)
     180             :         {
     181           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     182             :                      "Wrong repetition number that would overflow data "
     183             :                      "at line %d",
     184             :                      y);
     185           0 :             return CE_Failure;
     186             :         }
     187             : 
     188         198 :         if (pixel & 0x80)
     189             :         {
     190         110 :             memcpy(oPtr, iPtr, count);
     191         110 :             iPtr += count;
     192             :         }
     193             :         else
     194             :         {
     195          88 :             pixel = *iPtr++;
     196          88 :             memset(oPtr, pixel, count);
     197             :         }
     198         198 :         oPtr += count;
     199         198 :         xsizeCount += count;
     200         198 :     }
     201             : 
     202          90 :     return CE_None;
     203             : }
     204             : 
     205             : /************************************************************************/
     206             : /* ==================================================================== */
     207             : /*                              SGIDataset                              */
     208             : /* ==================================================================== */
     209             : /************************************************************************/
     210             : 
     211             : class SGIRasterBand;
     212             : 
     213             : class SGIDataset final : public GDALPamDataset
     214             : {
     215             :     friend class SGIRasterBand;
     216             : 
     217             :     VSILFILE *fpImage;
     218             : 
     219             :     int bGeoTransformValid;
     220             :     double adfGeoTransform[6];
     221             : 
     222             :     ImageRec image;
     223             : 
     224             :   public:
     225             :     SGIDataset();
     226             :     virtual ~SGIDataset();
     227             : 
     228             :     virtual CPLErr GetGeoTransform(double *) override;
     229             :     static GDALDataset *Open(GDALOpenInfo *);
     230             :     static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
     231             :                                int nBandsIn, GDALDataType eType,
     232             :                                char **papszOptions);
     233             : };
     234             : 
     235             : /************************************************************************/
     236             : /* ==================================================================== */
     237             : /*                            SGIRasterBand                             */
     238             : /* ==================================================================== */
     239             : /************************************************************************/
     240             : 
     241             : class SGIRasterBand final : public GDALPamRasterBand
     242             : {
     243             :     friend class SGIDataset;
     244             : 
     245             :   public:
     246             :     SGIRasterBand(SGIDataset *, int);
     247             : 
     248             :     virtual CPLErr IReadBlock(int, int, void *) override;
     249             :     virtual CPLErr IWriteBlock(int, int, void *) override;
     250             :     virtual GDALColorInterp GetColorInterpretation() override;
     251             : };
     252             : 
     253             : /************************************************************************/
     254             : /*                           SGIRasterBand()                            */
     255             : /************************************************************************/
     256             : 
     257          53 : SGIRasterBand::SGIRasterBand(SGIDataset *poDSIn, int nBandIn)
     258             : 
     259             : {
     260          53 :     poDS = poDSIn;
     261          53 :     nBand = nBandIn;
     262             : 
     263          53 :     if (static_cast<int>(poDSIn->image.bpc) == 1)
     264          53 :         eDataType = GDT_Byte;
     265             :     else
     266           0 :         eDataType = GDT_Int16;
     267             : 
     268          53 :     nBlockXSize = poDSIn->nRasterXSize;
     269          53 :     nBlockYSize = 1;
     270          53 : }
     271             : 
     272             : /************************************************************************/
     273             : /*                             IReadBlock()                             */
     274             : /************************************************************************/
     275             : 
     276          90 : CPLErr SGIRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
     277             :                                  void *pImage)
     278             : {
     279          90 :     SGIDataset *poGDS = reinterpret_cast<SGIDataset *>(poDS);
     280             : 
     281          90 :     CPLAssert(nBlockXOff == 0);
     282             : 
     283             :     /* -------------------------------------------------------------------- */
     284             :     /*      Load the desired data into the working buffer.              */
     285             :     /* -------------------------------------------------------------------- */
     286         180 :     return ImageGetRow(&(poGDS->image),
     287             :                        reinterpret_cast<unsigned char *>(pImage), nBlockYOff,
     288          90 :                        nBand - 1);
     289             : }
     290             : 
     291             : /************************************************************************/
     292             : /*                             IWritelock()                             */
     293             : /************************************************************************/
     294             : 
     295         220 : CPLErr SGIRasterBand::IWriteBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
     296             :                                   void *pImage)
     297             : {
     298         220 :     CPLAssert(nBlockXOff == 0);
     299             : 
     300         220 :     SGIDataset *poGDS = reinterpret_cast<SGIDataset *>(poDS);
     301         220 :     ImageRec *image = &(poGDS->image);
     302             : 
     303             :     /* -------------------------------------------------------------------- */
     304             :     /*      Handle the fairly trivial non-RLE case.                         */
     305             :     /* -------------------------------------------------------------------- */
     306         220 :     if (image->type == 0)
     307             :     {
     308           0 :         VSIFSeekL(image->file,
     309           0 :                   512 + (nBlockYOff * static_cast<vsi_l_offset>(image->xsize)) +
     310           0 :                       ((nBand - 1) * static_cast<vsi_l_offset>(image->xsize) *
     311           0 :                        static_cast<vsi_l_offset>(image->ysize)),
     312             :                   SEEK_SET);
     313           0 :         if (VSIFWriteL(pImage, 1, image->xsize, image->file) != image->xsize)
     314             :         {
     315           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
     316             :                      "file write error: row (%d)\n", nBlockYOff);
     317           0 :             return CE_Failure;
     318             :         }
     319           0 :         return CE_None;
     320             :     }
     321             : 
     322             :     /* -------------------------------------------------------------------- */
     323             :     /*      Handle RLE case.                                                */
     324             :     /* -------------------------------------------------------------------- */
     325         220 :     const GByte *pabyRawBuf = reinterpret_cast<const GByte *>(pImage);
     326             :     GByte *pabyRLEBuf =
     327         220 :         reinterpret_cast<GByte *>(CPLMalloc(image->xsize * 2 + 6));
     328             : 
     329         220 :     int iX = 0;
     330         220 :     int nRLEBytes = 0;
     331             : 
     332         528 :     while (iX < image->xsize)
     333             :     {
     334         308 :         int nRepeatCount = 1;
     335             : 
     336        2216 :         while (iX + nRepeatCount < image->xsize && nRepeatCount < 127 &&
     337        2065 :                pabyRawBuf[iX + nRepeatCount] == pabyRawBuf[iX])
     338        1908 :             nRepeatCount++;
     339             : 
     340         308 :         if (nRepeatCount > 2 || iX + nRepeatCount == image->xsize ||
     341          90 :             (iX + nRepeatCount < image->xsize - 3 &&
     342          87 :              pabyRawBuf[iX + nRepeatCount + 1] ==
     343          87 :                  pabyRawBuf[iX + nRepeatCount + 2] &&
     344          16 :              pabyRawBuf[iX + nRepeatCount + 1] ==
     345          16 :                  pabyRawBuf[iX + nRepeatCount + 3]))
     346             :         {  // encode a constant run.
     347         226 :             pabyRLEBuf[nRLEBytes++] = static_cast<GByte>(nRepeatCount);
     348         226 :             pabyRLEBuf[nRLEBytes++] = pabyRawBuf[iX];
     349         226 :             iX += nRepeatCount;
     350             :         }
     351             :         else
     352             :         {  // copy over mixed data.
     353        2272 :             for (nRepeatCount = 1;
     354        2272 :                  iX + nRepeatCount < image->xsize && nRepeatCount < 127;
     355             :                  nRepeatCount++)
     356             :             {
     357        2203 :                 if (iX + nRepeatCount + 3 >= image->xsize)
     358         204 :                     continue;
     359             : 
     360             :                 // quit if the next 3 pixels match
     361        1999 :                 if (pabyRawBuf[iX + nRepeatCount] ==
     362        1999 :                         pabyRawBuf[iX + nRepeatCount + 1] &&
     363          91 :                     pabyRawBuf[iX + nRepeatCount] ==
     364          91 :                         pabyRawBuf[iX + nRepeatCount + 2])
     365          13 :                     break;
     366             :             }
     367             : 
     368          82 :             pabyRLEBuf[nRLEBytes++] = static_cast<GByte>(0x80 | nRepeatCount);
     369          82 :             memcpy(pabyRLEBuf + nRLEBytes, pabyRawBuf + iX, nRepeatCount);
     370             : 
     371          82 :             nRLEBytes += nRepeatCount;
     372          82 :             iX += nRepeatCount;
     373             :         }
     374             :     }
     375             : 
     376             :     // EOL marker.
     377         220 :     pabyRLEBuf[nRLEBytes++] = 0;
     378             : 
     379             :     /* -------------------------------------------------------------------- */
     380             :     /*      Write RLE Buffer at end of file.                                */
     381             :     /* -------------------------------------------------------------------- */
     382         220 :     const int row =
     383         220 :         (image->ysize - nBlockYOff - 1) + (nBand - 1) * image->ysize;
     384             : 
     385         220 :     VSIFSeekL(image->file, 0, SEEK_END);
     386             : 
     387         220 :     image->rowStart[row] = static_cast<GUInt32>(VSIFTellL(image->file));
     388         220 :     image->rowSize[row] = nRLEBytes;
     389         220 :     image->rleTableDirty = TRUE;
     390             : 
     391         220 :     if (static_cast<int>(VSIFWriteL(pabyRLEBuf, 1, nRLEBytes, image->file)) !=
     392             :         nRLEBytes)
     393             :     {
     394           0 :         CPLFree(pabyRLEBuf);
     395           0 :         CPLError(CE_Failure, CPLE_OpenFailed, "file write error: row (%d)\n",
     396             :                  nBlockYOff);
     397           0 :         return CE_Failure;
     398             :     }
     399             : 
     400         220 :     CPLFree(pabyRLEBuf);
     401             : 
     402         220 :     return CE_None;
     403             : }
     404             : 
     405             : /************************************************************************/
     406             : /*                       GetColorInterpretation()                       */
     407             : /************************************************************************/
     408             : 
     409           0 : GDALColorInterp SGIRasterBand::GetColorInterpretation()
     410             : 
     411             : {
     412           0 :     SGIDataset *poGDS = reinterpret_cast<SGIDataset *>(poDS);
     413             : 
     414           0 :     if (poGDS->nBands == 1)
     415           0 :         return GCI_GrayIndex;
     416           0 :     else if (poGDS->nBands == 2)
     417             :     {
     418           0 :         if (nBand == 1)
     419           0 :             return GCI_GrayIndex;
     420             :         else
     421           0 :             return GCI_AlphaBand;
     422             :     }
     423           0 :     else if (poGDS->nBands == 3)
     424             :     {
     425           0 :         if (nBand == 1)
     426           0 :             return GCI_RedBand;
     427           0 :         else if (nBand == 2)
     428           0 :             return GCI_GreenBand;
     429             :         else
     430           0 :             return GCI_BlueBand;
     431             :     }
     432           0 :     else if (poGDS->nBands == 4)
     433             :     {
     434           0 :         if (nBand == 1)
     435           0 :             return GCI_RedBand;
     436           0 :         else if (nBand == 2)
     437           0 :             return GCI_GreenBand;
     438           0 :         else if (nBand == 3)
     439           0 :             return GCI_BlueBand;
     440             :         else
     441           0 :             return GCI_AlphaBand;
     442             :     }
     443           0 :     return GCI_Undefined;
     444             : }
     445             : 
     446             : /************************************************************************/
     447             : /* ==================================================================== */
     448             : /*                             SGIDataset                               */
     449             : /* ==================================================================== */
     450             : /************************************************************************/
     451             : 
     452             : /************************************************************************/
     453             : /*                            SGIDataset()                              */
     454             : /************************************************************************/
     455             : 
     456          25 : SGIDataset::SGIDataset() : fpImage(nullptr), bGeoTransformValid(FALSE)
     457             : {
     458          25 :     adfGeoTransform[0] = 0.0;
     459          25 :     adfGeoTransform[1] = 1.0;
     460          25 :     adfGeoTransform[2] = 0.0;
     461          25 :     adfGeoTransform[3] = 0.0;
     462          25 :     adfGeoTransform[4] = 0.0;
     463          25 :     adfGeoTransform[5] = 1.0;
     464          25 : }
     465             : 
     466             : /************************************************************************/
     467             : /*                           ~SGIDataset()                            */
     468             : /************************************************************************/
     469             : 
     470          50 : SGIDataset::~SGIDataset()
     471             : 
     472             : {
     473          25 :     FlushCache(true);
     474             : 
     475             :     // Do we need to write out rle table?
     476          25 :     if (image.rleTableDirty)
     477             :     {
     478           7 :         CPLDebug("SGI", "Flushing RLE offset table.");
     479           7 :         ConvertLong(image.rowStart, image.ysize * image.zsize);
     480           7 :         ConvertLong(reinterpret_cast<GUInt32 *>(image.rowSize),
     481           7 :                     image.ysize * image.zsize);
     482             : 
     483           7 :         VSIFSeekL(fpImage, 512, SEEK_SET);
     484           7 :         size_t nSize =
     485           7 :             static_cast<size_t>(image.ysize) * static_cast<size_t>(image.zsize);
     486           7 :         VSIFWriteL(image.rowStart, 4, nSize, fpImage);
     487           7 :         VSIFWriteL(image.rowSize, 4, nSize, fpImage);
     488           7 :         image.rleTableDirty = FALSE;
     489             :     }
     490             : 
     491          25 :     if (fpImage != nullptr)
     492          25 :         VSIFCloseL(fpImage);
     493             : 
     494          25 :     CPLFree(image.tmp);
     495          25 :     CPLFree(image.rowSize);
     496          25 :     CPLFree(image.rowStart);
     497          50 : }
     498             : 
     499             : /************************************************************************/
     500             : /*                          GetGeoTransform()                           */
     501             : /************************************************************************/
     502             : 
     503           5 : CPLErr SGIDataset::GetGeoTransform(double *padfTransform)
     504             : 
     505             : {
     506           5 :     if (bGeoTransformValid)
     507             :     {
     508           0 :         memcpy(padfTransform, adfGeoTransform, sizeof(double) * 6);
     509           0 :         return CE_None;
     510             :     }
     511             : 
     512           5 :     return GDALPamDataset::GetGeoTransform(padfTransform);
     513             : }
     514             : 
     515             : /************************************************************************/
     516             : /*                                Open()                                */
     517             : /************************************************************************/
     518             : 
     519       32831 : GDALDataset *SGIDataset::Open(GDALOpenInfo *poOpenInfo)
     520             : 
     521             : {
     522             :     /* -------------------------------------------------------------------- */
     523             :     /*      First we check to see if the file has the expected header       */
     524             :     /*      bytes.                                                          */
     525             :     /* -------------------------------------------------------------------- */
     526       32831 :     if (poOpenInfo->nHeaderBytes < 12 || poOpenInfo->fpL == nullptr)
     527       27250 :         return nullptr;
     528             : 
     529       11162 :     ImageRec tmpImage;
     530        5581 :     memcpy(&tmpImage.imagic, poOpenInfo->pabyHeader + 0, 2);
     531        5581 :     memcpy(&tmpImage.type, poOpenInfo->pabyHeader + 2, 1);
     532        5581 :     memcpy(&tmpImage.bpc, poOpenInfo->pabyHeader + 3, 1);
     533        5581 :     memcpy(&tmpImage.dim, poOpenInfo->pabyHeader + 4, 2);
     534        5581 :     memcpy(&tmpImage.xsize, poOpenInfo->pabyHeader + 6, 2);
     535        5581 :     memcpy(&tmpImage.ysize, poOpenInfo->pabyHeader + 8, 2);
     536        5581 :     memcpy(&tmpImage.zsize, poOpenInfo->pabyHeader + 10, 2);
     537        5581 :     tmpImage.Swap();
     538             : 
     539        5581 :     if (tmpImage.imagic != 474)
     540        5556 :         return nullptr;
     541             : 
     542          25 :     if (tmpImage.type != 0 && tmpImage.type != 1)
     543           0 :         return nullptr;
     544             : 
     545          25 :     if (tmpImage.bpc != 1 && tmpImage.bpc != 2)
     546           0 :         return nullptr;
     547             : 
     548          25 :     if (tmpImage.dim != 1 && tmpImage.dim != 2 && tmpImage.dim != 3)
     549           0 :         return nullptr;
     550             : 
     551          25 :     if (tmpImage.bpc != 1)
     552             :     {
     553           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     554             :                  "The SGI driver only supports 1 byte channel values.\n");
     555           0 :         return nullptr;
     556             :     }
     557             : 
     558             :     /* -------------------------------------------------------------------- */
     559             :     /*      Create a corresponding GDALDataset.                             */
     560             :     /* -------------------------------------------------------------------- */
     561          25 :     SGIDataset *poDS = new SGIDataset();
     562          25 :     poDS->eAccess = poOpenInfo->eAccess;
     563          25 :     poDS->fpImage = poOpenInfo->fpL;
     564          25 :     poOpenInfo->fpL = nullptr;
     565             : 
     566             :     /* -------------------------------------------------------------------- */
     567             :     /*      Read pre-image data after ensuring the file is rewound.         */
     568             :     /* -------------------------------------------------------------------- */
     569          25 :     VSIFSeekL(poDS->fpImage, 0, SEEK_SET);
     570          25 :     if (VSIFReadL(reinterpret_cast<void *>(&(poDS->image)), 1, 12,
     571          25 :                   poDS->fpImage) != 12)
     572             :     {
     573           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     574             :                  "file read error while reading header in sgidataset.cpp");
     575           0 :         delete poDS;
     576           0 :         return nullptr;
     577             :     }
     578          25 :     poDS->image.Swap();
     579          25 :     poDS->image.file = poDS->fpImage;
     580          25 :     poDS->image.fileName = poOpenInfo->pszFilename;
     581             : 
     582             :     /* -------------------------------------------------------------------- */
     583             :     /*      Capture some information from the file that is of interest.     */
     584             :     /* -------------------------------------------------------------------- */
     585          25 :     poDS->nRasterXSize = poDS->image.xsize;
     586          25 :     poDS->nRasterYSize = poDS->image.ysize;
     587          25 :     if (poDS->nRasterXSize <= 0 || poDS->nRasterYSize <= 0)
     588             :     {
     589           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     590             :                  "Invalid image dimensions : %d x %d", poDS->nRasterXSize,
     591             :                  poDS->nRasterYSize);
     592           0 :         delete poDS;
     593           0 :         return nullptr;
     594             :     }
     595          25 :     poDS->nBands = std::max(static_cast<GUInt16>(1), poDS->image.zsize);
     596          25 :     if (poDS->nBands > 256)
     597             :     {
     598           0 :         CPLError(CE_Failure, CPLE_OpenFailed, "Too many bands : %d",
     599             :                  poDS->nBands);
     600           0 :         delete poDS;
     601           0 :         return nullptr;
     602             :     }
     603             : 
     604          25 :     const int numItems = (static_cast<int>(poDS->image.bpc) == 1) ? 256 : 65536;
     605          25 :     if (poDS->image.xsize > INT_MAX / numItems)
     606             :     {
     607           0 :         delete poDS;
     608           0 :         return nullptr;
     609             :     }
     610          25 :     poDS->image.tmpSize = poDS->image.xsize * numItems;
     611          25 :     poDS->image.tmp =
     612          25 :         (unsigned char *)VSI_CALLOC_VERBOSE(poDS->image.xsize, numItems);
     613          25 :     if (poDS->image.tmp == nullptr)
     614             :     {
     615           0 :         delete poDS;
     616           0 :         return nullptr;
     617             :     }
     618             : 
     619             :     /* -------------------------------------------------------------------- */
     620             :     /*      Read RLE Pointer tables.                                        */
     621             :     /* -------------------------------------------------------------------- */
     622          25 :     if (static_cast<int>(poDS->image.type) == 1)  // RLE compressed
     623             :     {
     624          25 :         const size_t x = static_cast<size_t>(poDS->image.ysize) * poDS->nBands *
     625             :                          sizeof(GUInt32);
     626          25 :         poDS->image.rowStart = reinterpret_cast<GUInt32 *>(VSI_MALLOC2_VERBOSE(
     627             :             poDS->image.ysize, poDS->nBands * sizeof(GUInt32)));
     628          25 :         poDS->image.rowSize = reinterpret_cast<GInt32 *>(VSI_MALLOC2_VERBOSE(
     629             :             poDS->image.ysize, poDS->nBands * sizeof(GUInt32)));
     630          25 :         if (poDS->image.rowStart == nullptr || poDS->image.rowSize == nullptr)
     631             :         {
     632           0 :             delete poDS;
     633           0 :             return nullptr;
     634             :         }
     635          25 :         memset(poDS->image.rowStart, 0, x);
     636          25 :         memset(poDS->image.rowSize, 0, x);
     637          25 :         poDS->image.rleEnd = static_cast<GUInt32>(512 + (2 * x));
     638          25 :         VSIFSeekL(poDS->fpImage, 512, SEEK_SET);
     639          25 :         if (VSIFReadL(poDS->image.rowStart, 1, x, poDS->image.file) != x)
     640             :         {
     641           2 :             delete poDS;
     642           2 :             CPLError(CE_Failure, CPLE_OpenFailed,
     643             :                      "file read error while reading start positions in "
     644             :                      "sgidataset.cpp");
     645           2 :             return nullptr;
     646             :         }
     647          23 :         if (VSIFReadL(poDS->image.rowSize, 1, x, poDS->image.file) != x)
     648             :         {
     649           0 :             delete poDS;
     650           0 :             CPLError(
     651             :                 CE_Failure, CPLE_OpenFailed,
     652             :                 "file read error while reading row lengths in sgidataset.cpp");
     653           0 :             return nullptr;
     654             :         }
     655          23 :         ConvertLong(poDS->image.rowStart,
     656          23 :                     static_cast<int>(x / static_cast<int>(sizeof(GUInt32))));
     657          23 :         ConvertLong(reinterpret_cast<GUInt32 *>(poDS->image.rowSize),
     658          23 :                     static_cast<int>(x / static_cast<int>(sizeof(GInt32))));
     659             :     }
     660             :     else  // uncompressed.
     661             :     {
     662           0 :         poDS->image.rowStart = nullptr;
     663           0 :         poDS->image.rowSize = nullptr;
     664             :     }
     665             : 
     666             :     /* -------------------------------------------------------------------- */
     667             :     /*      Create band information objects.                                */
     668             :     /* -------------------------------------------------------------------- */
     669          76 :     for (int iBand = 0; iBand < poDS->nBands; iBand++)
     670          53 :         poDS->SetBand(iBand + 1, new SGIRasterBand(poDS, iBand + 1));
     671             : 
     672             :     /* -------------------------------------------------------------------- */
     673             :     /*      Check for world file.                                           */
     674             :     /* -------------------------------------------------------------------- */
     675          46 :     poDS->bGeoTransformValid = GDALReadWorldFile(poOpenInfo->pszFilename,
     676          23 :                                                  ".wld", poDS->adfGeoTransform);
     677             : 
     678             :     /* -------------------------------------------------------------------- */
     679             :     /*      Initialize any PAM information.                                 */
     680             :     /* -------------------------------------------------------------------- */
     681          23 :     poDS->SetDescription(poOpenInfo->pszFilename);
     682          23 :     poDS->TryLoadXML();
     683             : 
     684             :     /* -------------------------------------------------------------------- */
     685             :     /*      Check for overviews.                                            */
     686             :     /* -------------------------------------------------------------------- */
     687          23 :     poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename);
     688             : 
     689          23 :     return poDS;
     690             : }
     691             : 
     692             : /************************************************************************/
     693             : /*                               Create()                               */
     694             : /************************************************************************/
     695             : 
     696          62 : GDALDataset *SGIDataset::Create(const char *pszFilename, int nXSize, int nYSize,
     697             :                                 int nBandsIn, GDALDataType eType,
     698             :                                 CPL_UNUSED char **papszOptions)
     699             : {
     700          62 :     if (eType != GDT_Byte)
     701             :     {
     702          36 :         CPLError(CE_Failure, CPLE_AppDefined,
     703             :                  "Attempt to create SGI dataset with an illegal\n"
     704             :                  "data type (%s), only Byte supported by the format.\n",
     705             :                  GDALGetDataTypeName(eType));
     706             : 
     707          36 :         return nullptr;
     708             :     }
     709             : 
     710             :     /* -------------------------------------------------------------------- */
     711             :     /*      Open the file for output.                                       */
     712             :     /* -------------------------------------------------------------------- */
     713          26 :     VSILFILE *fp = VSIFOpenL(pszFilename, "w");
     714          26 :     if (fp == nullptr)
     715             :     {
     716           3 :         CPLError(CE_Failure, CPLE_OpenFailed, "Failed to create file '%s': %s",
     717           3 :                  pszFilename, VSIStrerror(errno));
     718           3 :         return nullptr;
     719             :     }
     720             : 
     721             :     /* -------------------------------------------------------------------- */
     722             :     /*      Prepare and write 512 byte header.                              */
     723             :     /* -------------------------------------------------------------------- */
     724             :     GByte abyHeader[512];
     725             : 
     726          23 :     memset(abyHeader, 0, 512);
     727             : 
     728          23 :     abyHeader[0] = 1;
     729          23 :     abyHeader[1] = 218;
     730          23 :     abyHeader[2] = 1;  // RLE
     731          23 :     abyHeader[3] = 1;  // 8bit
     732             : 
     733             :     GInt16 nShortValue;
     734          23 :     if (nBandsIn == 1)
     735          14 :         nShortValue = CPL_MSBWORD16(2);
     736             :     else
     737           9 :         nShortValue = CPL_MSBWORD16(3);
     738          23 :     memcpy(abyHeader + 4, &nShortValue, 2);
     739             : 
     740          23 :     nShortValue = CPL_MSBWORD16(nXSize);
     741          23 :     memcpy(abyHeader + 6, &nShortValue, 2);
     742             : 
     743          23 :     nShortValue = CPL_MSBWORD16(nYSize);
     744          23 :     memcpy(abyHeader + 8, &nShortValue, 2);
     745             : 
     746          23 :     nShortValue = CPL_MSBWORD16(nBandsIn);
     747          23 :     memcpy(abyHeader + 10, &nShortValue, 2);
     748             : 
     749          23 :     GInt32 nIntValue = CPL_MSBWORD32(0);
     750          23 :     memcpy(abyHeader + 12, &nIntValue, 4);
     751             : 
     752          23 :     GUInt32 nUIntValue = CPL_MSBWORD32(255);
     753          23 :     memcpy(abyHeader + 16, &nUIntValue, 4);
     754             : 
     755          23 :     VSIFWriteL(abyHeader, 1, 512, fp);
     756             : 
     757             :     /* -------------------------------------------------------------------- */
     758             :     /*      Create our RLE compressed zero-ed dummy line.                   */
     759             :     /* -------------------------------------------------------------------- */
     760             :     GByte *pabyRLELine =
     761          23 :         reinterpret_cast<GByte *>(CPLMalloc((nXSize / 127) * 2 + 4));
     762             : 
     763          23 :     int nPixelsRemaining = nXSize;
     764          23 :     GInt32 nRLEBytes = 0;
     765          46 :     while (nPixelsRemaining > 0)
     766             :     {
     767          23 :         pabyRLELine[nRLEBytes] =
     768          23 :             static_cast<GByte>(std::min(127, nPixelsRemaining));
     769          23 :         pabyRLELine[nRLEBytes + 1] = 0;
     770          23 :         nPixelsRemaining -= pabyRLELine[nRLEBytes];
     771             : 
     772          23 :         nRLEBytes += 2;
     773             :     }
     774             : 
     775             :     /* -------------------------------------------------------------------- */
     776             :     /*      Prepare and write RLE offset/size tables with everything        */
     777             :     /*      zeroed indicating dummy lines.                                  */
     778             :     /* -------------------------------------------------------------------- */
     779          23 :     const int nTableLen = nYSize * nBandsIn;
     780          23 :     GInt32 nDummyRLEOffset = 512 + 4 * nTableLen * 2;
     781             : 
     782          23 :     CPL_MSBPTR32(&nRLEBytes);
     783          23 :     CPL_MSBPTR32(&nDummyRLEOffset);
     784             : 
     785        1843 :     for (int i = 0; i < nTableLen; i++)
     786        1820 :         VSIFWriteL(&nDummyRLEOffset, 1, 4, fp);
     787             : 
     788        1843 :     for (int i = 0; i < nTableLen; i++)
     789        1820 :         VSIFWriteL(&nRLEBytes, 1, 4, fp);
     790             : 
     791             :     /* -------------------------------------------------------------------- */
     792             :     /*      write the dummy RLE blank line.                                 */
     793             :     /* -------------------------------------------------------------------- */
     794          23 :     CPL_MSBPTR32(&nRLEBytes);
     795          23 :     if (static_cast<GInt32>(VSIFWriteL(pabyRLELine, 1, nRLEBytes, fp)) !=
     796             :         nRLEBytes)
     797             :     {
     798           2 :         CPLError(CE_Failure, CPLE_FileIO, "Failure writing SGI file '%s'.\n%s",
     799           2 :                  pszFilename, VSIStrerror(errno));
     800           2 :         VSIFCloseL(fp);
     801           2 :         CPLFree(pabyRLELine);
     802           2 :         return nullptr;
     803             :     }
     804             : 
     805          21 :     VSIFCloseL(fp);
     806          21 :     CPLFree(pabyRLELine);
     807             : 
     808          21 :     return GDALDataset::FromHandle(GDALOpen(pszFilename, GA_Update));
     809             : }
     810             : 
     811             : /************************************************************************/
     812             : /*                         GDALRegister_SGI()                           */
     813             : /************************************************************************/
     814             : 
     815        1520 : void GDALRegister_SGI()
     816             : 
     817             : {
     818        1520 :     if (GDALGetDriverByName("SGI") != nullptr)
     819         301 :         return;
     820             : 
     821        1219 :     GDALDriver *poDriver = new GDALDriver();
     822             : 
     823        1219 :     poDriver->SetDescription("SGI");
     824        1219 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     825        1219 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "SGI Image File Format 1.0");
     826        1219 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "rgb");
     827        1219 :     poDriver->SetMetadataItem(GDAL_DMD_MIMETYPE, "image/rgb");
     828        1219 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/sgi.html");
     829        1219 :     poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Byte");
     830        1219 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     831             : 
     832        1219 :     poDriver->pfnOpen = SGIDataset::Open;
     833        1219 :     poDriver->pfnCreate = SGIDataset::Create;
     834             : 
     835        1219 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     836             : }

Generated by: LCOV version 1.14