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