• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OSGeo / gdal / 15885686134

25 Jun 2025 07:44PM UTC coverage: 71.084%. Remained the same
15885686134

push

github

rouault
gdal_priv.h: fix C++11 compatibility

573814 of 807237 relevant lines covered (71.08%)

250621.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

15.99
/frmts/rik/rikdataset.cpp
1
/******************************************************************************
2
 *
3
 * Project:  RIK Reader
4
 * Purpose:  All code for RIK Reader
5
 * Author:   Daniel Wallner, daniel.wallner@bredband.net
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2005, Daniel Wallner <daniel.wallner@bredband.net>
9
 * Copyright (c) 2008-2011, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13

14
#include <cfloat>
15
#include <zlib.h>
16
#include "gdal_frmts.h"
17
#include "gdal_pam.h"
18

19
#include <cmath>
20

21
#define RIK_HEADER_DEBUG 0
22
#define RIK_CLEAR_DEBUG 0
23
#define RIK_PIXEL_DEBUG 0
24

25
// #define RIK_SINGLE_BLOCK 0
26

27
#define RIK_ALLOW_BLOCK_ERRORS 1
28

29
//
30
// The RIK file format information was extracted from the trikpanel project:
31
// http://sourceforge.net/projects/trikpanel/
32
//
33
// A RIK file consists of the following elements:
34
//
35
// +--------------------+
36
// | Magic "RIK3"       | (Only in RIK version 3)
37
// +--------------------+
38
// | Map name           | (The first two bytes is the string length)
39
// +--------------------+
40
// | Header             | (Three different formats exists)
41
// +--------------------+
42
// | Color palette      |
43
// +--------------------+
44
// | Block offset array | (Only in compressed formats)
45
// +--------------------+
46
// | Image blocks       |
47
// +--------------------+
48
//
49
// All numbers are stored in little endian.
50
//
51
// There are four different image block formats:
52
//
53
// 1. Uncompressed image block
54
//
55
//   A stream of palette indexes.
56
//
57
// 2. RLE image block
58
//
59
//   The RLE image block is a stream of byte pairs:
60
//   |  Run length - 1 (byte)  |  Pixel value (byte)  |  Run length - 1 ...
61
//
62
// 3. LZW image block
63
//
64
//   The LZW image block uses the same LZW encoding as a GIF file
65
//   except that there is no EOF code and maximum code length is 13 bits.
66
//   These blocks are upside down compared to GDAL.
67
//
68
// 4. ZLIB image block
69
//
70
//   These blocks are upside down compared to GDAL.
71
//
72

73
typedef struct
74
{
75
    GUInt16 iUnknown;
76
    double fSouth;  // Map bounds
77
    double fWest;
78
    double fNorth;
79
    double fEast;
80
    GUInt32 iScale;   // Source map scale
81
    float iMPPNum;    // Meters per pixel numerator
82
    GUInt32 iMPPDen;  // Meters per pixel denominator
83
                      // Only used if fSouth < 4000000
84
    GUInt32 iBlockWidth;
85
    GUInt32 iBlockHeight;
86
    GUInt32 iHorBlocks;   // Number of horizontal blocks
87
    GUInt32 iVertBlocks;  // Number of vertical blocks
88
                          // Only used if fSouth >= 4000000
89
    GByte iBitsPerPixel;
90
    GByte iOptions;
91
} RIKHeader;
92

93
/************************************************************************/
94
/* ==================================================================== */
95
/*                              RIKDataset                              */
96
/* ==================================================================== */
97
/************************************************************************/
98

99
class RIKRasterBand;
100

101
class RIKDataset final : public GDALPamDataset
102
{
103
    friend class RIKRasterBand;
104

105
    VSILFILE *fp;
106

107
    OGRSpatialReference m_oSRS{};
108
    GDALGeoTransform m_gt{};
109

110
    GUInt32 nBlockXSize;
111
    GUInt32 nBlockYSize;
112
    GUInt32 nHorBlocks;
113
    GUInt32 nVertBlocks;
114
    GUInt32 nFileSize;
115
    GUInt32 *pOffsets;
116
    GByte options;
117

118
    GDALColorTable *poColorTable;
119

120
  public:
121
    RIKDataset();
122
    ~RIKDataset();
123

124
    static GDALDataset *Open(GDALOpenInfo *);
125
    static int Identify(GDALOpenInfo *);
126

127
    CPLErr GetGeoTransform(GDALGeoTransform &gt) const override;
128
    const OGRSpatialReference *GetSpatialRef() const override;
129
};
130

131
/************************************************************************/
132
/* ==================================================================== */
133
/*                            RIKRasterBand                             */
134
/* ==================================================================== */
135
/************************************************************************/
136

137
class RIKRasterBand final : public GDALPamRasterBand
138
{
139
    friend class RIKDataset;
140

141
  public:
142
    RIKRasterBand(RIKDataset *, int);
143

144
    virtual CPLErr IReadBlock(int, int, void *) override;
145
    virtual GDALColorInterp GetColorInterpretation() override;
146
    virtual GDALColorTable *GetColorTable() override;
147
};
148

149
/************************************************************************/
150
/*                           RIKRasterBand()                            */
151
/************************************************************************/
152

153
RIKRasterBand::RIKRasterBand(RIKDataset *poDSIn, int nBandIn)
×
154

155
{
156
    poDS = poDSIn;
×
157
    nBand = nBandIn;
×
158

159
    eDataType = GDT_Byte;
×
160

161
    nBlockXSize = poDSIn->nBlockXSize;
×
162
    nBlockYSize = poDSIn->nBlockYSize;
×
163
}
×
164

165
/************************************************************************/
166
/*                             GetNextLZWCode()                         */
167
/************************************************************************/
168

169
static int GetNextLZWCode(int codeBits, const GByte *blockData,
×
170
                          const GUInt32 blockSize, GUInt32 &filePos,
171
                          GUInt32 &fileAlign, int &bitsTaken)
172

