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

Generated by: LCOV version 1.14