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

Generated by: LCOV version 1.14