173
{
174
    if (filePos == fileAlign)
×
175
    {
176
        fileAlign += codeBits;
×
177
    }
178

179
    const int BitMask[] = {0x0000, 0x0001, 0x0003, 0x0007,
×
180
                           0x000f, 0x001f, 0x003f, 0x007f};
181

182
    int ret = 0;
×
183
    int bitsLeftToGo = codeBits;
×
184

185
    while (bitsLeftToGo > 0)
×
186
    {
187
        if (filePos >= blockSize)
×
188
            return -1;
×
189

190
        int tmp = blockData[filePos];
×
191
        tmp = tmp >> bitsTaken;
×
192

193
        if (bitsLeftToGo < 8)
×
194
            tmp &= BitMask[bitsLeftToGo];
×
195

196
        tmp = tmp << (codeBits - bitsLeftToGo);
×
197

198
        ret |= tmp;
×
199

200
        bitsLeftToGo -= (8 - bitsTaken);
×
201
        bitsTaken = 0;
×
202

203
        if (bitsLeftToGo < 0)
×
204
            bitsTaken = 8 + bitsLeftToGo;
×
205

206
        if (bitsTaken == 0)
×
207
            filePos++;
×
208
    }
209

210
#if RIK_PIXEL_DEBUG
211
    printf("c%03X\n", ret); /*ok*/
212
#endif
213

214
    return ret;
×
215
}
216

217
/************************************************************************/
218
/*                             OutputPixel()                            */
219
/************************************************************************/
220

221
static void OutputPixel(GByte pixel, void *image, GUInt32 imageWidth,
×
222
                        GUInt32 lineBreak, int &imageLine, GUInt32 &imagePos)
223

224
{
225
    if (imagePos < imageWidth && imageLine >= 0)
×
226
        reinterpret_cast<GByte *>(image)[imagePos + imageLine * imageWidth] =
×
227
            pixel;
228

229
    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
    if (imagePos == lineBreak)
×
238
    {
239
#if RIK_PIXEL_DEBUG
240
        printf("\n%d\n", imageLine); /*ok*/
241
#endif
242

243
        imagePos = 0;
×
244

245
        imageLine--;
×
246
    }
247
}
×
248

249
/************************************************************************/
250
/*                             IReadBlock()                             */
251
/************************************************************************/
252

253
CPLErr RIKRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
×
254

