LCOV - code coverage report
Current view: top level - frmts/rik - rikdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 71 444 16.0 %
Date: 2025-10-01 17:07:58 Functions: 4 15 26.7 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  RIK Reader
       4             :  * Purpose:  All code for RIK Reader
       5             :  * Author:   Daniel Wallner, daniel.wallner@bredband.net
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2005, Daniel Wallner <daniel.wallner@bredband.net>
       9             :  * Copyright (c) 2008-2011, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include <cfloat>
      15             : #include <zlib.h>
      16             : #include "gdal_frmts.h"
      17             : #include "gdal_colortable.h"
      18             : #include "gdal_pam.h"
      19             : #include "gdal_driver.h"
      20             : #include "gdal_drivermanager.h"
      21             : #include "gdal_openinfo.h"
      22             : #include "gdal_cpp_functions.h"
      23             : 
      24             : #include <cmath>
      25             : 
      26             : #define RIK_HEADER_DEBUG 0
      27             : #define RIK_CLEAR_DEBUG 0
      28             : #define RIK_PIXEL_DEBUG 0
      29             : 
      30             : // #define RIK_SINGLE_BLOCK 0
      31             : 
      32             : #define RIK_ALLOW_BLOCK_ERRORS 1
      33             : 
      34             : //
      35             : // The RIK file format information was extracted from the trikpanel project:
      36             : // http://sourceforge.net/projects/trikpanel/
      37             : //
      38             : // A RIK file consists of the following elements:
      39             : //
      40             : // +--------------------+
      41             : // | Magic "RIK3"       | (Only in RIK version 3)
      42             : // +--------------------+
      43             : // | Map name           | (The first two bytes is the string length)
      44             : // +--------------------+
      45             : // | Header             | (Three different formats exists)
      46             : // +--------------------+
      47             : // | Color palette      |
      48             : // +--------------------+
      49             : // | Block offset array | (Only in compressed formats)
      50             : // +--------------------+
      51             : // | Image blocks       |
      52             : // +--------------------+
      53             : //
      54             : // All numbers are stored in little endian.
      55             : //
      56             : // There are four different image block formats:
      57             : //
      58             : // 1. Uncompressed image block
      59             : //
      60             : //   A stream of palette indexes.
      61             : //
      62             : // 2. RLE image block
      63             : //
      64             : //   The RLE image block is a stream of byte pairs:
      65             : //   |  Run length - 1 (byte)  |  Pixel value (byte)  |  Run length - 1 ...
      66             : //
      67             : // 3. LZW image block
      68             : //
      69             : //   The LZW image block uses the same LZW encoding as a GIF file
      70             : //   except that there is no EOF code and maximum code length is 13 bits.
      71             : //   These blocks are upside down compared to GDAL.
      72             : //
      73             : // 4. ZLIB image block
      74             : //
      75             : //   These blocks are upside down compared to GDAL.
      76             : //
      77             : 
      78             : typedef struct
      79             : {
      80             :     GUInt16 iUnknown;
      81             :     double fSouth;  // Map bounds
      82             :     double fWest;
      83             :     double fNorth;
      84             :     double fEast;
      85             :     GUInt32 iScale;   // Source map scale
      86             :     float iMPPNum;    // Meters per pixel numerator
      87             :     GUInt32 iMPPDen;  // Meters per pixel denominator
      88             :                       // Only used if fSouth < 4000000
      89             :     GUInt32 iBlockWidth;
      90             :     GUInt32 iBlockHeight;
      91             :     GUInt32 iHorBlocks;   // Number of horizontal blocks
      92             :     GUInt32 iVertBlocks;  // Number of vertical blocks
      93             :                           // Only used if fSouth >= 4000000
      94             :     GByte iBitsPerPixel;
      95             :     GByte iOptions;
      96             : } RIKHeader;
      97             : 
      98             : /************************************************************************/
      99             : /* ==================================================================== */
     100             : /*                              RIKDataset                              */
     101             : /* ==================================================================== */
     102             : /************************************************************************/
     103             : 
     104             : class RIKRasterBand;
     105             : 
     106             : class RIKDataset final : public GDALPamDataset
     107             : {
     108             :     friend class RIKRasterBand;
     109             : 
     110             :     VSILFILE *fp;
     111             : 
     112             :     OGRSpatialReference m_oSRS{};
     113             :     GDALGeoTransform m_gt{};
     114             : 
     115             :     GUInt32 nBlockXSize;
     116             :     GUInt32 nBlockYSize;
     117             :     GUInt32 nHorBlocks;
     118             :     GUInt32 nVertBlocks;
     119             :     GUInt32 nFileSize;
     120             :     GUInt32 *pOffsets;
     121             :     GByte options;
     122             : 
     123             :     GDALColorTable *poColorTable;
     124             : 
     125             :   public:
     126             :     RIKDataset();
     127             :     ~RIKDataset() override;
     128             : 
     129             :     static GDALDataset *Open(GDALOpenInfo *);
     130             :     static int Identify(GDALOpenInfo *);
     131             : 
     132             :     CPLErr GetGeoTransform(GDALGeoTransform &gt) const override;
     133             :     const OGRSpatialReference *GetSpatialRef() const override;
     134             : };
     135             : 
     136             : /************************************************************************/
     137             : /* ==================================================================== */
     138             : /*                            RIKRasterBand                             */
     139             : /* ==================================================================== */
     140             : /************************************************************************/
     141             : 
     142             : class RIKRasterBand final : public GDALPamRasterBand
     143             : {
     144             :     friend class RIKDataset;
     145             : 
     146             :   public:
     147             :     RIKRasterBand(RIKDataset *, int);
     148             : 
     149             :     CPLErr IReadBlock(int, int, void *) override;
     150             :     GDALColorInterp GetColorInterpretation() override;
     151             :     GDALColorTable *GetColorTable() override;
     152             : };
     153             : 
     154             : /************************************************************************/
     155             : /*                           RIKRasterBand()                            */
     156             : /************************************************************************/
     157             : 
     158           0 : RIKRasterBand::RIKRasterBand(RIKDataset *poDSIn, int nBandIn)
     159             : 
     160             : {
     161           0 :     poDS = poDSIn;
     162           0 :     nBand = nBandIn;
     163             : 
     164           0 :     eDataType = GDT_Byte;
     165             : 
     166           0 :     nBlockXSize = poDSIn->nBlockXSize;
     167           0 :     nBlockYSize = poDSIn->nBlockYSize;
     168           0 : }
     169             : 
     170             : /************************************************************************/
     171             : /*                             GetNextLZWCode()                         */
     172             : /************************************************************************/
     173             : 
     174           0 : static int GetNextLZWCode(int codeBits, const GByte *blockData,
     175             :                           const GUInt32 blockSize, GUInt32 &filePos,
     176             :                           GUInt32 &fileAlign, int &bitsTaken)
     177             : 
     178             : {
     179           0 :     if (filePos == fileAlign)
     180             :     {
     181           0 :         fileAlign += codeBits;
     182             :     }
     183             : 
     184           0 :     const int BitMask[] = {0x0000, 0x0001, 0x0003, 0x0007,
     185             :                            0x000f, 0x001f, 0x003f, 0x007f};
     186             : 
     187           0 :     int ret = 0;
     188           0 :     int bitsLeftToGo = codeBits;
     189             : 
     190           0 :     while (bitsLeftToGo > 0)
     191             :     {
     192           0 :         if (filePos >= blockSize)
     193           0 :             return -1;
     194             : 
     195           0 :         int tmp = blockData[filePos];
     196           0 :         tmp = tmp >> bitsTaken;
     197             : 
     198           0 :         if (bitsLeftToGo < 8)
     199           0 :             tmp &= BitMask[bitsLeftToGo];
     200             : 
     201           0 :         tmp = tmp << (codeBits - bitsLeftToGo);
     202             : 
     203           0 :         ret |= tmp;
     204             : 
     205           0 :         bitsLeftToGo -= (8 - bitsTaken);
     206           0 :         bitsTaken = 0;
     207             : 
     208           0 :         if (bitsLeftToGo < 0)
     209           0 :             bitsTaken = 8 + bitsLeftToGo;
     210             : 
     211           0 :         if (bitsTaken == 0)
     212           0 :             filePos++;
     213             :     }
     214             : 
     215             : #if RIK_PIXEL_DEBUG
     216             :     printf("c%03X\n", ret); /*ok*/
     217             : #endif
     218             : 
     219           0 :     return ret;
     220             : }
     221             : 
     222             : /************************************************************************/
     223             : /*                             OutputPixel()                            */
     224             : /************************************************************************/
     225             : 
     226           0 : static void OutputPixel(GByte pixel, void *image, GUInt32 imageWidth,
     227             :                         GUInt32 lineBreak, int &imageLine, GUInt32 &imagePos)
     228             : 
     229             : {
     230           0 :     if (imagePos < imageWidth && imageLine >= 0)
     231           0 :         reinterpret_cast<GByte *>(image)[imagePos + imageLine * imageWidth] =
     232             :             pixel;
     233             : 
     234           0 :     imagePos++;
     235             : 
     236             : #if RIK_PIXEL_DEBUG
     237             :     printf("_%02X %d\n", pixel, imagePos); /*ok*/
     238             : #endif
     239             : 
     240             :     // Check if we need to change line
     241             : 
     242           0 :     if (imagePos == lineBreak)
     243             :     {
     244             : #if RIK_PIXEL_DEBUG
     245             :         printf("\n%d\n", imageLine); /*ok*/
     246             : #endif
     247             : 
     248           0 :         imagePos = 0;
     249             : 
     250           0 :         imageLine--;
     251             :     }
     252           0 : }
     253             : 
     254             : /************************************************************************/
     255             : /*                             IReadBlock()                             */
     256             : /************************************************************************/
     257             : 
     258           0 : CPLErr RIKRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
     259             : 
     260             : {
     261           0 :     RIKDataset *poRDS = cpl::down_cast<RIKDataset *>(poDS);
     262             : 
     263           0 :     const GUInt32 blocks = poRDS->nHorBlocks * poRDS->nVertBlocks;
     264           0 :     const GUInt32 nBlockIndex = nBlockXOff + nBlockYOff * poRDS->nHorBlocks;
     265           0 :     const GUInt32 nBlockOffset = poRDS->pOffsets[nBlockIndex];
     266             : 
     267           0 :     GUInt32 nBlockSize = poRDS->nFileSize;
     268           0 :     for (GUInt32 bi = nBlockIndex + 1; bi < blocks; bi++)
     269             :     {
     270           0 :         if (poRDS->pOffsets[bi])
     271             :         {
     272           0 :             nBlockSize = poRDS->pOffsets[bi];
     273           0 :             break;
     274             :         }
     275             :     }
     276           0 :     nBlockSize -= nBlockOffset;
     277             : 
     278           0 :     const GUInt32 pixels = poRDS->nBlockXSize * poRDS->nBlockYSize;
     279             : 
     280           0 :     if (!nBlockOffset || !nBlockSize
     281             : #ifdef RIK_SINGLE_BLOCK
     282             :         || nBlockIndex != RIK_SINGLE_BLOCK
     283             : #endif
     284             :     )
     285             :     {
     286           0 :         memset(pImage, 0, pixels);
     287           0 :         return CE_None;
     288             :     }
     289             : 
     290           0 :     VSIFSeekL(poRDS->fp, nBlockOffset, SEEK_SET);
     291             : 
     292             :     /* -------------------------------------------------------------------- */
     293             :     /*      Read uncompressed block.                                        */
     294             :     /* -------------------------------------------------------------------- */
     295             : 
     296           0 :     if (poRDS->options == 0x00 || poRDS->options == 0x40)
     297             :     {
     298           0 :         VSIFReadL(pImage, 1, pixels, poRDS->fp);
     299           0 :         return CE_None;
     300             :     }
     301             : 
     302             :     // Read block to memory
     303           0 :     GByte *blockData = static_cast<GByte *>(VSI_MALLOC_VERBOSE(nBlockSize));
     304           0 :     if (blockData == nullptr)
     305           0 :         return CE_Failure;
     306           0 :     if (VSIFReadL(blockData, 1, nBlockSize, poRDS->fp) != nBlockSize)
     307             :     {
     308           0 :         VSIFree(blockData);
     309           0 :         return CE_Failure;
     310             :     }
     311           0 :     memset(pImage, 0, pixels);
     312             : 
     313             :     /* -------------------------------------------------------------------- */
     314             :     /*      Read RLE block.                                                 */
     315             :     /* -------------------------------------------------------------------- */
     316           0 :     GUInt32 filePos = 0;
     317           0 :     GUInt32 imagePos = 0;
     318             : 
     319           0 :     if (poRDS->options == 0x01 || poRDS->options == 0x41)
     320             :     {
     321           0 :         while (filePos + 1 < nBlockSize && imagePos < pixels)
     322             :         {
     323           0 :             GByte count = blockData[filePos++];
     324           0 :             GByte color = blockData[filePos++];
     325             : 
     326           0 :             for (GByte i = 0; imagePos < pixels && i <= count; i++)
     327             :             {
     328           0 :                 reinterpret_cast<GByte *>(pImage)[imagePos++] = color;
     329             :             }
     330           0 :         }
     331             :     }
     332             : 
     333             :     /* -------------------------------------------------------------------- */
     334             :     /*      Read LZW block.                                                 */
     335             :     /* -------------------------------------------------------------------- */
     336             : 
     337           0 :     else if (poRDS->options == 0x0b)
     338             :     {
     339             :         try
     340             :         {
     341           0 :             if (nBlockSize < 5)
     342             :             {
     343           0 :                 throw "Not enough bytes";
     344             :             }
     345             : 
     346           0 :             const bool LZW_HAS_CLEAR_CODE = !!(blockData[4] & 0x80);
     347           0 :             const int LZW_MAX_BITS = blockData[4] & 0x1f;  // Max 13
     348           0 :             if (LZW_MAX_BITS > 13)
     349             :             {
     350           0 :                 throw "Invalid LZW_MAX_BITS";
     351             :             }
     352           0 :             const int LZW_BITS_PER_PIXEL = 8;
     353           0 :             const int LZW_OFFSET = 5;
     354             : 
     355           0 :             const int LZW_CLEAR = 1 << LZW_BITS_PER_PIXEL;
     356           0 :             const int LZW_CODES = 1 << LZW_MAX_BITS;
     357           0 :             const int LZW_NO_SUCH_CODE = LZW_CODES + 1;
     358             : 
     359           0 :             int lastAdded = LZW_HAS_CLEAR_CODE ? LZW_CLEAR : LZW_CLEAR - 1;
     360           0 :             int codeBits = LZW_BITS_PER_PIXEL + 1;
     361             : 
     362             :             int code;
     363             :             int lastCode;
     364             :             GByte lastOutput;
     365           0 :             int bitsTaken = 0;
     366             : 
     367             :             int prefix[8192];       // only need LZW_CODES for size.
     368             :             GByte character[8192];  // only need LZW_CODES for size.
     369             : 
     370           0 :             for (int i = 0; i < LZW_CLEAR; i++)
     371           0 :                 character[i] = static_cast<GByte>(i);
     372           0 :             for (int i = 0; i < LZW_CODES; i++)
     373           0 :                 prefix[i] = LZW_NO_SUCH_CODE;
     374             : 
     375           0 :             filePos = LZW_OFFSET;
     376           0 :             GUInt32 fileAlign = LZW_OFFSET;
     377           0 :             int imageLine = poRDS->nBlockYSize - 1;
     378             : 
     379           0 :             GUInt32 lineBreak = poRDS->nBlockXSize;
     380             : 
     381             :             // 32 bit alignment
     382           0 :             lineBreak += 3;
     383           0 :             lineBreak &= 0xfffffffc;
     384             : 
     385           0 :             code = GetNextLZWCode(codeBits, blockData, nBlockSize, filePos,
     386             :                                   fileAlign, bitsTaken);
     387           0 :             if (code < 0)
     388             :             {
     389           0 :                 throw "Not enough bytes";
     390             :             }
     391             : 
     392           0 :             OutputPixel(static_cast<GByte>(code), pImage, poRDS->nBlockXSize,
     393             :                         lineBreak, imageLine, imagePos);
     394           0 :             lastOutput = static_cast<GByte>(code);
     395             : 
     396           0 :             while (imageLine >= 0 &&
     397           0 :                    (imageLine || imagePos < poRDS->nBlockXSize) &&
     398           0 :                    filePos < nBlockSize)
     399             :             {
     400           0 :                 lastCode = code;
     401           0 :                 code = GetNextLZWCode(codeBits, blockData, nBlockSize, filePos,
     402             :                                       fileAlign, bitsTaken);
     403           0 :                 if (code < 0)
     404             :                 {
     405           0 :                     throw "Not enough bytes";
     406             :                 }
     407             : 
     408           0 :                 if (LZW_HAS_CLEAR_CODE && code == LZW_CLEAR)
     409             :                 {
     410             : #if RIK_CLEAR_DEBUG
     411             :                     CPLDebug("RIK",
     412             :                              "Clearing block %d\n"
     413             :                              " x=%d y=%d\n"
     414             :                              " pos=%d size=%d\n",
     415             :                              nBlockIndex, imagePos, imageLine, filePos,
     416             :                              nBlockSize);
     417             : #endif
     418             : 
     419             :                     // Clear prefix table
     420           0 :                     for (int i = LZW_CLEAR; i < LZW_CODES; i++)
     421           0 :                         prefix[i] = LZW_NO_SUCH_CODE;
     422           0 :                     lastAdded = LZW_CLEAR;
     423           0 :                     codeBits = LZW_BITS_PER_PIXEL + 1;
     424             : 
     425           0 :                     filePos = fileAlign;
     426           0 :                     bitsTaken = 0;
     427             : 
     428           0 :                     code = GetNextLZWCode(codeBits, blockData, nBlockSize,
     429             :                                           filePos, fileAlign, bitsTaken);
     430           0 :                     if (code < 0)
     431             :                     {
     432           0 :                         throw "Not enough bytes";
     433             :                     }
     434             : 
     435           0 :                     if (code > lastAdded)
     436             :                     {
     437           0 :                         throw "Clear Error";
     438             :                     }
     439             : 
     440           0 :                     OutputPixel((GByte)code, pImage, poRDS->nBlockXSize,
     441             :                                 lineBreak, imageLine, imagePos);
     442           0 :                     lastOutput = (GByte)code;
     443             :                 }
     444             :                 else
     445             :                 {
     446             :                     // Set-up decoding
     447             : 
     448             :                     GByte stack[8192];  // only need LZW_CODES for size.
     449             : 
     450           0 :                     int stackPtr = 0;
     451           0 :                     int decodeCode = code;
     452             : 
     453           0 :                     if (code == lastAdded + 1)
     454             :                     {
     455             :                         // Handle special case
     456           0 :                         *stack = lastOutput;
     457           0 :                         stackPtr = 1;
     458           0 :                         decodeCode = lastCode;
     459             :                     }
     460           0 :                     else if (code > lastAdded + 1)
     461             :                     {
     462           0 :                         throw "Too high code";
     463             :                     }
     464             : 
     465             :                     // Decode
     466             : 
     467           0 :                     int i = 0;
     468           0 :                     while (++i < LZW_CODES && decodeCode >= LZW_CLEAR &&
     469             :                            decodeCode < LZW_NO_SUCH_CODE)
     470             :                     {
     471           0 :                         stack[stackPtr++] = character[decodeCode];
     472           0 :                         decodeCode = prefix[decodeCode];
     473             :                     }
     474           0 :                     stack[stackPtr++] = static_cast<GByte>(decodeCode);
     475             : 
     476           0 :                     if (i == LZW_CODES || decodeCode >= LZW_NO_SUCH_CODE)
     477             :                     {
     478           0 :                         throw "Decode error";
     479             :                     }
     480             : 
     481             :                     // Output stack
     482             : 
     483           0 :                     lastOutput = stack[stackPtr - 1];
     484             : 
     485           0 :                     while (stackPtr != 0 && imagePos < pixels)
     486             :                     {
     487           0 :                         OutputPixel(stack[--stackPtr], pImage,
     488             :                                     poRDS->nBlockXSize, lineBreak, imageLine,
     489             :                                     imagePos);
     490             :                     }
     491             : 
     492             :                     // Add code to string table
     493             : 
     494           0 :                     if (lastCode != LZW_NO_SUCH_CODE &&
     495           0 :                         lastAdded != LZW_CODES - 1)
     496             :                     {
     497           0 :                         ++lastAdded;
     498           0 :                         if (lastAdded >= 8192)
     499             :                         {
     500           0 :                             throw "Decode error";
     501             :                         }
     502           0 :                         prefix[lastAdded] = lastCode;
     503           0 :                         character[lastAdded] = lastOutput;
     504             :                     }
     505             : 
     506             :                     // Check if we need to use more bits
     507             : 
     508           0 :                     if (lastAdded == (1 << codeBits) - 1 &&
     509             :                         codeBits != LZW_MAX_BITS)
     510             :                     {
     511           0 :                         codeBits++;
     512             : 
     513           0 :                         filePos = fileAlign;
     514           0 :                         bitsTaken = 0;
     515             :                     }
     516             :                 }
     517             :             }
     518             :         }
     519           0 :         catch (const char *errStr)
     520             :         {
     521             : #if RIK_ALLOW_BLOCK_ERRORS
     522           0 :             CPLDebug("RIK",
     523             :                      "LZW Decompress Failed: %s\n"
     524             :                      " blocks: %d\n"
     525             :                      " blockindex: %d\n"
     526             :                      " blockoffset: %X\n"
     527             :                      " blocksize: %d\n",
     528             :                      errStr, blocks, nBlockIndex, nBlockOffset, nBlockSize);
     529             : #else
     530             :             CPLFree(blockData);
     531             :             CPLError(CE_Failure, CPLE_AppDefined,
     532             :                      "RIK decompression failed: %s", errStr);
     533             :             return CE_Failure;
     534             : #endif
     535             :         }
     536             :     }
     537             : 
     538             :     /* -------------------------------------------------------------------- */
     539             :     /*      Read ZLIB block.                                                */
     540             :     /* -------------------------------------------------------------------- */
     541             : 
     542           0 :     else if (poRDS->options == 0x0d)
     543             :     {
     544           0 :         uLong destLen = pixels;
     545           0 :         Byte *upsideDown = static_cast<Byte *>(CPLMalloc(pixels));
     546             : 
     547           0 :         if (uncompress(upsideDown, &destLen, blockData, nBlockSize) != Z_OK)
     548             :         {
     549           0 :             CPLDebug("RIK", "Deflate compression failed on block %u",
     550             :                      nBlockIndex);
     551             :         }
     552             : 
     553           0 :         for (GUInt32 i = 0; i < poRDS->nBlockYSize; i++)
     554             :         {
     555           0 :             memcpy(reinterpret_cast<Byte *>(pImage) + poRDS->nBlockXSize * i,
     556           0 :                    upsideDown +
     557           0 :                        poRDS->nBlockXSize * (poRDS->nBlockYSize - i - 1),
     558           0 :                    poRDS->nBlockXSize);
     559             :         }
     560             : 
     561           0 :         CPLFree(upsideDown);
     562             :     }
     563             : 
     564           0 :     CPLFree(blockData);
     565             : 
     566           0 :     return CE_None;
     567             : }
     568             : 
     569             : /************************************************************************/
     570             : /*                       GetColorInterpretation()                       */
     571             : /************************************************************************/
     572             : 
     573           0 : GDALColorInterp RIKRasterBand::GetColorInterpretation()
     574             : 
     575             : {
     576           0 :     return GCI_PaletteIndex;
     577             : }
     578             : 
     579             : /************************************************************************/
     580             : /*                           GetColorTable()                            */
     581             : /************************************************************************/
     582             : 
     583           0 : GDALColorTable *RIKRasterBand::GetColorTable()
     584             : 
     585             : {
     586           0 :     RIKDataset *poRDS = cpl::down_cast<RIKDataset *>(poDS);
     587             : 
     588           0 :     return poRDS->poColorTable;
     589             : }
     590             : 
     591             : /************************************************************************/
     592             : /* ==================================================================== */
     593             : /*                              RIKDataset                              */
     594             : /* ==================================================================== */
     595             : /************************************************************************/
     596             : 
     597             : /************************************************************************/
     598             : /*                             RIKDataset()                             */
     599             : /************************************************************************/
     600             : 
     601           0 : RIKDataset::RIKDataset()
     602             :     : fp(nullptr), nBlockXSize(0), nBlockYSize(0), nHorBlocks(0),
     603             :       nVertBlocks(0), nFileSize(0), pOffsets(nullptr), options(0),
     604           0 :       poColorTable(nullptr)
     605             : 
     606             : {
     607           0 :     m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     608           0 :     m_oSRS.importFromWkt(
     609             :         "PROJCS[\"RT90 2.5 gon "
     610             :         "V\",GEOGCS[\"RT90\",DATUM[\"Rikets_koordinatsystem_1990\",SPHEROID["
     611             :         "\"Bessel "
     612             :         "1841\",6377397.155,299.1528128,AUTHORITY[\"EPSG\",\"7004\"]],TOWGS84["
     613             :         "414.1055246174,41.3265500042,603.0582474221,-0.8551163377,2."
     614             :         "1413174055,-7.0227298286,0],AUTHORITY[\"EPSG\",\"6124\"]],PRIMEM["
     615             :         "\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0."
     616             :         "0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\","
     617             :         "\"4124\"]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"latitude_"
     618             :         "of_origin\",0],PARAMETER[\"central_meridian\",15.80827777777778],"
     619             :         "PARAMETER[\"scale_factor\",1],PARAMETER[\"false_easting\",1500000],"
     620             :         "PARAMETER[\"false_northing\",0],UNIT[\"metre\",1,AUTHORITY[\"EPSG\","
     621             :         "\"9001\"]],AUTHORITY[\"EPSG\",\"3021\"]]");
     622           0 : }
     623             : 
     624             : /************************************************************************/
     625             : /*                            ~RIKDataset()                             */
     626             : /************************************************************************/
     627             : 
     628           0 : RIKDataset::~RIKDataset()
     629             : 
     630             : {
     631           0 :     FlushCache(true);
     632           0 :     CPLFree(pOffsets);
     633           0 :     if (fp != nullptr)
     634           0 :         VSIFCloseL(fp);
     635           0 :     delete poColorTable;
     636           0 : }
     637             : 
     638             : /************************************************************************/
     639             : /*                          GetGeoTransform()                           */
     640             : /************************************************************************/
     641             : 
     642           0 : CPLErr RIKDataset::GetGeoTransform(GDALGeoTransform &gt) const
     643             : 
     644             : {
     645           0 :     gt = m_gt;
     646           0 :     return CE_None;
     647             : }
     648             : 
     649             : /************************************************************************/
     650             : /*                          GetSpatialRef()                             */
     651             : /************************************************************************/
     652             : 
     653           0 : const OGRSpatialReference *RIKDataset::GetSpatialRef() const
     654             : 
     655             : {
     656           0 :     return &m_oSRS;
     657             : }
     658             : 
     659             : /************************************************************************/
     660             : /*                             GetRikString()                           */
     661             : /************************************************************************/
     662             : 
     663         810 : static GUInt16 GetRikString(VSILFILE *fp, char *str, GUInt16 strLength)
     664             : 
     665             : {
     666             :     GUInt16 actLength;
     667             : 
     668         810 :     VSIFReadL(&actLength, 1, sizeof(actLength), fp);
     669             : #ifdef CPL_MSB
     670             :     CPL_SWAP16PTR(&actLength);
     671             : #endif
     672             : 
     673         810 :     if (actLength + 2 > strLength)
     674             :     {
     675           0 :         return actLength;
     676             :     }
     677             : 
     678         810 :     VSIFReadL(str, 1, actLength, fp);
     679             : 
     680         810 :     str[actLength] = '\0';
     681             : 
     682         810 :     return actLength;
     683             : }
     684             : 
     685             : /************************************************************************/
     686             : /*                          Identify()                                  */
     687             : /************************************************************************/
     688             : 
     689       59155 : int RIKDataset::Identify(GDALOpenInfo *poOpenInfo)
     690             : 
     691             : {
     692       59155 :     if (poOpenInfo->fpL == nullptr || poOpenInfo->nHeaderBytes < 50)
     693       54893 :         return FALSE;
     694             : 
     695        4262 :     if (STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader, "RIK3"))
     696             :     {
     697           0 :         return TRUE;
     698             :     }
     699             :     else
     700             :     {
     701             :         GUInt16 actLength;
     702        4262 :         memcpy(&actLength, poOpenInfo->pabyHeader, 2);
     703             : #ifdef CPL_MSB
     704             :         CPL_SWAP16PTR(&actLength);
     705             : #endif
     706        4262 :         if (actLength + 2 > 1024)
     707             :         {
     708        2525 :             return FALSE;
     709             :         }
     710        1737 :         if (actLength == 0)
     711        1671 :             return -1;
     712             : 
     713        2549 :         for (int i = 0; i < actLength; i++)
     714             :         {
     715        2543 :             if (poOpenInfo->pabyHeader[2 + i] == 0)
     716          60 :                 return FALSE;
     717             :         }
     718             : 
     719           6 :         if (poOpenInfo->IsExtensionEqualToCI("rik"))
     720           0 :             return TRUE;
     721             : 
     722             :         // We really need Open to be able to conclude
     723           6 :         return -1;
     724             :     }
     725             : }
     726             : 
     727             : /************************************************************************/
     728             : /*                                Open()                                */
     729             : /************************************************************************/
     730             : 
     731         810 : GDALDataset *RIKDataset::Open(GDALOpenInfo *poOpenInfo)
     732             : 
     733             : {
     734         810 :     if (Identify(poOpenInfo) == FALSE)
     735           0 :         return nullptr;
     736             : 
     737         810 :     bool rik3header = false;
     738             : 
     739         810 :     if (STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader, "RIK3"))
     740             :     {
     741           0 :         rik3header = true;
     742           0 :         VSIFSeekL(poOpenInfo->fpL, 4, SEEK_SET);
     743             :     }
     744             :     else
     745         810 :         VSIFSeekL(poOpenInfo->fpL, 0, SEEK_SET);
     746             : 
     747             :     /* -------------------------------------------------------------------- */
     748             :     /*      Read the map name.                                              */
     749             :     /* -------------------------------------------------------------------- */
     750             : 
     751             :     char name[1024];
     752             : 
     753         810 :     GUInt16 nameLength = GetRikString(poOpenInfo->fpL, name, sizeof(name));
     754             : 
     755         810 :     if (nameLength > sizeof(name) - 1)
     756             :     {
     757           0 :         return nullptr;
     758             :     }
     759             : 
     760         810 :     if (!rik3header)
     761             :     {
     762         810 :         if (nameLength == 0 || nameLength != strlen(name))
     763         807 :             return nullptr;
     764             :     }
     765             : 
     766             :     /* -------------------------------------------------------------------- */
     767             :     /*      Read the header.                                                */
     768             :     /* -------------------------------------------------------------------- */
     769             : 
     770             :     RIKHeader header;
     771             :     double metersPerPixel;
     772             : 
     773           3 :     const char *headerType = "RIK3";
     774             : 
     775           3 :     if (rik3header)
     776             :     {
     777             :         /* --------------------------------------------------------------------
     778             :          */
     779             :         /*      RIK3 header. */
     780             :         /* --------------------------------------------------------------------
     781             :          */
     782             : 
     783             :         // Read projection name
     784             : 
     785             :         char projection[1024];
     786             : 
     787             :         GUInt16 projLength =
     788           0 :             GetRikString(poOpenInfo->fpL, projection, sizeof(projection));
     789             : 
     790           0 :         if (projLength > sizeof(projection) - 1)
     791             :         {
     792             :             // Unreasonable string length, assume wrong format
     793           0 :             return nullptr;
     794             :         }
     795             : 
     796             :         // Read unknown string
     797             : 
     798           0 :         /*projLength =*/GetRikString(poOpenInfo->fpL, projection,
     799             :                                      sizeof(projection));
     800             : 
     801             :         // Read map north edge
     802             : 
     803             :         char tmpStr[16];
     804             : 
     805             :         GUInt16 tmpLength =
     806           0 :             GetRikString(poOpenInfo->fpL, tmpStr, sizeof(tmpStr));
     807             : 
     808           0 :         if (tmpLength > sizeof(tmpStr) - 1)
     809             :         {
     810             :             // Unreasonable string length, assume wrong format
     811           0 :             return nullptr;
     812             :         }
     813             : 
     814           0 :         header.fNorth = CPLAtof(tmpStr);
     815             : 
     816             :         // Read map west edge
     817             : 
     818           0 :         tmpLength = GetRikString(poOpenInfo->fpL, tmpStr, sizeof(tmpStr));
     819             : 
     820           0 :         if (tmpLength > sizeof(tmpStr) - 1)
     821             :         {
     822             :             // Unreasonable string length, assume wrong format
     823           0 :             return nullptr;
     824             :         }
     825             : 
     826           0 :         header.fWest = CPLAtof(tmpStr);
     827             : 
     828             :         // Read binary values
     829             : 
     830           0 :         VSIFReadL(&header.iScale, 1, sizeof(header.iScale), poOpenInfo->fpL);
     831           0 :         VSIFReadL(&header.iMPPNum, 1, sizeof(header.iMPPNum), poOpenInfo->fpL);
     832           0 :         VSIFReadL(&header.iBlockWidth, 1, sizeof(header.iBlockWidth),
     833             :                   poOpenInfo->fpL);
     834           0 :         VSIFReadL(&header.iBlockHeight, 1, sizeof(header.iBlockHeight),
     835             :                   poOpenInfo->fpL);
     836           0 :         VSIFReadL(&header.iHorBlocks, 1, sizeof(header.iHorBlocks),
     837             :                   poOpenInfo->fpL);
     838           0 :         VSIFReadL(&header.iVertBlocks, 1, sizeof(header.iVertBlocks),
     839             :                   poOpenInfo->fpL);
     840             : #ifdef CPL_MSB
     841             :         CPL_SWAP32PTR(&header.iScale);
     842             :         CPL_SWAP32PTR(&header.iMPPNum);
     843             :         CPL_SWAP32PTR(&header.iBlockWidth);
     844             :         CPL_SWAP32PTR(&header.iBlockHeight);
     845             :         CPL_SWAP32PTR(&header.iHorBlocks);
     846             :         CPL_SWAP32PTR(&header.iVertBlocks);
     847             : #endif
     848           0 :         if (header.iMPPNum == 0)
     849           0 :             return nullptr;
     850             : 
     851           0 :         VSIFReadL(&header.iBitsPerPixel, 1, sizeof(header.iBitsPerPixel),
     852             :                   poOpenInfo->fpL);
     853           0 :         VSIFReadL(&header.iOptions, 1, sizeof(header.iOptions),
     854             :                   poOpenInfo->fpL);
     855           0 :         header.iUnknown = header.iOptions;
     856           0 :         VSIFReadL(&header.iOptions, 1, sizeof(header.iOptions),
     857             :                   poOpenInfo->fpL);
     858             : 
     859           0 :         header.fSouth =
     860           0 :             header.fNorth - static_cast<double>(header.iVertBlocks) *
     861           0 :                                 header.iBlockHeight * header.iMPPNum;
     862           0 :         header.fEast = header.fWest + static_cast<double>(header.iHorBlocks) *
     863           0 :                                           header.iBlockWidth * header.iMPPNum;
     864             : 
     865           0 :         metersPerPixel = header.iMPPNum;
     866             :     }
     867             :     else
     868             :     {
     869             :         /* --------------------------------------------------------------------
     870             :          */
     871             :         /*      Old RIK header. */
     872             :         /* --------------------------------------------------------------------
     873             :          */
     874             : 
     875           3 :         VSIFReadL(&header.iUnknown, 1, sizeof(header.iUnknown),
     876             :                   poOpenInfo->fpL);
     877           3 :         VSIFReadL(&header.fSouth, 1, sizeof(header.fSouth), poOpenInfo->fpL);
     878           3 :         VSIFReadL(&header.fWest, 1, sizeof(header.fWest), poOpenInfo->fpL);
     879           3 :         VSIFReadL(&header.fNorth, 1, sizeof(header.fNorth), poOpenInfo->fpL);
     880           3 :         VSIFReadL(&header.fEast, 1, sizeof(header.fEast), poOpenInfo->fpL);
     881           3 :         VSIFReadL(&header.iScale, 1, sizeof(header.iScale), poOpenInfo->fpL);
     882           3 :         VSIFReadL(&header.iMPPNum, 1, sizeof(header.iMPPNum), poOpenInfo->fpL);
     883             : #ifdef CPL_MSB
     884             :         CPL_SWAP64PTR(&header.fSouth);
     885             :         CPL_SWAP64PTR(&header.fWest);
     886             :         CPL_SWAP64PTR(&header.fNorth);
     887             :         CPL_SWAP64PTR(&header.fEast);
     888             :         CPL_SWAP32PTR(&header.iScale);
     889             :         CPL_SWAP32PTR(&header.iMPPNum);
     890             : #endif
     891             : 
     892           6 :         if (!std::isfinite(header.fSouth) || !std::isfinite(header.fWest) ||
     893           9 :             !std::isfinite(header.fNorth) || !std::isfinite(header.fEast) ||
     894           3 :             header.iMPPNum == 0)
     895             :         {
     896           0 :             return nullptr;
     897             :         }
     898             : 
     899           3 :         const bool offsetBounds = header.fSouth < 4000000;
     900             : 
     901           3 :         header.iMPPDen = 1;
     902             : 
     903           3 :         if (offsetBounds)
     904             :         {
     905           3 :             header.fSouth += 4002995;
     906           3 :             header.fNorth += 5004000;
     907           3 :             header.fWest += 201000;
     908           3 :             header.fEast += 302005;
     909             : 
     910           3 :             VSIFReadL(&header.iMPPDen, 1, sizeof(header.iMPPDen),
     911             :                       poOpenInfo->fpL);
     912             : #ifdef CPL_MSB
     913             :             CPL_SWAP32PTR(&header.iMPPDen);
     914             : #endif
     915           3 :             if (header.iMPPDen == 0)
     916           0 :                 return nullptr;
     917             : 
     918           3 :             headerType = "RIK1";
     919             :         }
     920             :         else
     921             :         {
     922           0 :             headerType = "RIK2";
     923             :         }
     924             : 
     925           3 :         metersPerPixel = header.iMPPNum / static_cast<double>(header.iMPPDen);
     926             : 
     927           3 :         VSIFReadL(&header.iBlockWidth, 1, sizeof(header.iBlockWidth),
     928             :                   poOpenInfo->fpL);
     929           3 :         VSIFReadL(&header.iBlockHeight, 1, sizeof(header.iBlockHeight),
     930             :                   poOpenInfo->fpL);
     931           3 :         VSIFReadL(&header.iHorBlocks, 1, sizeof(header.iHorBlocks),
     932             :                   poOpenInfo->fpL);
     933             : #ifdef CPL_MSB
     934             :         CPL_SWAP32PTR(&header.iBlockWidth);
     935             :         CPL_SWAP32PTR(&header.iBlockHeight);
     936             :         CPL_SWAP32PTR(&header.iHorBlocks);
     937             : #endif
     938             : 
     939           3 :         if ((header.iBlockWidth > 2000) || (header.iBlockWidth < 10) ||
     940           0 :             (header.iBlockHeight > 2000) || (header.iBlockHeight < 10))
     941           3 :             return nullptr;
     942             : 
     943           0 :         if (!offsetBounds)
     944             :         {
     945           0 :             VSIFReadL(&header.iVertBlocks, 1, sizeof(header.iVertBlocks),
     946             :                       poOpenInfo->fpL);
     947             : #ifdef CPL_MSB
     948             :             CPL_SWAP32PTR(&header.iVertBlocks);
     949             : #endif
     950             :         }
     951             : 
     952           0 :         if (offsetBounds || !header.iVertBlocks)
     953             :         {
     954           0 :             double dfVertBlocks = ceil((header.fNorth - header.fSouth) /
     955           0 :                                        (header.iBlockHeight * metersPerPixel));
     956           0 :             if (dfVertBlocks < 1 || dfVertBlocks > INT_MAX)
     957           0 :                 return nullptr;
     958           0 :             header.iVertBlocks = static_cast<GUInt32>(dfVertBlocks);
     959             :         }
     960             : 
     961             : #if RIK_HEADER_DEBUG
     962             :         CPLDebug("RIK", "Original vertical blocks %d\n", header.iVertBlocks);
     963             : #endif
     964             : 
     965           0 :         VSIFReadL(&header.iBitsPerPixel, 1, sizeof(header.iBitsPerPixel),
     966             :                   poOpenInfo->fpL);
     967             : 
     968           0 :         if (header.iBitsPerPixel != 8)
     969             :         {
     970           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
     971             :                      "File %s has unsupported number of bits per pixel.\n",
     972             :                      poOpenInfo->pszFilename);
     973           0 :             return nullptr;
     974             :         }
     975             : 
     976           0 :         VSIFReadL(&header.iOptions, 1, sizeof(header.iOptions),
     977             :                   poOpenInfo->fpL);
     978             : 
     979           0 :         if (header.iOptions != 0x00 &&  // Uncompressed
     980           0 :             header.iOptions != 0x40 &&  // Uncompressed
     981           0 :             header.iOptions != 0x01 &&  // RLE
     982           0 :             header.iOptions != 0x41 &&  // RLE
     983           0 :             header.iOptions != 0x0B &&  // LZW
     984           0 :             header.iOptions != 0x0D)    // ZLIB
     985             :         {
     986           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
     987             :                      "File %s. Unknown map options.\n",
     988             :                      poOpenInfo->pszFilename);
     989           0 :             return nullptr;
     990             :         }
     991             :     }
     992             : 
     993           0 :     if (header.iBlockWidth == 0 || header.iHorBlocks == 0 ||
     994           0 :         header.iBlockWidth >= INT_MAX / header.iHorBlocks ||
     995           0 :         header.iBlockHeight == 0 || header.iVertBlocks == 0 ||
     996           0 :         header.iBlockHeight >= INT_MAX / header.iVertBlocks ||
     997           0 :         header.iBlockHeight >= INT_MAX / header.iBlockWidth ||
     998           0 :         header.iVertBlocks >= INT_MAX / (int)sizeof(GUInt32) ||
     999           0 :         header.iHorBlocks >=
    1000           0 :             INT_MAX / (header.iVertBlocks * (int)sizeof(GUInt32)))
    1001             :     {
    1002           0 :         return nullptr;
    1003             :     }
    1004             : 
    1005             :     /* -------------------------------------------------------------------- */
    1006             :     /*      Read the palette.                                               */
    1007             :     /* -------------------------------------------------------------------- */
    1008             : 
    1009             :     GByte palette[768];
    1010             : 
    1011           0 :     for (GUInt16 i = 0; i < 256; i++)
    1012             :     {
    1013           0 :         VSIFReadL(&palette[i * 3 + 2], 1, 1, poOpenInfo->fpL);
    1014           0 :         VSIFReadL(&palette[i * 3 + 1], 1, 1, poOpenInfo->fpL);
    1015           0 :         VSIFReadL(&palette[i * 3 + 0], 1, 1, poOpenInfo->fpL);
    1016             :     }
    1017             : 
    1018             :     /* -------------------------------------------------------------------- */
    1019             :     /*      Find block offsets.                                             */
    1020             :     /* -------------------------------------------------------------------- */
    1021             : 
    1022           0 :     GUInt32 blocks = header.iHorBlocks * header.iVertBlocks;
    1023             :     GUInt32 *offsets =
    1024           0 :         reinterpret_cast<GUInt32 *>(VSIMalloc(blocks * sizeof(GUInt32)));
    1025             : 
    1026           0 :     if (!offsets)
    1027             :     {
    1028           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
    1029             :                  "File %s. Unable to allocate offset table.\n",
    1030             :                  poOpenInfo->pszFilename);
    1031           0 :         return nullptr;
    1032             :     }
    1033             : 
    1034           0 :     if (header.iOptions == 0x00)
    1035             :     {
    1036           0 :         offsets[0] = static_cast<GUInt32>(VSIFTellL(poOpenInfo->fpL));
    1037             : 
    1038           0 :         if (VSIFEofL(poOpenInfo->fpL))
    1039             :         {
    1040           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
    1041             :                      "File %s. Read past end of file.\n",
    1042             :                      poOpenInfo->pszFilename);
    1043           0 :             CPLFree(offsets);
    1044           0 :             return nullptr;
    1045             :         }
    1046             : 
    1047           0 :         VSIFSeekL(poOpenInfo->fpL, 0, SEEK_END);
    1048           0 :         vsi_l_offset nBigFileSize = VSIFTellL(poOpenInfo->fpL);
    1049           0 :         if (nBigFileSize > UINT_MAX)
    1050           0 :             nBigFileSize = UINT_MAX;
    1051           0 :         GUInt32 fileSize = static_cast<GUInt32>(nBigFileSize);
    1052             : 
    1053           0 :         GUInt32 nBlocksFromFileSize =
    1054           0 :             (fileSize - offsets[0]) /
    1055           0 :             (header.iBlockWidth * header.iBlockHeight);
    1056           0 :         if (nBlocksFromFileSize < blocks)
    1057             :         {
    1058           0 :             blocks = nBlocksFromFileSize;
    1059           0 :             header.iVertBlocks = blocks / header.iHorBlocks;
    1060             :         }
    1061             : 
    1062           0 :         if (header.iVertBlocks == 0)
    1063             :         {
    1064           0 :             CPLError(CE_Failure, CPLE_OpenFailed, "File %s too short.\n",
    1065             :                      poOpenInfo->pszFilename);
    1066           0 :             CPLFree(offsets);
    1067           0 :             return nullptr;
    1068             :         }
    1069             : 
    1070           0 :         for (GUInt32 i = 1; i < blocks; i++)
    1071             :         {
    1072           0 :             offsets[i] =
    1073           0 :                 offsets[i - 1] + header.iBlockWidth * header.iBlockHeight;
    1074             :         }
    1075             :     }
    1076             :     else
    1077             :     {
    1078           0 :         for (GUInt32 i = 0; i < blocks; i++)
    1079             :         {
    1080           0 :             if (VSIFReadL(&offsets[i], sizeof(offsets[i]), 1,
    1081           0 :                           poOpenInfo->fpL) != 1)
    1082           0 :                 break;
    1083             : #ifdef CPL_MSB
    1084             :             CPL_SWAP32PTR(&offsets[i]);
    1085             : #endif
    1086           0 :             if (rik3header)
    1087             :             {
    1088             :                 GUInt32 blockSize;
    1089           0 :                 if (VSIFReadL(&blockSize, sizeof(blockSize), 1,
    1090           0 :                               poOpenInfo->fpL) != 1)
    1091           0 :                     break;
    1092             : #ifdef CPL_MSB
    1093             :                 CPL_SWAP32PTR(&blockSize);
    1094             : #endif
    1095             :             }
    1096             :         }
    1097             :     }
    1098             : 
    1099             :     /* -------------------------------------------------------------------- */
    1100             :     /*      Final checks.                                                   */
    1101             :     /* -------------------------------------------------------------------- */
    1102             : 
    1103             :     // File size
    1104             : 
    1105           0 :     if (VSIFEofL(poOpenInfo->fpL))
    1106             :     {
    1107           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
    1108             :                  "File %s. Read past end of file.\n", poOpenInfo->pszFilename);
    1109           0 :         CPLFree(offsets);
    1110           0 :         return nullptr;
    1111             :     }
    1112             : 
    1113           0 :     VSIFSeekL(poOpenInfo->fpL, 0, SEEK_END);
    1114           0 :     GUInt32 fileSize = static_cast<GUInt32>(VSIFTellL(poOpenInfo->fpL));
    1115             : 
    1116             : #if RIK_HEADER_DEBUG
    1117             :     CPLDebug("RIK", "File size %d\n", fileSize);
    1118             : #endif
    1119             : 
    1120             :     // Make sure the offset table is valid
    1121             : 
    1122           0 :     GUInt32 lastoffset = 0;
    1123             : 
    1124           0 :     for (GUInt32 y = 0; y < header.iVertBlocks; y++)
    1125             :     {
    1126           0 :         for (GUInt32 x = 0; x < header.iHorBlocks; x++)
    1127             :         {
    1128           0 :             if (!offsets[x + y * header.iHorBlocks])
    1129             :             {
    1130           0 :                 continue;
    1131             :             }
    1132             : 
    1133           0 :             if (offsets[x + y * header.iHorBlocks] >= fileSize)
    1134             :             {
    1135           0 :                 if (!y)
    1136             :                 {
    1137           0 :                     CPLError(CE_Failure, CPLE_OpenFailed,
    1138             :                              "File %s too short.\n", poOpenInfo->pszFilename);
    1139           0 :                     CPLFree(offsets);
    1140           0 :                     return nullptr;
    1141             :                 }
    1142           0 :                 header.iVertBlocks = y;
    1143           0 :                 break;
    1144             :             }
    1145             : 
    1146           0 :             if (offsets[x + y * header.iHorBlocks] < lastoffset)
    1147             :             {
    1148           0 :                 if (!y)
    1149             :                 {
    1150           0 :                     CPLError(CE_Failure, CPLE_OpenFailed,
    1151             :                              "File %s. Corrupt offset table.\n",
    1152             :                              poOpenInfo->pszFilename);
    1153           0 :                     CPLFree(offsets);
    1154           0 :                     return nullptr;
    1155             :                 }
    1156           0 :                 header.iVertBlocks = y;
    1157           0 :                 break;
    1158             :             }
    1159             : 
    1160           0 :             lastoffset = offsets[x + y * header.iHorBlocks];
    1161             :         }
    1162             :     }
    1163             : 
    1164             : #if RIK_HEADER_DEBUG
    1165             :     CPLDebug("RIK",
    1166             :              "first offset %d\n"
    1167             :              "last offset %d\n",
    1168             :              offsets[0], lastoffset);
    1169             : #endif
    1170             : 
    1171           0 :     const char *compression = "RLE";
    1172             : 
    1173           0 :     if (header.iOptions == 0x00 || header.iOptions == 0x40)
    1174           0 :         compression = "Uncompressed";
    1175           0 :     if (header.iOptions == 0x0b)
    1176           0 :         compression = "LZW";
    1177           0 :     if (header.iOptions == 0x0d)
    1178           0 :         compression = "ZLIB";
    1179             : 
    1180           0 :     CPLDebug("RIK",
    1181             :              "RIK file parameters:\n"
    1182             :              " name: %s\n"
    1183             :              " header: %s\n"
    1184             :              " unknown: 0x%X\n"
    1185             :              " south: %f\n"
    1186             :              " west: %f\n"
    1187             :              " north: %f\n"
    1188             :              " east: %f\n"
    1189             :              " original scale: %d\n"
    1190             :              " meters per pixel: %f\n"
    1191             :              " block width: %d\n"
    1192             :              " block height: %d\n"
    1193             :              " horizontal blocks: %d\n"
    1194             :              " vertical blocks: %d\n"
    1195             :              " bits per pixel: %d\n"
    1196             :              " options: 0x%X\n"
    1197             :              " compression: %s\n",
    1198           0 :              name, headerType, header.iUnknown, header.fSouth, header.fWest,
    1199             :              header.fNorth, header.fEast, header.iScale, metersPerPixel,
    1200             :              header.iBlockWidth, header.iBlockHeight, header.iHorBlocks,
    1201           0 :              header.iVertBlocks, header.iBitsPerPixel, header.iOptions,
    1202             :              compression);
    1203             : 
    1204             :     /* -------------------------------------------------------------------- */
    1205             :     /*      Create a corresponding GDALDataset.                             */
    1206             :     /* -------------------------------------------------------------------- */
    1207             : 
    1208           0 :     RIKDataset *poDS = new RIKDataset();
    1209             : 
    1210           0 :     poDS->fp = poOpenInfo->fpL;
    1211           0 :     poOpenInfo->fpL = nullptr;
    1212             : 
    1213           0 :     poDS->m_gt[0] = header.fWest - metersPerPixel / 2.0;
    1214           0 :     poDS->m_gt[1] = metersPerPixel;
    1215           0 :     poDS->m_gt[2] = 0.0;
    1216           0 :     poDS->m_gt[3] = header.fNorth + metersPerPixel / 2.0;
    1217           0 :     poDS->m_gt[4] = 0.0;
    1218           0 :     poDS->m_gt[5] = -metersPerPixel;
    1219             : 
    1220           0 :     poDS->nBlockXSize = header.iBlockWidth;
    1221           0 :     poDS->nBlockYSize = header.iBlockHeight;
    1222           0 :     poDS->nHorBlocks = header.iHorBlocks;
    1223           0 :     poDS->nVertBlocks = header.iVertBlocks;
    1224           0 :     poDS->pOffsets = offsets;
    1225           0 :     poDS->options = header.iOptions;
    1226           0 :     poDS->nFileSize = fileSize;
    1227             : 
    1228           0 :     poDS->nRasterXSize = header.iBlockWidth * header.iHorBlocks;
    1229           0 :     poDS->nRasterYSize = header.iBlockHeight * header.iVertBlocks;
    1230             : 
    1231           0 :     poDS->nBands = 1;
    1232             : 
    1233             :     GDALColorEntry oEntry;
    1234           0 :     poDS->poColorTable = new GDALColorTable();
    1235           0 :     for (GUInt16 i = 0; i < 256; i++)
    1236             :     {
    1237           0 :         oEntry.c1 = palette[i * 3 + 2];  // Red
    1238           0 :         oEntry.c2 = palette[i * 3 + 1];  // Green
    1239           0 :         oEntry.c3 = palette[i * 3];      // Blue
    1240           0 :         oEntry.c4 = 255;
    1241             : 
    1242           0 :         poDS->poColorTable->SetColorEntry(i, &oEntry);
    1243             :     }
    1244             : 
    1245             :     /* -------------------------------------------------------------------- */
    1246             :     /*      Create band information objects.                                */
    1247             :     /* -------------------------------------------------------------------- */
    1248             : 
    1249           0 :     poDS->SetBand(1, new RIKRasterBand(poDS, 1));
    1250             : 
    1251             :     /* -------------------------------------------------------------------- */
    1252             :     /*      Initialize any PAM information.                                 */
    1253             :     /* -------------------------------------------------------------------- */
    1254             : 
    1255           0 :     poDS->SetDescription(poOpenInfo->pszFilename);
    1256           0 :     poDS->TryLoadXML();
    1257             : 
    1258             :     /* -------------------------------------------------------------------- */
    1259             :     /*      Check for external overviews.                                   */
    1260             :     /* -------------------------------------------------------------------- */
    1261           0 :     poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename,
    1262           0 :                                 poOpenInfo->GetSiblingFiles());
    1263             : 
    1264             :     /* -------------------------------------------------------------------- */
    1265             :     /*      Confirm the requested access is supported.                      */
    1266             :     /* -------------------------------------------------------------------- */
    1267           0 :     if (poOpenInfo->eAccess == GA_Update)
    1268             :     {
    1269           0 :         delete poDS;
    1270           0 :         ReportUpdateNotSupportedByDriver("RIK");
    1271           0 :         return nullptr;
    1272             :     }
    1273             : 
    1274           0 :     return poDS;
    1275             : }
    1276             : 
    1277             : /************************************************************************/
    1278             : /*                          GDALRegister_RIK()                          */
    1279             : /************************************************************************/
    1280             : 
    1281        2033 : void GDALRegister_RIK()
    1282             : 
    1283             : {
    1284        2033 :     if (GDALGetDriverByName("RIK") != nullptr)
    1285         283 :         return;
    1286             : 
    1287        1750 :     GDALDriver *poDriver = new GDALDriver();
    1288             : 
    1289        1750 :     poDriver->SetDescription("RIK");
    1290        1750 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
    1291        1750 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Swedish Grid RIK (.rik)");
    1292        1750 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/rik.html");
    1293        1750 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "rik");
    1294        1750 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
    1295             : 
    1296        1750 :     poDriver->pfnOpen = RIKDataset::Open;
    1297        1750 :     poDriver->pfnIdentify = RIKDataset::Identify;
    1298             : 
    1299        1750 :     GetGDALDriverManager()->RegisterDriver(poDriver);
    1300             : }

Generated by: LCOV version 1.14