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

Generated by: LCOV version 1.14