255
{
256
    RIKDataset *poRDS = reinterpret_cast<RIKDataset *>(poDS);
×
257

258
    const GUInt32 blocks = poRDS->nHorBlocks * poRDS->nVertBlocks;
×
259
    const GUInt32 nBlockIndex = nBlockXOff + nBlockYOff * poRDS->nHorBlocks;
×
260
    const GUInt32 nBlockOffset = poRDS->pOffsets[nBlockIndex];
×
261

262
    GUInt32 nBlockSize = poRDS->nFileSize;
×
263
    for (GUInt32 bi = nBlockIndex + 1; bi < blocks; bi++)
×
264
    {
265
        if (poRDS->pOffsets[bi])
×
266
        {
267
            nBlockSize = poRDS->pOffsets[bi];
×
268
            break;
×
269
        }
270
    }
271
    nBlockSize -= nBlockOffset;
×
272

273
    const GUInt32 pixels = poRDS->nBlockXSize * poRDS->nBlockYSize;
×
274

275
    if (!nBlockOffset || !nBlockSize
×
276
#ifdef RIK_SINGLE_BLOCK
277
        || nBlockIndex != RIK_SINGLE_BLOCK
278
#endif
279
    )
280
    {
281
        memset(pImage, 0, pixels);
×
282
        return CE_None;
×
283
    }
284

285
    VSIFSeekL(poRDS->fp, nBlockOffset, SEEK_SET);
×
286

287
    /* -------------------------------------------------------------------- */
288
    /*      Read uncompressed block.                                        */
289
    /* -------------------------------------------------------------------- */
290

291
    if (poRDS->options == 0x00 || poRDS->options == 0x40)
×
292
    {
293
        VSIFReadL(pImage, 1, pixels, poRDS->fp);
×
294
        return CE_None;
×
295
    }
296

297
    // Read block to memory
298
    GByte *blockData =
299
        reinterpret_cast<GByte *>(VSI_MALLOC_VERBOSE(nBlockSize));
×
300
    if (blockData == nullptr)
×
301
        return CE_Failure;
×
302
    if (VSIFReadL(blockData, 1, nBlockSize, poRDS->fp) != nBlockSize)
×
303
    {
304
        VSIFree(blockData);
×
305
        return CE_Failure;
×
306
    }
307
    memset(pImage, 0, pixels);
×
308

309
    /* -------------------------------------------------------------------- */
310
    /*      Read RLE block.                                                 */
311
    /* -------------------------------------------------------------------- */
312
    GUInt32 filePos = 0;
×
313
    GUInt32 imagePos = 0;
×
314

315
    if (poRDS->options == 0x01 || poRDS->options == 0x41)
×
316
    {
317
        while (filePos + 1 < nBlockSize && imagePos < pixels)
×
318
        {
319
            GByte count = blockData[filePos++];
×
320
            GByte color = blockData[filePos++];
×
321

322
            for (GByte i = 0; imagePos < pixels && i <= count; i++)
×
323
            {
324
                reinterpret_cast<GByte *>(pImage)[imagePos++] = color;
×
325
            }
326
        }
×
327
    }
328

329
    /* -------------------------------------------------------------------- */
330
    /*      Read LZW block.                                                 */
331
    /* -------------------------------------------------------------------- */
332

333
    else if (poRDS->options == 0x0b)
×
334
    {
335
        try
336
        {
337
            if (nBlockSize < 5)
×
338
            {
339
                throw "Not enough bytes";
×
340
            }
341

342
            const bool LZW_HAS_CLEAR_CODE = !!(blockData[4] & 0x80);
×
343
            const int LZW_MAX_BITS = blockData[4] & 0x1f;  // Max 13
×
344
            if (LZW_MAX_BITS > 13)
×
345
            {
346
                throw "Invalid LZW_MAX_BITS";
×
347
            }
348
            const int LZW_BITS_PER_PIXEL = 8;
×
349
            const int LZW_OFFSET = 5;
×
350

351
            const int LZW_CLEAR = 1 << LZW_BITS_PER_PIXEL;
×
352
            const int LZW_CODES = 1 << LZW_MAX_BITS;
×
353
            const int LZW_NO_SUCH_CODE = LZW_CODES + 1;
×
354

355
            int lastAdded = LZW_HAS_CLEAR_CODE ? LZW_CLEAR : LZW_CLEAR - 1;
×
356
            int codeBits = LZW_BITS_PER_PIXEL + 1;
×
357

358
            int code;
359
            int lastCode;
360
            GByte lastOutput;
361
            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
            for (int i = 0; i < LZW_CLEAR; i++)
×
367
                character[i] = static_cast<GByte>(i);
×
368
            for (int i = 0; i < LZW_CODES; i++)
×
369
                prefix[i] = LZW_NO_SUCH_CODE;
×
370

371
            filePos = LZW_OFFSET;
×
372
            GUInt32 fileAlign = LZW_OFFSET;
×
373
            int imageLine = poRDS->nBlockYSize - 1;
×
374

375
            GUInt32 lineBreak = poRDS->nBlockXSize;
×
376

377
            // 32 bit alignment
378
            lineBreak += 3;
×
379
            lineBreak &= 0xfffffffc;
×
380

381
            code = GetNextLZWCode(codeBits, blockData, nBlockSize, filePos,
×
382
                                  fileAlign, bitsTaken);
383
            if (code < 0)
×
384
            {
385
                throw "Not enough bytes";
×
386
            }
387

388
            OutputPixel(static_cast<GByte>(code), pImage, poRDS->nBlockXSize,
×
389
                        lineBreak, imageLine, imagePos);
390
            lastOutput = static_cast<GByte>(code);
×
391

392
            while (imageLine >= 0 &&
×
393
                   (imageLine || imagePos < poRDS->nBlockXSize) &&
×
394
                   filePos < nBlockSize)
×
395
            {
396
                lastCode = code;
×
397
                code = GetNextLZWCode(codeBits, blockData, nBlockSize, filePos,
×
398
                                      fileAlign, bitsTaken);
399
                if (code < 0)
×
400
                {
401
                    throw "Not enough bytes";
×
402
                }
403

404
                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
                    for (int i = LZW_CLEAR; i < LZW_CODES; i++)
×
417
                        prefix[i] = LZW_NO_SUCH_CODE;
×
418
                    lastAdded = LZW_CLEAR;
×
419
                    codeBits = LZW_BITS_PER_PIXEL + 1;
×
420

421
                    filePos = fileAlign;
×
422
                    bitsTaken = 0;
×
423

424
                    code = GetNextLZWCode(codeBits, blockData, nBlockSize,
×
425
                                          filePos, fileAlign, bitsTaken);
426
                    if (code < 0)
×
427
                    {
428
                        throw "Not enough bytes";
×
429
                    }
430

431
                    if (code > lastAdded)
×
432
                    {
433
                        throw "Clear Error";
×
434
                    }
435

436
                    OutputPixel((GByte)code, pImage, poRDS->nBlockXSize,
×
437
                                lineBreak, imageLine, imagePos);
438
                    lastOutput = (GByte)code;
×
439
                }
440
                else
441
                {
442
                    // Set-up decoding
443

444
                    GByte stack[8192];  // only need LZW_CODES for size.
445

446
                    int stackPtr = 0;
×
447
                    int decodeCode = code;
×
448

449
                    if (code == lastAdded + 1)
×
450
                    {
451
                        // Handle special case
452
                        *stack = lastOutput;
×
453
                        stackPtr = 1;
×
454
                        decodeCode = lastCode;
×
455
                    }
456
                    else if (code > lastAdded + 1)
×
457
                    {
458
                        throw "Too high code";
×
459
                    }
460

461
                    // Decode
462

463
                    int i = 0;
×
464
                    while (++i < LZW_CODES && decodeCode >= LZW_CLEAR &&
×
465
                           decodeCode < LZW_NO_SUCH_CODE)
466
                    {
467
                        stack[stackPtr++] = character[decodeCode];
×
468
                        decodeCode = prefix[decodeCode];
×
469
                    }
470
                    stack[stackPtr++] = static_cast<GByte>(decodeCode);
×
471

472
                    if (i == LZW_CODES || decodeCode >= LZW_NO_SUCH_CODE)
×
473
                    {
474
                        throw "Decode error";
×
475
                    }
476

477
                    // Output stack
478

479
                    lastOutput = stack[stackPtr - 1];
×
480

481
                    while (stackPtr != 0 && imagePos < pixels)
×
482
                    {
483
                        OutputPixel(stack[--stackPtr], pImage,
×
484
                                    poRDS->nBlockXSize, lineBreak, imageLine,
485
                                    imagePos);
486
                    }
487

488
                    // Add code to string table
489

490
                    if (lastCode != LZW_NO_SUCH_CODE &&
×
491
                        lastAdded != LZW_CODES - 1)
×
492
                    {
493
                        ++lastAdded;
×
494
                        if (lastAdded >= 8192)
×
495
                        {
496
                            throw "Decode error";
×
497
                        }
498
                        prefix[lastAdded] = lastCode;
×
499
                        character[lastAdded] = lastOutput;
×
500
                    }
501

502
                    // Check if we need to use more bits
503

504
                    if (lastAdded == (1 << codeBits) - 1 &&
×
505
                        codeBits != LZW_MAX_BITS)
506
                    {
507
                        codeBits++;
×
508

509
                        filePos = fileAlign;
×
510
                        bitsTaken = 0;
×
511
                    }
512
                }
513
            }
514
        }
515
        catch (const char *errStr)
×
516
        {
517
#if RIK_ALLOW_BLOCK_ERRORS
518
            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
    else if (poRDS->options == 0x0d)
×
539
    {
540
        uLong destLen = pixels;
×
541
        Byte *upsideDown = static_cast<Byte *>(CPLMalloc(pixels));
×
542

543
        if (uncompress(upsideDown, &destLen, blockData, nBlockSize) != Z_OK)
×
544
        {
545
            CPLDebug("RIK", "Deflate compression failed on block %u",
×
546
                     nBlockIndex);
547
        }
548

549
        for (GUInt32 i = 0; i < poRDS->nBlockYSize; i++)
×
550
        {
551
            memcpy(reinterpret_cast<Byte *>(pImage) + poRDS->nBlockXSize * i,
×
552
                   upsideDown +
×
553
                       poRDS->nBlockXSize * (poRDS->nBlockYSize - i - 1),
×
554
                   poRDS->nBlockXSize);
×
555
        }
556

557
        CPLFree(upsideDown);
×
558
    }
559

560
    CPLFree(blockData);
×
561

562
    return CE_None;
×
563
}
564

565
/************************************************************************/
566
/*                       GetColorInterpretation()                       */
567
/************************************************************************/
568

569
GDALColorInterp RIKRasterBand::GetColorInterpretation()
×
570

571
{
572
    return GCI_PaletteIndex;
×
573
}
574

575
/************************************************************************/
576
/*                           GetColorTable()                            */
577
/************************************************************************/
578

579
GDALColorTable *RIKRasterBand::GetColorTable()
×
580

581
{
582
    RIKDataset *poRDS = reinterpret_cast<RIKDataset *>(poDS);
×
583

584
    return poRDS->poColorTable;
×
585
}
586

587
/************************************************************************/
588
/* ==================================================================== */
589
/*                              RIKDataset                              */
590
/* ==================================================================== */
591
/************************************************************************/
592

593
/************************************************************************/
594
/*                             RIKDataset()                             */
595
/************************************************************************/
596

597
RIKDataset::RIKDataset()
×
598
    : fp(nullptr), nBlockXSize(0), nBlockYSize(0), nHorBlocks(0),
599
      nVertBlocks(0), nFileSize(0), pOffsets(nullptr), options(0),
600
      poColorTable(nullptr)
×
601

602
{
603
    m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
×
604
    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
}
×
619

620
/************************************************************************/
621
/*                            ~RIKDataset()                             */
622
/************************************************************************/
623

624
RIKDataset::~RIKDataset()
×
625

626
{
627
    FlushCache(true);
×
628
    CPLFree(pOffsets);
×
629
    if (fp != nullptr)
×
630
        VSIFCloseL(fp);
×
631
    delete poColorTable;
×
632
}
×
633

634
/************************************************************************/
635
/*                          GetGeoTransform()                           */
636
/************************************************************************/
637

638
CPLErr RIKDataset::GetGeoTransform(GDALGeoTransform &gt) const
×
639

640
{
641
    gt = m_gt;
×
642
    return CE_None;
×
643
}
644

645
/************************************************************************/
646
/*                          GetSpatialRef()                             */
647
/************************************************************************/
648

649
const OGRSpatialReference *RIKDataset::GetSpatialRef() const
×
650

651
{
652
    return &m_oSRS;
×
653
}
654

655
/************************************************************************/
656
/*                             GetRikString()                           */
657
/************************************************************************/
658

659
static GUInt16 GetRikString(VSILFILE *fp, char *str, GUInt16 strLength)
783✔
660

661
{
662
    GUInt16 actLength;
663

664
    VSIFReadL(&actLength, 1, sizeof(actLength), fp);
783✔
665
#ifdef CPL_MSB
666
    CPL_SWAP16PTR(&actLength);
667
#endif
668

669
    if (actLength + 2 > strLength)
783✔
670
    {
671
        return actLength;
×
672
    }
673

674
    VSIFReadL(str, 1, actLength, fp);
783✔
675

676
    str[actLength] = '\0';
783✔
677

678
    return actLength;
783✔
679
}
680

681
/************************************************************************/
682
/*                          Identify()                                  */
683
/************************************************************************/
684

685
int RIKDataset::Identify(GDALOpenInfo *poOpenInfo)
57,707✔
686

687
{
688
    if (poOpenInfo->fpL == nullptr || poOpenInfo->nHeaderBytes < 50)
57,707✔
689
        return FALSE;
53,566✔
690

691
    if (STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader, "RIK3"))
4,141✔
692
    {
693
        return TRUE;
×
694
    }
695
    else
696
    {
697
        GUInt16 actLength;
698
        memcpy(&actLength, poOpenInfo->pabyHeader, 2);
4,141✔
699
#ifdef CPL_MSB
700
        CPL_SWAP16PTR(&actLength);
701
#endif
702
        if (actLength + 2 > 1024)
4,141✔
703
        {
704
            return FALSE;
2,463✔
705
        }
706
        if (actLength == 0)
1,678✔
707
            return -1;
1,615✔
708

709
        for (int i = 0; i < actLength; i++)
2,544✔
710
        {
711
            if (poOpenInfo->pabyHeader[2 + i] == 0)
2,538✔
712
                return FALSE;
57✔
713
        }
714

715
        if (poOpenInfo->IsExtensionEqualToCI("rik"))
6✔
716
            return TRUE;
×
717

718
        // We really need Open to be able to conclude
719
        return -1;
6✔
720
    }
721
}
722

