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