LCOV - code coverage report
Current view: top level - frmts/rik - rikdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 71 445 16.0 %
Date: 2024-11-21 22:18:42 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             :     double adfTransform[6];
     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(double *padfTransform) 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 = reinterpret_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             :     GByte *blockData =
     299           0 :         reinterpret_cast<GByte *>(VSI_MALLOC_VERBOSE(nBlockSize));
     300           0 :     if (blockData == nullptr)
     301           0 :         return CE_Failure;
     302           0 :     if (VSIFReadL(blockData, 1, nBlockSize, poRDS->fp) != nBlockSize)
     303             :     {
     304           0 :         VSIFree(blockData);
     305           0 :         return CE_Failure;
     306             :     }
     307           0 :     memset(pImage, 0, pixels);
     308             : 
     309             :     /* -------------------------------------------------------------------- */
     310             :     /*      Read RLE block.                                                 */
     311             :     /* -------------------------------------------------------------------- */
     312           0 :     GUInt32 filePos = 0;
     313           0 :     GUInt32 imagePos = 0;
     314             : 
     315           0 :     if (poRDS->options == 0x01 || poRDS->options == 0x41)
     316             :     {
     317           0 :         while (filePos + 1 < nBlockSize && imagePos < pixels)
     318             :         {
     319           0 :             GByte count = blockData[filePos++];
     320           0 :             GByte color = blockData[filePos++];
     321             : 
     322           0 :             for (GByte i = 0; imagePos < pixels && i <= count; i++)
     323             :             {
     324           0 :                 reinterpret_cast<GByte *>(pImage)[imagePos++] = color;
     325             :             }
     326           0 :         }
     327             :     }
     328             : 
     329             :     /* -------------------------------------------------------------------- */
     330             :     /*      Read LZW block.                                                 */
     331             :     /* -------------------------------------------------------------------- */
     332             : 
     333           0 :     else if (poRDS->options == 0x0b)
     334             :     {
     335             :         try
     336             :         {
     337           0 :             if (nBlockSize < 5)
     338             :             {
     339           0 :                 throw "Not enough bytes";
     340             :             }
     341             : 
     342           0 :             const bool LZW_HAS_CLEAR_CODE = !!(blockData[4] & 0x80);
     343           0 :             const int LZW_MAX_BITS = blockData[4] & 0x1f;  // Max 13
     344           0 :             if (LZW_MAX_BITS > 13)
     345             :             {
     346           0 :                 throw "Invalid LZW_MAX_BITS";
     347             :             }
     348           0 :             const int LZW_BITS_PER_PIXEL = 8;
     349           0 :             const int LZW_OFFSET = 5;
     350             : 
     351           0 :             const int LZW_CLEAR = 1 << LZW_BITS_PER_PIXEL;
     352           0 :             const int LZW_CODES = 1 << LZW_MAX_BITS;
     353           0 :             const int LZW_NO_SUCH_CODE = LZW_CODES + 1;
     354             : 
     355           0 :             int lastAdded = LZW_HAS_CLEAR_CODE ? LZW_CLEAR : LZW_CLEAR - 1;
     356           0 :             int codeBits = LZW_BITS_PER_PIXEL + 1;
     357             : 
     358             :             int code;
     359             :             int lastCode;
     360             :             GByte lastOutput;
     361           0 :             int bitsTaken = 0;
     362             : 
     363             :             int prefix[8192];       // only need LZW_CODES for size.
     364             :             GByte character[8192];  // only need LZW_CODES for size.
     365             : 
     366           0 :             for (int i = 0; i < LZW_CLEAR; i++)
     367           0 :                 character[i] = static_cast<GByte>(i);
     368           0 :             for (int i = 0; i < LZW_CODES; i++)
     369           0 :                 prefix[i] = LZW_NO_SUCH_CODE;
     370             : 
     371           0 :             filePos = LZW_OFFSET;
     372           0 :             GUInt32 fileAlign = LZW_OFFSET;
     373           0 :             int imageLine = poRDS->nBlockYSize - 1;
     374             : 
     375           0 :             GUInt32 lineBreak = poRDS->nBlockXSize;
     376             : 
     377             :             // 32 bit alignment
     378           0 :             lineBreak += 3;
     379           0 :             lineBreak &= 0xfffffffc;
     380             : 
     381           0 :             code = GetNextLZWCode(codeBits, blockData, nBlockSize, filePos,
     382             :                                   fileAlign, bitsTaken);
     383           0 :             if (code < 0)
     384             :             {
     385           0 :                 throw "Not enough bytes";
     386             :             }
     387             : 
     388           0 :             OutputPixel(static_cast<GByte>(code), pImage, poRDS->nBlockXSize,
     389             :                         lineBreak, imageLine, imagePos);
     390           0 :             lastOutput = static_cast<GByte>(code);
     391             : 
     392           0 :             while (imageLine >= 0 &&
     393           0 :                    (imageLine || imagePos < poRDS->nBlockXSize) &&
     394           0 :                    filePos < nBlockSize)
     395             :             {
     396           0 :                 lastCode = code;
     397           0 :                 code = GetNextLZWCode(codeBits, blockData, nBlockSize, filePos,
     398             :                                       fileAlign, bitsTaken);
     399           0 :                 if (code < 0)
     400             :                 {
     401           0 :                     throw "Not enough bytes";
     402             :                 }
     403             : 
     404           0 :                 if (LZW_HAS_CLEAR_CODE && code == LZW_CLEAR)
     405             :                 {
     406             : #if RIK_CLEAR_DEBUG
     407             :                     CPLDebug("RIK",
     408             :                              "Clearing block %d\n"
     409             :                              " x=%d y=%d\n"
     410             :                              " pos=%d size=%d\n",
     411             :                              nBlockIndex, imagePos, imageLine, filePos,
     412             :                              nBlockSize);
     413             : #endif
     414             : 
     415             :                     // Clear prefix table
     416           0 :                     for (int i = LZW_CLEAR; i < LZW_CODES; i++)
     417           0 :                         prefix[i] = LZW_NO_SUCH_CODE;
     418           0 :                     lastAdded = LZW_CLEAR;
     419           0 :                     codeBits = LZW_BITS_PER_PIXEL + 1;
     420             : 
     421           0 :                     filePos = fileAlign;
     422           0 :                     bitsTaken = 0;
     423             : 
     424           0 :                     code = GetNextLZWCode(codeBits, blockData, nBlockSize,
     425             :                                           filePos, fileAlign, bitsTaken);
     426           0 :                     if (code < 0)
     427             :                     {
     428           0 :                         throw "Not enough bytes";
     429             :                     }
     430             : 
     431           0 :                     if (code > lastAdded)
     432             :                     {
     433           0 :                         throw "Clear Error";
     434             :                     }
     435             : 
     436           0 :                     OutputPixel((GByte)code, pImage, poRDS->nBlockXSize,
     437             :                                 lineBreak, imageLine, imagePos);
     438           0 :                     lastOutput = (GByte)code;
     439             :                 }
     440             :                 else
     441             :                 {
     442             :                     // Set-up decoding
     443             : 
     444             :                     GByte stack[8192];  // only need LZW_CODES for size.
     445             : 
     446           0 :                     int stackPtr = 0;
     447           0 :                     int decodeCode = code;
     448             : 
     449           0 :                     if (code == lastAdded + 1)
     450             :                     {
     451             :                         // Handle special case
     452           0 :                         *stack = lastOutput;
     453           0 :                         stackPtr = 1;
     454           0 :                         decodeCode = lastCode;
     455             :                     }
     456           0 :                     else if (code > lastAdded + 1)
     457             :                     {
     458           0 :                         throw "Too high code";
     459             :                     }
     460             : 
     461             :                     // Decode
     462             : 
     463           0 :                     int i = 0;
     464           0 :                     while (++i < LZW_CODES && decodeCode >= LZW_CLEAR &&
     465             :                            decodeCode < LZW_NO_SUCH_CODE)
     466             :                     {
     467           0 :                         stack[stackPtr++] = character[decodeCode];
     468           0 :                         decodeCode = prefix[decodeCode];
     469             :                     }
     470           0 :                     stack[stackPtr++] = static_cast<GByte>(decodeCode);
     471             : 
     472           0 :                     if (i == LZW_CODES || decodeCode >= LZW_NO_SUCH_CODE)
     473             :                     {
     474           0 :                         throw "Decode error";
     475             :                     }
     476             : 
     477             :                     // Output stack
     478             : 
     479           0 :                     lastOutput = stack[stackPtr - 1];
     480             : 
     481           0 :                     while (stackPtr != 0 && imagePos < pixels)
     482             :                     {
     483           0 :                         OutputPixel(stack[--stackPtr], pImage,
     484             :                                     poRDS->nBlockXSize, lineBreak, imageLine,
     485             :                                     imagePos);
     486             :                     }
     487             : 
     488             :                     // Add code to string table
     489             : 
     490           0 :                     if (lastCode != LZW_NO_SUCH_CODE &&
     491           0 :                         lastAdded != LZW_CODES - 1)
     492             :                     {
     493           0 :                         ++lastAdded;
     494           0 :                         if (lastAdded >= 8192)
     495             :                         {
     496           0 :                             throw "Decode error";
     497             :                         }
     498           0 :                         prefix[lastAdded] = lastCode;
     499           0 :                         character[lastAdded] = lastOutput;
     500             :                     }
     501             : 
     502             :                     // Check if we need to use more bits
     503             : 
     504           0 :                     if (lastAdded == (1 << codeBits) - 1 &&
     505             :                         codeBits != LZW_MAX_BITS)
     506             :                     {
     507           0 :                         codeBits++;
     508             : 
     509           0 :                         filePos = fileAlign;
     510           0 :                         bitsTaken = 0;
     511             :                     }
     512             :                 }
     513             :             }
     514             :         }
     515           0 :         catch (const char *errStr)
     516             :         {
     517             : #if RIK_ALLOW_BLOCK_ERRORS
     518           0 :             CPLDebug("RIK",
     519             :                      "LZW Decompress Failed: %s\n"
     520             :                      " blocks: %d\n"
     521             :                      " blockindex: %d\n"
     522             :                      " blockoffset: %X\n"
     523             :                      " blocksize: %d\n",
     524             :                      errStr, blocks, nBlockIndex, nBlockOffset, nBlockSize);
     525             : #else
     526             :             CPLFree(blockData);
     527             :             CPLError(CE_Failure, CPLE_AppDefined,
     528             :                      "RIK decompression failed: %s", errStr);
     529             :             return CE_Failure;
     530             : #endif
     531             :         }
     532             :     }
     533             : 
     534             :     /* -------------------------------------------------------------------- */
     535             :     /*      Read ZLIB block.                                                */
     536             :     /* -------------------------------------------------------------------- */
     537             : 
     538           0 :     else if (poRDS->options == 0x0d)
     539             :     {
     540           0 :         uLong destLen = pixels;
     541           0 :         Byte *upsideDown = static_cast<Byte *>(CPLMalloc(pixels));
     542             : 
     543           0 :         if (uncompress(upsideDown, &destLen, blockData, nBlockSize) != Z_OK)
     544             :         {
     545           0 :             CPLDebug("RIK", "Deflate compression failed on block %u",
     546             :                      nBlockIndex);
     547             :         }
     548             : 
     549           0 :         for (GUInt32 i = 0; i < poRDS->nBlockYSize; i++)
     550             :         {
     551           0 :             memcpy(reinterpret_cast<Byte *>(pImage) + poRDS->nBlockXSize * i,
     552           0 :                    upsideDown +
     553           0 :                        poRDS->nBlockXSize * (poRDS->nBlockYSize - i - 1),
     554           0 :                    poRDS->nBlockXSize);
     555             :         }
     556             : 
     557           0 :         CPLFree(upsideDown);
     558             :     }
     559             : 
     560           0 :     CPLFree(blockData);
     561             : 
     562           0 :     return CE_None;
     563             : }
     564             : 
     565             : /************************************************************************/
     566             : /*                       GetColorInterpretation()                       */
     567             : /************************************************************************/
     568             : 
     569           0 : GDALColorInterp RIKRasterBand::GetColorInterpretation()
     570             : 
     571             : {
     572           0 :     return GCI_PaletteIndex;
     573             : }
     574             : 
     575             : /************************************************************************/
     576             : /*                           GetColorTable()                            */
     577             : /************************************************************************/
     578             : 
     579           0 : GDALColorTable *RIKRasterBand::GetColorTable()
     580             : 
     581             : {
     582           0 :     RIKDataset *poRDS = reinterpret_cast<RIKDataset *>(poDS);
     583             : 
     584           0 :     return poRDS->poColorTable;
     585             : }
     586             : 
     587             : /************************************************************************/
     588             : /* ==================================================================== */
     589             : /*                              RIKDataset                              */
     590             : /* ==================================================================== */
     591             : /************************************************************************/
     592             : 
     593             : /************************************************************************/
     594             : /*                             RIKDataset()                             */
     595             : /************************************************************************/
     596             : 
     597           0 : RIKDataset::RIKDataset()
     598             :     : fp(nullptr), nBlockXSize(0), nBlockYSize(0), nHorBlocks(0),
     599             :       nVertBlocks(0), nFileSize(0), pOffsets(nullptr), options(0),
     600           0 :       poColorTable(nullptr)
     601             : 
     602             : {
     603           0 :     m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     604           0 :     m_oSRS.importFromWkt(
     605             :         "PROJCS[\"RT90 2.5 gon "
     606             :         "V\",GEOGCS[\"RT90\",DATUM[\"Rikets_koordinatsystem_1990\",SPHEROID["
     607             :         "\"Bessel "
     608             :         "1841\",6377397.155,299.1528128,AUTHORITY[\"EPSG\",\"7004\"]],TOWGS84["
     609             :         "414.1055246174,41.3265500042,603.0582474221,-0.8551163377,2."
     610             :         "1413174055,-7.0227298286,0],AUTHORITY[\"EPSG\",\"6124\"]],PRIMEM["
     611             :         "\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0."
     612             :         "0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\","
     613             :         "\"4124\"]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"latitude_"
     614             :         "of_origin\",0],PARAMETER[\"central_meridian\",15.80827777777778],"
     615             :         "PARAMETER[\"scale_factor\",1],PARAMETER[\"false_easting\",1500000],"
     616             :         "PARAMETER[\"false_northing\",0],UNIT[\"metre\",1,AUTHORITY[\"EPSG\","
     617             :         "\"9001\"]],AUTHORITY[\"EPSG\",\"3021\"]]");
     618           0 :     memset(adfTransform, 0, sizeof(adfTransform));
     619           0 : }
     620             : 
     621             : /************************************************************************/
     622             : /*                            ~RIKDataset()                             */
     623             : /************************************************************************/
     624             : 
     625           0 : RIKDataset::~RIKDataset()
     626             : 
     627             : {
     628           0 :     FlushCache(true);
     629           0 :     CPLFree(pOffsets);
     630           0 :     if (fp != nullptr)
     631           0 :         VSIFCloseL(fp);
     632           0 :     delete poColorTable;
     633           0 : }
     634             : 
     635             : /************************************************************************/
     636             : /*                          GetGeoTransform()                           */
     637             : /************************************************************************/
     638             : 
     639           0 : CPLErr RIKDataset::GetGeoTransform(double *padfTransform)
     640             : 
     641             : {
     642           0 :     memcpy(padfTransform, &adfTransform, sizeof(double) * 6);
     643             : 
     644           0 :     return CE_None;
     645             : }
     646             : 
     647             : /************************************************************************/
     648             : /*                          GetSpatialRef()                             */
     649             : /************************************************************************/
     650             : 
     651           0 : const OGRSpatialReference *RIKDataset::GetSpatialRef() const
     652             : 
     653             : {
     654           0 :     return &m_oSRS;
     655             : }
     656             : 
     657             : /************************************************************************/
     658             : /*                             GetRikString()                           */
     659             : /************************************************************************/
     660             : 
     661         739 : static GUInt16 GetRikString(VSILFILE *fp, char *str, GUInt16 strLength)
     662             : 
     663             : {
     664             :     GUInt16 actLength;
     665             : 
     666         739 :     VSIFReadL(&actLength, 1, sizeof(actLength), fp);
     667             : #ifdef CPL_MSB
     668             :     CPL_SWAP16PTR(&actLength);
     669             : #endif
     670             : 
     671         739 :     if (actLength + 2 > strLength)
     672             :     {
     673           0 :         return actLength;
     674             :     }
     675             : 
     676         739 :     VSIFReadL(str, 1, actLength, fp);
     677             : 
     678         739 :     str[actLength] = '\0';
     679             : 
     680         739 :     return actLength;
     681             : }
     682             : 
     683             : /************************************************************************/
     684             : /*                          Identify()                                  */
     685             : /************************************************************************/
     686             : 
     687       51999 : int RIKDataset::Identify(GDALOpenInfo *poOpenInfo)
     688             : 
     689             : {
     690       51999 :     if (poOpenInfo->fpL == nullptr || poOpenInfo->nHeaderBytes < 50)
     691       48081 :         return FALSE;
     692             : 
     693        3918 :     if (STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader, "RIK3"))
     694             :     {
     695           0 :         return TRUE;
     696             :     }
     697             :     else
     698             :     {
     699             :         GUInt16 actLength;
     700        3918 :         memcpy(&actLength, poOpenInfo->pabyHeader, 2);
     701             : #ifdef CPL_MSB
     702             :         CPL_SWAP16PTR(&actLength);
     703             : #endif
     704        3918 :         if (actLength + 2 > 1024)
     705             :         {
     706        2335 :             return FALSE;
     707             :         }
     708        1583 :         if (actLength == 0)
     709        1512 :             return -1;
     710             : 
     711        2560 :         for (int i = 0; i < actLength; i++)
     712             :         {
     713        2554 :             if (poOpenInfo->pabyHeader[2 + i] == 0)
     714          65 :                 return FALSE;
     715             :         }
     716             : 
     717           6 :         if (EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "rik"))
     718           0 :             return TRUE;
     719             : 
     720             :         // We really need Open to be able to conclude
     721           6 :         return -1;
     722             :     }
     723             : }
     724             : 
     725             : /************************************************************************/
     726             : /*                                Open()                                */
     727             : /************************************************************************/
     728             : 
     729         739 : GDALDataset *RIKDataset::Open(GDALOpenInfo *poOpenInfo)
     730             : 
     731             : {
     732         739 :     if (Identify(poOpenInfo) == FALSE)
     733           0 :         return nullptr;
     734             : 
     735         739 :     bool rik3header = false;
     736             : 
     737         739 :     if (STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader, "RIK3"))
     738             :     {
     739           0 :         rik3header = true;
     740           0 :         VSIFSeekL(poOpenInfo->fpL, 4, SEEK_SET);
     741             :     }
     742             :     else
     743         739 :         VSIFSeekL(poOpenInfo->fpL, 0, SEEK_SET);
     744             : 
     745             :     /* -------------------------------------------------------------------- */
     746             :     /*      Read the map name.                                              */
     747             :     /* -------------------------------------------------------------------- */
     748             : 
     749             :     char name[1024];
     750             : 
     751         739 :     GUInt16 nameLength = GetRikString(poOpenInfo->fpL, name, sizeof(name));
     752             : 
     753         739 :     if (nameLength > sizeof(name) - 1)
     754             :     {
     755           0 :         return nullptr;
     756             :     }
     757             : 
     758         739 :     if (!rik3header)
     759             :     {
     760         739 :         if (nameLength == 0 || nameLength != strlen(name))
     761         736 :             return nullptr;
     762             :     }
     763             : 
     764             :     /* -------------------------------------------------------------------- */
     765             :     /*      Read the header.                                                */
     766             :     /* -------------------------------------------------------------------- */
     767             : 
     768             :     RIKHeader header;
     769             :     double metersPerPixel;
     770             : 
     771           3 :     const char *headerType = "RIK3";
     772             : 
     773           3 :     if (rik3header)
     774             :     {
     775             :         /* --------------------------------------------------------------------
     776             :          */
     777             :         /*      RIK3 header. */
     778             :         /* --------------------------------------------------------------------
     779             :          */
     780             : 
     781             :         // Read projection name
     782             : 
     783             :         char projection[1024];
     784             : 
     785             :         GUInt16 projLength =
     786           0 :             GetRikString(poOpenInfo->fpL, projection, sizeof(projection));
     787             : 
     788           0 :         if (projLength > sizeof(projection) - 1)
     789             :         {
     790             :             // Unreasonable string length, assume wrong format
     791           0 :             return nullptr;
     792             :         }
     793             : 
     794             :         // Read unknown string
     795             : 
     796           0 :         /*projLength =*/GetRikString(poOpenInfo->fpL, projection,
     797             :                                      sizeof(projection));
     798             : 
     799             :         // Read map north edge
     800             : 
     801             :         char tmpStr[16];
     802             : 
     803             :         GUInt16 tmpLength =
     804           0 :             GetRikString(poOpenInfo->fpL, tmpStr, sizeof(tmpStr));
     805             : 
     806           0 :         if (tmpLength > sizeof(tmpStr) - 1)
     807             :         {
     808             :             // Unreasonable string length, assume wrong format
     809           0 :             return nullptr;
     810             :         }
     811             : 
     812           0 :         header.fNorth = CPLAtof(tmpStr);
     813             : 
     814             :         // Read map west edge
     815             : 
     816           0 :         tmpLength = GetRikString(poOpenInfo->fpL, tmpStr, sizeof(tmpStr));
     817             : 
     818           0 :         if (tmpLength > sizeof(tmpStr) - 1)
     819             :         {
     820             :             // Unreasonable string length, assume wrong format
     821           0 :             return nullptr;
     822             :         }
     823             : 
     824           0 :         header.fWest = CPLAtof(tmpStr);
     825             : 
     826             :         // Read binary values
     827             : 
     828           0 :         VSIFReadL(&header.iScale, 1, sizeof(header.iScale), poOpenInfo->fpL);
     829           0 :         VSIFReadL(&header.iMPPNum, 1, sizeof(header.iMPPNum), poOpenInfo->fpL);
     830           0 :         VSIFReadL(&header.iBlockWidth, 1, sizeof(header.iBlockWidth),
     831             :                   poOpenInfo->fpL);
     832           0 :         VSIFReadL(&header.iBlockHeight, 1, sizeof(header.iBlockHeight),
     833             :                   poOpenInfo->fpL);
     834           0 :         VSIFReadL(&header.iHorBlocks, 1, sizeof(header.iHorBlocks),
     835             :                   poOpenInfo->fpL);
     836           0 :         VSIFReadL(&header.iVertBlocks, 1, sizeof(header.iVertBlocks),
     837             :                   poOpenInfo->fpL);
     838             : #ifdef CPL_MSB
     839             :         CPL_SWAP32PTR(&header.iScale);
     840             :         CPL_SWAP32PTR(&header.iMPPNum);
     841             :         CPL_SWAP32PTR(&header.iBlockWidth);
     842             :         CPL_SWAP32PTR(&header.iBlockHeight);
     843             :         CPL_SWAP32PTR(&header.iHorBlocks);
     844             :         CPL_SWAP32PTR(&header.iVertBlocks);
     845             : #endif
     846           0 :         if (header.iMPPNum == 0)
     847           0 :             return nullptr;
     848             : 
     849           0 :         VSIFReadL(&header.iBitsPerPixel, 1, sizeof(header.iBitsPerPixel),
     850             :                   poOpenInfo->fpL);
     851           0 :         VSIFReadL(&header.iOptions, 1, sizeof(header.iOptions),
     852             :                   poOpenInfo->fpL);
     853           0 :         header.iUnknown = header.iOptions;
     854           0 :         VSIFReadL(&header.iOptions, 1, sizeof(header.iOptions),
     855             :                   poOpenInfo->fpL);
     856             : 
     857           0 :         header.fSouth =
     858           0 :             header.fNorth - static_cast<double>(header.iVertBlocks) *
     859           0 :                                 header.iBlockHeight * header.iMPPNum;
     860           0 :         header.fEast = header.fWest + static_cast<double>(header.iHorBlocks) *
     861           0 :                                           header.iBlockWidth * header.iMPPNum;
     862             : 
     863           0 :         metersPerPixel = header.iMPPNum;
     864             :     }
     865             :     else
     866             :     {
     867             :         /* --------------------------------------------------------------------
     868             :          */
     869             :         /*      Old RIK header. */
     870             :         /* --------------------------------------------------------------------
     871             :          */
     872             : 
     873           3 :         VSIFReadL(&header.iUnknown, 1, sizeof(header.iUnknown),
     874             :                   poOpenInfo->fpL);
     875           3 :         VSIFReadL(&header.fSouth, 1, sizeof(header.fSouth), poOpenInfo->fpL);
     876           3 :         VSIFReadL(&header.fWest, 1, sizeof(header.fWest), poOpenInfo->fpL);
     877           3 :         VSIFReadL(&header.fNorth, 1, sizeof(header.fNorth), poOpenInfo->fpL);
     878           3 :         VSIFReadL(&header.fEast, 1, sizeof(header.fEast), poOpenInfo->fpL);
     879           3 :         VSIFReadL(&header.iScale, 1, sizeof(header.iScale), poOpenInfo->fpL);
     880           3 :         VSIFReadL(&header.iMPPNum, 1, sizeof(header.iMPPNum), poOpenInfo->fpL);
     881             : #ifdef CPL_MSB
     882             :         CPL_SWAP64PTR(&header.fSouth);
     883             :         CPL_SWAP64PTR(&header.fWest);
     884             :         CPL_SWAP64PTR(&header.fNorth);
     885             :         CPL_SWAP64PTR(&header.fEast);
     886             :         CPL_SWAP32PTR(&header.iScale);
     887             :         CPL_SWAP32PTR(&header.iMPPNum);
     888             : #endif
     889             : 
     890           6 :         if (!std::isfinite(header.fSouth) || !std::isfinite(header.fWest) ||
     891           9 :             !std::isfinite(header.fNorth) || !std::isfinite(header.fEast) ||
     892           3 :             header.iMPPNum == 0)
     893             :         {
     894           0 :             return nullptr;
     895             :         }
     896             : 
     897           3 :         const bool offsetBounds = header.fSouth < 4000000;
     898             : 
     899           3 :         header.iMPPDen = 1;
     900             : 
     901           3 :         if (offsetBounds)
     902             :         {
     903           3 :             header.fSouth += 4002995;
     904           3 :             header.fNorth += 5004000;
     905           3 :             header.fWest += 201000;
     906           3 :             header.fEast += 302005;
     907             : 
     908           3 :             VSIFReadL(&header.iMPPDen, 1, sizeof(header.iMPPDen),
     909             :                       poOpenInfo->fpL);
     910             : #ifdef CPL_MSB
     911             :             CPL_SWAP32PTR(&header.iMPPDen);
     912             : #endif
     913           3 :             if (header.iMPPDen == 0)
     914           0 :                 return nullptr;
     915             : 
     916           3 :             headerType = "RIK1";
     917             :         }
     918             :         else
     919             :         {
     920           0 :             headerType = "RIK2";
     921             :         }
     922             : 
     923           3 :         metersPerPixel = header.iMPPNum / static_cast<double>(header.iMPPDen);
     924             : 
     925           3 :         VSIFReadL(&header.iBlockWidth, 1, sizeof(header.iBlockWidth),
     926             :                   poOpenInfo->fpL);
     927           3 :         VSIFReadL(&header.iBlockHeight, 1, sizeof(header.iBlockHeight),
     928             :                   poOpenInfo->fpL);
     929           3 :         VSIFReadL(&header.iHorBlocks, 1, sizeof(header.iHorBlocks),
     930             :                   poOpenInfo->fpL);
     931             : #ifdef CPL_MSB
     932             :         CPL_SWAP32PTR(&header.iBlockWidth);
     933             :         CPL_SWAP32PTR(&header.iBlockHeight);
     934             :         CPL_SWAP32PTR(&header.iHorBlocks);
     935             : #endif
     936             : 
     937           3 :         if ((header.iBlockWidth > 2000) || (header.iBlockWidth < 10) ||
     938           0 :             (header.iBlockHeight > 2000) || (header.iBlockHeight < 10))
     939           3 :             return nullptr;
     940             : 
     941           0 :         if (!offsetBounds)
     942             :         {
     943           0 :             VSIFReadL(&header.iVertBlocks, 1, sizeof(header.iVertBlocks),
     944             :                       poOpenInfo->fpL);
     945             : #ifdef CPL_MSB
     946             :             CPL_SWAP32PTR(&header.iVertBlocks);
     947             : #endif
     948             :         }
     949             : 
     950           0 :         if (offsetBounds || !header.iVertBlocks)
     951             :         {
     952           0 :             double dfVertBlocks = ceil((header.fNorth - header.fSouth) /
     953           0 :                                        (header.iBlockHeight * metersPerPixel));
     954           0 :             if (dfVertBlocks < 1 || dfVertBlocks > INT_MAX)
     955           0 :                 return nullptr;
     956           0 :             header.iVertBlocks = static_cast<GUInt32>(dfVertBlocks);
     957             :         }
     958             : 
     959             : #if RIK_HEADER_DEBUG
     960             :         CPLDebug("RIK", "Original vertical blocks %d\n", header.iVertBlocks);
     961             : #endif
     962             : 
     963           0 :         VSIFReadL(&header.iBitsPerPixel, 1, sizeof(header.iBitsPerPixel),
     964             :                   poOpenInfo->fpL);
     965             : 
     966           0 :         if (header.iBitsPerPixel != 8)
     967             :         {
     968           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
     969             :                      "File %s has unsupported number of bits per pixel.\n",
     970             :                      poOpenInfo->pszFilename);
     971           0 :             return nullptr;
     972             :         }
     973             : 
     974           0 :         VSIFReadL(&header.iOptions, 1, sizeof(header.iOptions),
     975             :                   poOpenInfo->fpL);
     976             : 
     977           0 :         if (header.iOptions != 0x00 &&  // Uncompressed
     978           0 :             header.iOptions != 0x40 &&  // Uncompressed
     979           0 :             header.iOptions != 0x01 &&  // RLE
     980           0 :             header.iOptions != 0x41 &&  // RLE
     981           0 :             header.iOptions != 0x0B &&  // LZW
     982           0 :             header.iOptions != 0x0D)    // ZLIB
     983             :         {
     984           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
     985             :                      "File %s. Unknown map options.\n",
     986             :                      poOpenInfo->pszFilename);
     987           0 :             return nullptr;
     988             :         }
     989             :     }
     990             : 
     991           0 :     if (header.iBlockWidth == 0 || header.iHorBlocks == 0 ||
     992           0 :         header.iBlockWidth >= INT_MAX / header.iHorBlocks ||
     993           0 :         header.iBlockHeight == 0 || header.iVertBlocks == 0 ||
     994           0 :         header.iBlockHeight >= INT_MAX / header.iVertBlocks ||
     995           0 :         header.iBlockHeight >= INT_MAX / header.iBlockWidth ||
     996           0 :         header.iVertBlocks >= INT_MAX / (int)sizeof(GUInt32) ||
     997           0 :         header.iHorBlocks >=
     998           0 :             INT_MAX / (header.iVertBlocks * (int)sizeof(GUInt32)))
     999             :     {
    1000           0 :         return nullptr;
    1001             :     }
    1002             : 
    1003             :     /* -------------------------------------------------------------------- */
    1004             :     /*      Read the palette.                                               */
    1005             :     /* -------------------------------------------------------------------- */
    1006             : 
    1007             :     GByte palette[768];
    1008             : 
    1009           0 :     for (GUInt16 i = 0; i < 256; i++)
    1010             :     {
    1011           0 :         VSIFReadL(&palette[i * 3 + 2], 1, 1, poOpenInfo->fpL);
    1012           0 :         VSIFReadL(&palette[i * 3 + 1], 1, 1, poOpenInfo->fpL);
    1013           0 :         VSIFReadL(&palette[i * 3 + 0], 1, 1, poOpenInfo->fpL);
    1014             :     }
    1015             : 
    1016             :     /* -------------------------------------------------------------------- */
    1017             :     /*      Find block offsets.                                             */
    1018             :     /* -------------------------------------------------------------------- */
    1019             : 
    1020           0 :     GUInt32 blocks = header.iHorBlocks * header.iVertBlocks;
    1021             :     GUInt32 *offsets =
    1022           0 :         reinterpret_cast<GUInt32 *>(VSIMalloc(blocks * sizeof(GUInt32)));
    1023             : 
    1024           0 :     if (!offsets)
    1025             :     {
    1026           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
    1027             :                  "File %s. Unable to allocate offset table.\n",
    1028             :                  poOpenInfo->pszFilename);
    1029           0 :         return nullptr;
    1030             :     }
    1031             : 
    1032           0 :     if (header.iOptions == 0x00)
    1033             :     {
    1034           0 :         offsets[0] = static_cast<GUInt32>(VSIFTellL(poOpenInfo->fpL));
    1035             : 
    1036           0 :         if (VSIFEofL(poOpenInfo->fpL))
    1037             :         {
    1038           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
    1039             :                      "File %s. Read past end of file.\n",
    1040             :                      poOpenInfo->pszFilename);
    1041           0 :             CPLFree(offsets);
    1042           0 :             return nullptr;
    1043             :         }
    1044             : 
    1045           0 :         VSIFSeekL(poOpenInfo->fpL, 0, SEEK_END);
    1046           0 :         vsi_l_offset nBigFileSize = VSIFTellL(poOpenInfo->fpL);
    1047           0 :         if (nBigFileSize > UINT_MAX)
    1048           0 :             nBigFileSize = UINT_MAX;
    1049           0 :         GUInt32 fileSize = static_cast<GUInt32>(nBigFileSize);
    1050             : 
    1051           0 :         GUInt32 nBlocksFromFileSize =
    1052           0 :             (fileSize - offsets[0]) /
    1053           0 :             (header.iBlockWidth * header.iBlockHeight);
    1054           0 :         if (nBlocksFromFileSize < blocks)
    1055             :         {
    1056           0 :             blocks = nBlocksFromFileSize;
    1057           0 :             header.iVertBlocks = blocks / header.iHorBlocks;
    1058             :         }
    1059             : 
    1060           0 :         if (header.iVertBlocks == 0)
    1061             :         {
    1062           0 :             CPLError(CE_Failure, CPLE_OpenFailed, "File %s too short.\n",
    1063             :                      poOpenInfo->pszFilename);
    1064           0 :             CPLFree(offsets);
    1065           0 :             return nullptr;
    1066             :         }
    1067             : 
    1068           0 :         for (GUInt32 i = 1; i < blocks; i++)
    1069             :         {
    1070           0 :             offsets[i] =
    1071           0 :                 offsets[i - 1] + header.iBlockWidth * header.iBlockHeight;
    1072             :         }
    1073             :     }
    1074             :     else
    1075             :     {
    1076           0 :         for (GUInt32 i = 0; i < blocks; i++)
    1077             :         {
    1078           0 :             if (VSIFReadL(&offsets[i], sizeof(offsets[i]), 1,
    1079           0 :                           poOpenInfo->fpL) != 1)
    1080           0 :                 break;
    1081             : #ifdef CPL_MSB
    1082             :             CPL_SWAP32PTR(&offsets[i]);
    1083             : #endif
    1084           0 :             if (rik3header)
    1085             :             {
    1086             :                 GUInt32 blockSize;
    1087           0 :                 if (VSIFReadL(&blockSize, sizeof(blockSize), 1,
    1088           0 :                               poOpenInfo->fpL) != 1)
    1089           0 :                     break;
    1090             : #ifdef CPL_MSB
    1091             :                 CPL_SWAP32PTR(&blockSize);
    1092             : #endif
    1093             :             }
    1094             :         }
    1095             :     }
    1096             : 
    1097             :     /* -------------------------------------------------------------------- */
    1098             :     /*      Final checks.                                                   */
    1099             :     /* -------------------------------------------------------------------- */
    1100             : 
    1101             :     // File size
    1102             : 
    1103           0 :     if (VSIFEofL(poOpenInfo->fpL))
    1104             :     {
    1105           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
    1106             :                  "File %s. Read past end of file.\n", poOpenInfo->pszFilename);
    1107           0 :         CPLFree(offsets);
    1108           0 :         return nullptr;
    1109             :     }
    1110             : 
    1111           0 :     VSIFSeekL(poOpenInfo->fpL, 0, SEEK_END);
    1112           0 :     GUInt32 fileSize = static_cast<GUInt32>(VSIFTellL(poOpenInfo->fpL));
    1113             : 
    1114             : #if RIK_HEADER_DEBUG
    1115             :     CPLDebug("RIK", "File size %d\n", fileSize);
    1116             : #endif
    1117             : 
    1118             :     // Make sure the offset table is valid
    1119             : 
    1120           0 :     GUInt32 lastoffset = 0;
    1121             : 
    1122           0 :     for (GUInt32 y = 0; y < header.iVertBlocks; y++)
    1123             :     {
    1124           0 :         for (GUInt32 x = 0; x < header.iHorBlocks; x++)
    1125             :         {
    1126           0 :             if (!offsets[x + y * header.iHorBlocks])
    1127             :             {
    1128           0 :                 continue;
    1129             :             }
    1130             : 
    1131           0 :             if (offsets[x + y * header.iHorBlocks] >= fileSize)
    1132             :             {
    1133           0 :                 if (!y)
    1134             :                 {
    1135           0 :                     CPLError(CE_Failure, CPLE_OpenFailed,
    1136             :                              "File %s too short.\n", poOpenInfo->pszFilename);
    1137           0 :                     CPLFree(offsets);
    1138           0 :                     return nullptr;
    1139             :                 }
    1140           0 :                 header.iVertBlocks = y;
    1141           0 :                 break;
    1142             :             }
    1143             : 
    1144           0 :             if (offsets[x + y * header.iHorBlocks] < lastoffset)
    1145             :             {
    1146           0 :                 if (!y)
    1147             :                 {
    1148           0 :                     CPLError(CE_Failure, CPLE_OpenFailed,
    1149             :                              "File %s. Corrupt offset table.\n",
    1150             :                              poOpenInfo->pszFilename);
    1151           0 :                     CPLFree(offsets);
    1152           0 :                     return nullptr;
    1153             :                 }
    1154           0 :                 header.iVertBlocks = y;
    1155           0 :                 break;
    1156             :             }
    1157             : 
    1158           0 :             lastoffset = offsets[x + y * header.iHorBlocks];
    1159             :         }
    1160             :     }
    1161             : 
    1162             : #if RIK_HEADER_DEBUG
    1163             :     CPLDebug("RIK",
    1164             :              "first offset %d\n"
    1165             :              "last offset %d\n",
    1166             :              offsets[0], lastoffset);
    1167             : #endif
    1168             : 
    1169           0 :     const char *compression = "RLE";
    1170             : 
    1171           0 :     if (header.iOptions == 0x00 || header.iOptions == 0x40)
    1172           0 :         compression = "Uncompressed";
    1173           0 :     if (header.iOptions == 0x0b)
    1174           0 :         compression = "LZW";
    1175           0 :     if (header.iOptions == 0x0d)
    1176           0 :         compression = "ZLIB";
    1177             : 
    1178           0 :     CPLDebug("RIK",
    1179             :              "RIK file parameters:\n"
    1180             :              " name: %s\n"
    1181             :              " header: %s\n"
    1182             :              " unknown: 0x%X\n"
    1183             :              " south: %f\n"
    1184             :              " west: %f\n"
    1185             :              " north: %f\n"
    1186             :              " east: %f\n"
    1187             :              " original scale: %d\n"
    1188             :              " meters per pixel: %f\n"
    1189             :              " block width: %d\n"
    1190             :              " block height: %d\n"
    1191             :              " horizontal blocks: %d\n"
    1192             :              " vertical blocks: %d\n"
    1193             :              " bits per pixel: %d\n"
    1194             :              " options: 0x%X\n"
    1195             :              " compression: %s\n",
    1196           0 :              name, headerType, header.iUnknown, header.fSouth, header.fWest,
    1197             :              header.fNorth, header.fEast, header.iScale, metersPerPixel,
    1198             :              header.iBlockWidth, header.iBlockHeight, header.iHorBlocks,
    1199           0 :              header.iVertBlocks, header.iBitsPerPixel, header.iOptions,
    1200             :              compression);
    1201             : 
    1202             :     /* -------------------------------------------------------------------- */
    1203             :     /*      Create a corresponding GDALDataset.                             */
    1204             :     /* -------------------------------------------------------------------- */
    1205             : 
    1206           0 :     RIKDataset *poDS = new RIKDataset();
    1207             : 
    1208           0 :     poDS->fp = poOpenInfo->fpL;
    1209           0 :     poOpenInfo->fpL = nullptr;
    1210             : 
    1211           0 :     poDS->adfTransform[0] = header.fWest - metersPerPixel / 2.0;
    1212           0 :     poDS->adfTransform[1] = metersPerPixel;
    1213           0 :     poDS->adfTransform[2] = 0.0;
    1214           0 :     poDS->adfTransform[3] = header.fNorth + metersPerPixel / 2.0;
    1215           0 :     poDS->adfTransform[4] = 0.0;
    1216           0 :     poDS->adfTransform[5] = -metersPerPixel;
    1217             : 
    1218           0 :     poDS->nBlockXSize = header.iBlockWidth;
    1219           0 :     poDS->nBlockYSize = header.iBlockHeight;
    1220           0 :     poDS->nHorBlocks = header.iHorBlocks;
    1221           0 :     poDS->nVertBlocks = header.iVertBlocks;
    1222           0 :     poDS->pOffsets = offsets;
    1223           0 :     poDS->options = header.iOptions;
    1224           0 :     poDS->nFileSize = fileSize;
    1225             : 
    1226           0 :     poDS->nRasterXSize = header.iBlockWidth * header.iHorBlocks;
    1227           0 :     poDS->nRasterYSize = header.iBlockHeight * header.iVertBlocks;
    1228             : 
    1229           0 :     poDS->nBands = 1;
    1230             : 
    1231             :     GDALColorEntry oEntry;
    1232           0 :     poDS->poColorTable = new GDALColorTable();
    1233           0 :     for (GUInt16 i = 0; i < 256; i++)
    1234             :     {
    1235           0 :         oEntry.c1 = palette[i * 3 + 2];  // Red
    1236           0 :         oEntry.c2 = palette[i * 3 + 1];  // Green
    1237           0 :         oEntry.c3 = palette[i * 3];      // Blue
    1238           0 :         oEntry.c4 = 255;
    1239             : 
    1240           0 :         poDS->poColorTable->SetColorEntry(i, &oEntry);
    1241             :     }
    1242             : 
    1243             :     /* -------------------------------------------------------------------- */
    1244             :     /*      Create band information objects.                                */
    1245             :     /* -------------------------------------------------------------------- */
    1246             : 
    1247           0 :     poDS->SetBand(1, new RIKRasterBand(poDS, 1));
    1248             : 
    1249             :     /* -------------------------------------------------------------------- */
    1250             :     /*      Initialize any PAM information.                                 */
    1251             :     /* -------------------------------------------------------------------- */
    1252             : 
    1253           0 :     poDS->SetDescription(poOpenInfo->pszFilename);
    1254           0 :     poDS->TryLoadXML();
    1255             : 
    1256             :     /* -------------------------------------------------------------------- */
    1257             :     /*      Check for external overviews.                                   */
    1258             :     /* -------------------------------------------------------------------- */
    1259           0 :     poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename,
    1260           0 :                                 poOpenInfo->GetSiblingFiles());
    1261             : 
    1262             :     /* -------------------------------------------------------------------- */
    1263             :     /*      Confirm the requested access is supported.                      */
    1264             :     /* -------------------------------------------------------------------- */
    1265           0 :     if (poOpenInfo->eAccess == GA_Update)
    1266             :     {
    1267           0 :         delete poDS;
    1268           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    1269             :                  "The RIK driver does not support update access to existing"
    1270             :                  " datasets.\n");
    1271           0 :         return nullptr;
    1272             :     }
    1273             : 
    1274           0 :     return poDS;
    1275             : }
    1276             : 
    1277             : /************************************************************************/
    1278             : /*                          GDALRegister_RIK()                          */
    1279             : /************************************************************************/
    1280             : 
    1281        1595 : void GDALRegister_RIK()
    1282             : 
    1283             : {
    1284        1595 :     if (GDALGetDriverByName("RIK") != nullptr)
    1285         302 :         return;
    1286             : 
    1287        1293 :     GDALDriver *poDriver = new GDALDriver();
    1288             : 
    1289        1293 :     poDriver->SetDescription("RIK");
    1290        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
    1291        1293 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Swedish Grid RIK (.rik)");
    1292        1293 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/rik.html");
    1293        1293 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "rik");
    1294        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
    1295             : 
    1296        1293 :     poDriver->pfnOpen = RIKDataset::Open;
    1297        1293 :     poDriver->pfnIdentify = RIKDataset::Identify;
    1298             : 
    1299        1293 :     GetGDALDriverManager()->RegisterDriver(poDriver);
    1300             : }

Generated by: LCOV version 1.14