723
/************************************************************************/
724
/*                                Open()                                */
725
/************************************************************************/
726

727
GDALDataset *RIKDataset::Open(GDALOpenInfo *poOpenInfo)
783✔
728

729
{
730
    if (Identify(poOpenInfo) == FALSE)
783✔
731
        return nullptr;
×
732

733
    bool rik3header = false;
783✔
734

735
    if (STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader, "RIK3"))
783✔
736
    {
737
        rik3header = true;
×
738
        VSIFSeekL(poOpenInfo->fpL, 4, SEEK_SET);
×
739
    }
740
    else
741
        VSIFSeekL(poOpenInfo->fpL, 0, SEEK_SET);
783✔
742

743
    /* -------------------------------------------------------------------- */
744
    /*      Read the map name.                                              */
745
    /* -------------------------------------------------------------------- */
746

747
    char name[1024];
748

749
    GUInt16 nameLength = GetRikString(poOpenInfo->fpL, name, sizeof(name));
783✔
750

751
    if (nameLength > sizeof(name) - 1)
783✔
752
    {
753
        return nullptr;
×
754
    }
755

756
    if (!rik3header)
783✔
757
    {
758
        if (nameLength == 0 || nameLength != strlen(name))
783✔
759
            return nullptr;
780✔
760
    }
