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