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