761

762
    /* -------------------------------------------------------------------- */
763
    /*      Read the header.                                                */
764
    /* -------------------------------------------------------------------- */
765

766
    RIKHeader header;
767
    double metersPerPixel;
768

769
    const char *headerType = "RIK3";
3✔
770

771
    if (rik3header)
3✔
772
    {
773
        /* --------------------------------------------------------------------
774
         */
775
        /*      RIK3 header. */
776
        /* --------------------------------------------------------------------
777
         */
778

779
        // Read projection name
780

781
        char projection[1024];
782

783
        GUInt16 projLength =
784
            GetRikString(poOpenInfo->fpL, projection, sizeof(projection));
×
785

786
        if (projLength > sizeof(projection) - 1)
×
787
        {
788
            // Unreasonable string length, assume wrong format
789
            return nullptr;
×
790
        }
791

792
        // Read unknown string
793

794
        /*projLength =*/GetRikString(poOpenInfo->fpL, projection,
×
795
                                     sizeof(projection));
796

797
        // Read map north edge
798

799
        char tmpStr[16];
800

801
        GUInt16 tmpLength =
802
            GetRikString(poOpenInfo->fpL, tmpStr, sizeof(tmpStr));
×
803

804
        if (tmpLength > sizeof(tmpStr) - 1)
×
805
        {
806
            // Unreasonable string length, assume wrong format
807
            return nullptr;
×
808
        }
809

810
        header.fNorth = CPLAtof(tmpStr);
×
811

812
        // Read map west edge
813

814
        tmpLength = GetRikString(poOpenInfo->fpL, tmpStr, sizeof(tmpStr));
×
815

816
        if (tmpLength > sizeof(tmpStr) - 1)
×
817
        {
818
            // Unreasonable string length, assume wrong format
819
            return nullptr;
×
820
        }
821

822
        header.fWest = CPLAtof(tmpStr);
×
823

824
        // Read binary values
825

826
        VSIFReadL(&header.iScale, 1, sizeof(header.iScale), poOpenInfo->fpL);
×
827
        VSIFReadL(&header.iMPPNum, 1, sizeof(header.iMPPNum), poOpenInfo->fpL);
×
828
        VSIFReadL(&header.iBlockWidth, 1, sizeof(header.iBlockWidth),
×
829
                  poOpenInfo->fpL);
830
        VSIFReadL(&header.iBlockHeight, 1, sizeof(header.iBlockHeight),
×
831
                  poOpenInfo->fpL);
832
        VSIFReadL(&header.iHorBlocks, 1, sizeof(header.iHorBlocks),
×
833
                  poOpenInfo->fpL);
834
        VSIFReadL(&header.iVertBlocks, 1, sizeof(header.iVertBlocks),
×
835
                  poOpenInfo->fpL);
836
#ifdef CPL_MSB
837
        CPL_SWAP32PTR(&header.iScale);
838
        CPL_SWAP32PTR(&header.iMPPNum);
839
        CPL_SWAP32PTR(&header.iBlockWidth);
840
        CPL_SWAP32PTR(&header.iBlockHeight);
841
        CPL_SWAP32PTR(&header.iHorBlocks);
842
        CPL_SWAP32PTR(&header.iVertBlocks);
843
#endif
844
        if (header.iMPPNum == 0)
×
845
            return nullptr;
×
846

847
        VSIFReadL(&header.iBitsPerPixel, 1, sizeof(header.iBitsPerPixel),
×
848
                  poOpenInfo->fpL);
849
        VSIFReadL(&header.iOptions, 1, sizeof(header.iOptions),
×
850
                  poOpenInfo->fpL);
851
        header.iUnknown = header.iOptions;
×
852
        VSIFReadL(&header.iOptions, 1, sizeof(header.iOptions),
×
853
                  poOpenInfo->fpL);
854

855
        header.fSouth =
×
856
            header.fNorth - static_cast<double>(header.iVertBlocks) *
×
857
                                header.iBlockHeight * header.iMPPNum;
×
858
        header.fEast = header.fWest + static_cast<double>(header.iHorBlocks) *
×
859
                                          header.iBlockWidth * header.iMPPNum;
×
860

861
        metersPerPixel = header.iMPPNum;
×
862
    }
863
    else
