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