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