864
    {
865
        /* --------------------------------------------------------------------
866
         */
867
        /*      Old RIK header. */
868
        /* --------------------------------------------------------------------
869
         */
870

871
        VSIFReadL(&header.iUnknown, 1, sizeof(header.iUnknown),
3✔
872
                  poOpenInfo->fpL);
873
        VSIFReadL(&header.fSouth, 1, sizeof(header.fSouth), poOpenInfo->fpL);
3✔
874
        VSIFReadL(&header.fWest, 1, sizeof(header.fWest), poOpenInfo->fpL);
3✔
875
        VSIFReadL(&header.fNorth, 1, sizeof(header.fNorth), poOpenInfo->fpL);
3✔
876
        VSIFReadL(&header.fEast, 1, sizeof(header.fEast), poOpenInfo->fpL);
3✔
877
        VSIFReadL(&header.iScale, 1, sizeof(header.iScale), poOpenInfo->fpL);
3✔
878
        VSIFReadL(&header.iMPPNum, 1, sizeof(header.iMPPNum), poOpenInfo->fpL);
3✔
879
#ifdef CPL_MSB
880
        CPL_SWAP64PTR(&header.fSouth);
881
        CPL_SWAP64PTR(&header.fWest);
882
        CPL_SWAP64PTR(&header.fNorth);
883
        CPL_SWAP64PTR(&header.fEast);
884
        CPL_SWAP32PTR(&header.iScale);
885
        CPL_SWAP32PTR(&header.iMPPNum);
886
#endif
887

888
        if (!std::isfinite(header.fSouth) || !std::isfinite(header.fWest) ||
6✔
889
            !std::isfinite(header.fNorth) || !std::isfinite(header.fEast) ||
9✔
890
            header.iMPPNum == 0)
3✔
891
        {
892
            return nullptr;
×
893
        }
894

895
        const bool offsetBounds = header.fSouth < 4000000;
3✔
896

897
        header.iMPPDen = 1;
3✔
898

899
        if (offsetBounds)
3✔
900
        {
901
            header.fSouth += 4002995;
3✔
902
            header.fNorth += 5004000;
3✔
903
            header.fWest += 201000;
3✔
904
            header.fEast += 302005;
3✔
905

906
            VSIFReadL(&header.iMPPDen, 1, sizeof(header.iMPPDen),
3✔
907
                      poOpenInfo->fpL);
908
#ifdef CPL_MSB
909
            CPL_SWAP32PTR(&header.iMPPDen);
910
#endif
911
            if (header.iMPPDen == 0)
3✔
912
                return nullptr;
×
913

914
            headerType = "RIK1";
3✔
915
        }
916
        else
917
        {
918
            headerType = "RIK2";
×
919
        }
920

921
        metersPerPixel = header.iMPPNum / static_cast<double>(header.iMPPDen);
3✔
922

923
        VSIFReadL(&header.iBlockWidth, 1, sizeof(header.iBlockWidth),
3✔
924
                  poOpenInfo->fpL);
925
        VSIFReadL(&header.iBlockHeight, 1, sizeof(header.iBlockHeight),
3✔
926
                  poOpenInfo->fpL);
927
        VSIFReadL(&header.iHorBlocks, 1, sizeof(header.iHorBlocks),
3✔
928
                  poOpenInfo->fpL);
929
#ifdef CPL_MSB
930
        CPL_SWAP32PTR(&header.iBlockWidth);
931
        CPL_SWAP32PTR(&header.iBlockHeight);
932
        CPL_SWAP32PTR(&header.iHorBlocks);
933
#endif
934

935
        if ((header.iBlockWidth > 2000) || (header.iBlockWidth < 10) ||
3✔
936
            (header.iBlockHeight > 2000) || (header.iBlockHeight < 10))
×
937
            return nullptr;
3✔
938

939
        if (!offsetBounds)
×
940
        {
941
            VSIFReadL(&header.iVertBlocks, 1, sizeof(header.iVertBlocks),
×
942
                      poOpenInfo->fpL);
943
#ifdef CPL_MSB
944
            CPL_SWAP32PTR(&header.iVertBlocks);
945
#endif
946
        }
947

948
        if (offsetBounds || !header.iVertBlocks)
×
949
        {
950
            double dfVertBlocks = ceil((header.fNorth - header.fSouth) /
×
951
                                       (header.iBlockHeight * metersPerPixel));
×
952
            if (dfVertBlocks < 1 || dfVertBlocks > INT_MAX)
×
953
                return nullptr;
×
954
            header.iVertBlocks = static_cast<GUInt32>(dfVertBlocks);
×
955
        }
956

957
#if RIK_HEADER_DEBUG
958
        CPLDebug("RIK", "Original vertical blocks %d\n", header.iVertBlocks);
959
#endif
960

961
        VSIFReadL(&header.iBitsPerPixel, 1, sizeof(header.iBitsPerPixel),
×
962
                  poOpenInfo->fpL);
963

964
        if (header.iBitsPerPixel != 8)
×
965
        {
966
            CPLError(CE_Failure, CPLE_OpenFailed,
×
967
                     "File %s has unsupported number of bits per pixel.\n",
968
                     poOpenInfo->pszFilename);
969
            return nullptr;
×
970
        }
971

972
        VSIFReadL(&header.iOptions, 1, sizeof(header.iOptions),
×
973
                  poOpenInfo->fpL);
974

975
        if (header.iOptions != 0x00 &&  // Uncompressed
×
976
            header.iOptions != 0x40 &&  // Uncompressed
×
977
            header.iOptions != 0x01 &&  // RLE
×
978
            header.iOptions != 0x41 &&  // RLE
×
979
            header.iOptions != 0x0B &&  // LZW
×
980
            header.iOptions != 0x0D)    // ZLIB
×
981
        {
982
            CPLError(CE_Failure, CPLE_OpenFailed,
×
983
                     "File %s. Unknown map options.\n",
984
                     poOpenInfo->pszFilename);
985
            return nullptr;
×
986
        }
987
    }
988

989
    if (header.iBlockWidth == 0 || header.iHorBlocks == 0 ||
×
990
        header.iBlockWidth >= INT_MAX / header.iHorBlocks ||
×
991
        header.iBlockHeight == 0 || header.iVertBlocks == 0 ||
×
992
        header.iBlockHeight >= INT_MAX / header.iVertBlocks ||
×
993
        header.iBlockHeight >= INT_MAX / header.iBlockWidth ||
×
994
        header.iVertBlocks >= INT_MAX / (int)sizeof(GUInt32) ||
×
995
        header.iHorBlocks >=
×
996
            INT_MAX / (header.iVertBlocks * (int)sizeof(GUInt32)))
×
997
    {
998
        return nullptr;
×
999
    }
1000

1001
    /* -------------------------------------------------------------------- */
1002
    /*      Read the palette.                                               */
1003
    /* -------------------------------------------------------------------- */
1004

1005
    GByte palette[768];
1006

1007
    for (GUInt16 i = 0; i < 256; i++)
×
1008
    {
1009
        VSIFReadL(&palette[i * 3 + 2], 1, 1, poOpenInfo->fpL);
×
1010
        VSIFReadL(&palette[i * 3 + 1], 1, 1, poOpenInfo->fpL);
×
1011
        VSIFReadL(&palette[i * 3 + 0], 1, 1, poOpenInfo->fpL);
×
1012
    }
1013

1014
    /* -------------------------------------------------------------------- */
1015
    /*      Find block offsets.                                             */
1016
    /* -------------------------------------------------------------------- */
1017

1018
    GUInt32 blocks = header.iHorBlocks * header.iVertBlocks;
×
1019
    GUInt32 *offsets =
1020
        reinterpret_cast<GUInt32 *>(VSIMalloc(blocks * sizeof(GUInt32)));
×
1021

1022
    if (!offsets)
×
1023
    {
1024
        CPLError(CE_Failure, CPLE_OpenFailed,
×
1025
                 "File %s. Unable to allocate offset table.\n",
1026
                 poOpenInfo->pszFilename);
1027
        return nullptr;
×
1028
    }
1029

1030
    if (header.iOptions == 0x00)
×
1031
    {
1032
        offsets[0] = static_cast<GUInt32>(VSIFTellL(poOpenInfo->fpL));
×
1033

1034
        if (VSIFEofL(poOpenInfo->fpL))
×
1035
        {
1036
            CPLError(CE_Failure, CPLE_OpenFailed,
×
1037
                     "File %s. Read past end of file.\n",
1038
                     poOpenInfo->pszFilename);
1039
            CPLFree(offsets);
×
1040
            return nullptr;
×
1041
        }
1042

1043
        VSIFSeekL(poOpenInfo->fpL, 0, SEEK_END);
×
1044
        vsi_l_offset nBigFileSize = VSIFTellL(poOpenInfo->fpL);
×
1045
        if (nBigFileSize > UINT_MAX)
×
1046
            nBigFileSize = UINT_MAX;
×
1047
        GUInt32 fileSize = static_cast<GUInt32>(nBigFileSize);
×
1048

1049
        GUInt32 nBlocksFromFileSize =
×
1050
            (fileSize - offsets[0]) /
×
1051
            (header.iBlockWidth * header.iBlockHeight);
×
1052
        if (nBlocksFromFileSize < blocks)
×
1053
        {
1054
            blocks = nBlocksFromFileSize;
×
1055
            header.iVertBlocks = blocks / header.iHorBlocks;
×
1056
        }
1057

1058
        if (header.iVertBlocks == 0)
×
1059
        {
1060
            CPLError(CE_Failure, CPLE_OpenFailed, "File %s too short.\n",
×
1061
                     poOpenInfo->pszFilename);
1062
            CPLFree(offsets);
×
1063
            return nullptr;
×
1064
        }
1065

1066
        for (GUInt32 i = 1; i < blocks; i++)
×
1067
        {
1068
            offsets[i] =
×
1069
                offsets[i - 1] + header.iBlockWidth * header.iBlockHeight;
×
1070
        }
1071
    }
1072
    else
1073
    {
1074
        for (GUInt32 i = 0; i < blocks; i++)
×
1075
        {
1076
            if (VSIFReadL(&offsets[i], sizeof(offsets[i]), 1,
×
1077
                          poOpenInfo->fpL) != 1)
×
1078
                break;
×
1079
#ifdef CPL_MSB
1080
            CPL_SWAP32PTR(&offsets[i]);
1081
#endif
1082
            if (rik3header)
×
1083
            {
1084
                GUInt32 blockSize;
1085
                if (VSIFReadL(&blockSize, sizeof(blockSize), 1,
×
1086
                              poOpenInfo->fpL) != 1)
×
1087
                    break;
×
1088
#ifdef CPL_MSB
1089
                CPL_SWAP32PTR(&blockSize);
1090
#endif
1091
            }
1092
        }
1093
    }
1094

1095
    /* -------------------------------------------------------------------- */
1096
    /*      Final checks.                                                   */
1097
    /* -------------------------------------------------------------------- */
1098

1099
    // File size
1100

1101
    if (VSIFEofL(poOpenInfo->fpL))
×
1102
    {
1103
        CPLError(CE_Failure, CPLE_OpenFailed,
×
1104
                 "File %s. Read past end of file.\n", poOpenInfo->pszFilename);
1105
        CPLFree(offsets);
×
1106
        return nullptr;
×
1107
    }
1108

1109
    VSIFSeekL(poOpenInfo->fpL, 0, SEEK_END);
×
1110
    GUInt32 fileSize = static_cast<GUInt32>(VSIFTellL(poOpenInfo->fpL));
×
1111

1112
#if RIK_HEADER_DEBUG
1113
    CPLDebug("RIK", "File size %d\n", fileSize);
1114
#endif
1115

1116
    // Make sure the offset table is valid
1117

1118
    GUInt32 lastoffset = 0;
×
1119

1120
    for (GUInt32 y = 0; y < header.iVertBlocks; y++)
×
1121
    {
1122
        for (GUInt32 x = 0; x < header.iHorBlocks; x++)
×
1123
        {
1124
            if (!offsets[x + y * header.iHorBlocks])
×
1125
            {
1126
                continue;
×
1127
            }
1128

1129
            if (offsets[x + y * header.iHorBlocks] >= fileSize)
×
1130
            {
1131
                if (!y)
×
1132
                {
1133
                    CPLError(CE_Failure, CPLE_OpenFailed,
×
1134
                             "File %s too short.\n", poOpenInfo->pszFilename);
1135
                    CPLFree(offsets);
×
1136
                    return nullptr;
×
1137
                }
1138
                header.iVertBlocks = y;
×
1139
                break;
×
1140
            }
1141

1142
            if (offsets[x + y * header.iHorBlocks] < lastoffset)
×
1143
            {
1144
                if (!y)
×
1145
                {
1146
                    CPLError(CE_Failure, CPLE_OpenFailed,
×
1147
                             "File %s. Corrupt offset table.\n",
1148
                             poOpenInfo->pszFilename);
1149
                    CPLFree(offsets);
×
1150
                    return nullptr;
×
1151
                }
1152
                header.iVertBlocks = y;
×
1153
                break;
×
1154
            }
1155

1156
            lastoffset = offsets[x + y * header.iHorBlocks];
×
1157
        }
1158
    }
1159

1160
#if RIK_HEADER_DEBUG
1161
    CPLDebug("RIK",
1162
             "first offset %d\n"
1163
             "last offset %d\n",
1164
             offsets[0], lastoffset);
1165
#endif
1166

1167
    const char *compression = "RLE";
×
1168

1169
    if (header.iOptions == 0x00 || header.iOptions == 0x40)
×
1170
        compression = "Uncompressed";
×
1171
    if (header.iOptions == 0x0b)
×
1172
        compression = "LZW";
×
1173
    if (header.iOptions == 0x0d)
×
1174
        compression = "ZLIB";
×
1175

1176
    CPLDebug("RIK",
×
1177
             "RIK file parameters:\n"
1178
             " name: %s\n"
1179
             " header: %s\n"
1180
             " unknown: 0x%X\n"
1181
             " south: %f\n"
1182
             " west: %f\n"
1183
             " north: %f\n"
1184
             " east: %f\n"
1185
             " original scale: %d\n"
1186
             " meters per pixel: %f\n"
1187
             " block width: %d\n"
1188
             " block height: %d\n"
1189
             " horizontal blocks: %d\n"
1190
             " vertical blocks: %d\n"
1191
             " bits per pixel: %d\n"
1192
             " options: 0x%X\n"
1193
             " compression: %s\n",
1194
             name, headerType, header.iUnknown, header.fSouth, header.fWest,
×
1195
             header.fNorth, header.fEast, header.iScale, metersPerPixel,
1196
             header.iBlockWidth, header.iBlockHeight, header.iHorBlocks,
1197
             header.iVertBlocks, header.iBitsPerPixel, header.iOptions,
×
1198
             compression);
1199

1200
    /* -------------------------------------------------------------------- */
1201
    /*      Create a corresponding GDALDataset.                             */
1202
    /* -------------------------------------------------------------------- */
1203

1204
    RIKDataset *poDS = new RIKDataset();
×
1205

1206
    poDS->fp = poOpenInfo->fpL;
×
1207
    poOpenInfo->fpL = nullptr;
×
1208

1209
    poDS->m_gt[0] = header.fWest - metersPerPixel / 2.0;
×
1210
    poDS->m_gt[1] = metersPerPixel;
×
1211
    poDS->m_gt[2] = 0.0;
×
1212
    poDS->m_gt[3] = header.fNorth + metersPerPixel / 2.0;
×
1213
    poDS->m_gt[4] = 0.0;
×
1214
    poDS->m_gt[5] = -metersPerPixel;
×
1215

1216
    poDS->nBlockXSize = header.iBlockWidth;
×
1217
    poDS->nBlockYSize = header.iBlockHeight;
×
1218
    poDS->nHorBlocks = header.iHorBlocks;
×
1219
    poDS->nVertBlocks = header.iVertBlocks;
×
1220
    poDS->pOffsets = offsets;
×
1221
    poDS->options = header.iOptions;
×
1222
    poDS->nFileSize = fileSize;
×
1223

1224
    poDS->nRasterXSize = header.iBlockWidth * header.iHorBlocks;
×
1225
    poDS->nRasterYSize = header.iBlockHeight * header.iVertBlocks;
×
1226

1227
    poDS->nBands = 1;
×
1228

1229
    GDALColorEntry oEntry;
1230
    poDS->poColorTable = new GDALColorTable();
×
1231
    for (GUInt16 i = 0; i < 256; i++)
×
1232
    {
1233
        oEntry.c1 = palette[i * 3 + 2];  // Red
×
1234
        oEntry.c2 = palette[i * 3 + 1];  // Green
×
1235
        oEntry.c3 = palette[i * 3];      // Blue
×
1236
        oEntry.c4 = 255;
×
1237

1238
        poDS->poColorTable->SetColorEntry(i, &oEntry);
×
1239
    }
1240

1241
    /* -------------------------------------------------------------------- */
1242
    /*      Create band information objects.                                */
1243
    /* -------------------------------------------------------------------- */
1244

1245
    poDS->SetBand(1, new RIKRasterBand(poDS, 1));
×
1246

1247
    /* -------------------------------------------------------------------- */
1248
    /*      Initialize any PAM information.                                 */
1249
    /* -------------------------------------------------------------------- */
1250

1251
    poDS->SetDescription(poOpenInfo->pszFilename);
×
1252
    poDS->TryLoadXML();
×
1253

1254
    /* -------------------------------------------------------------------- */
1255
    /*      Check for external overviews.                                   */
1256
    /* -------------------------------------------------------------------- */
1257
    poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename,
×
1258
                                poOpenInfo->GetSiblingFiles());
×
1259

1260
    /* -------------------------------------------------------------------- */
1261
    /*      Confirm the requested access is supported.                      */
1262
    /* -------------------------------------------------------------------- */
1263
    if (poOpenInfo->eAccess == GA_Update)
×
1264
    {
1265
        delete poDS;
×
1266
        ReportUpdateNotSupportedByDriver("RIK");
×
1267
        return nullptr;
×
1268
    }
1269

1270
    return poDS;
×
1271
}
1272

1273
/************************************************************************/
1274
/*                          GDALRegister_RIK()                          */
1275
/************************************************************************/
1276

1277
void GDALRegister_RIK()
1,911✔
1278

1279
{
1280
    if (GDALGetDriverByName("RIK") != nullptr)
1,911✔
1281
        return;
282✔
1282

1283
    GDALDriver *poDriver = new GDALDriver();
1,629✔
1284

1285
    poDriver->SetDescription("RIK");
1,629✔
1286
    poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
1,629✔
1287
    poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Swedish Grid RIK (.rik)");
1,629✔
1288
    poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/rik.html");
1,629✔
1289
    poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "rik");
1,629✔
1290
    poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
1,629✔
1291

1292
    poDriver->pfnOpen = RIKDataset::Open;
1,629✔
1293
    poDriver->pfnIdentify = RIKDataset::Identify;
1,629✔
1294

1295
    GetGDALDriverManager()->RegisterDriver(poDriver);
1,629✔
1296
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc